c2rust_ast_exporter/
lib.rs1use serde_cbor::{from_slice, Value};
2use std::collections::HashMap;
3use std::ffi::{c_char, c_int, CStr, CString};
4use std::io::{Error, ErrorKind};
5use std::path::Path;
6use std::slice;
7
8use crate::clang_ast::BuiltinVaListKind;
9
10pub mod clang_ast;
11
12impl Default for BuiltinVaListKind {
13 fn default() -> Self {
14 Self::CharPtrBuiltinVaList
15 }
16}
17
18pub fn get_clang_major_version() -> Option<u32> {
19 let s = unsafe { CStr::from_ptr(clang_version()) };
20 s.to_str()
21 .unwrap()
22 .split('.')
23 .next()
24 .unwrap()
25 .parse::<u32>()
26 .ok()
27}
28
29pub fn get_untyped_ast(
30 file_path: &Path,
31 cc_db: &Path,
32 extra_args: &[&str],
33 debug: bool,
34) -> Result<clang_ast::AstContext, Error> {
35 let cbors = get_ast_cbors(file_path, cc_db, extra_args, debug);
36 let buffer = cbors
37 .values()
38 .next()
39 .ok_or_else(|| Error::new(ErrorKind::InvalidData, "Could not parse input file"))?;
40
41 let items: Value = from_slice(&buffer[..]).unwrap();
47
48 clang_ast::process(items).map_err(|e| Error::new(ErrorKind::InvalidData, format!("{}", e)))
49}
50
51fn get_ast_cbors(
52 file_path: &Path,
53 cc_db: &Path,
54 extra_args: &[&str],
55 debug: bool,
56) -> HashMap<String, Vec<u8>> {
57 let mut res = 0;
58
59 let mut args_owned = vec![CString::new("ast_exporter").unwrap()];
60 args_owned.push(CString::new(file_path.to_str().unwrap()).unwrap());
61 args_owned.push(CString::new("-p").unwrap());
62 args_owned.push(CString::new(cc_db.to_str().unwrap()).unwrap());
63
64 for &arg in extra_args {
65 args_owned.push(CString::new(["-extra-arg=", arg].join("")).unwrap())
66 }
67
68 let args_ptrs: Vec<*const c_char> = args_owned.iter().map(|x| x.as_ptr()).collect();
69
70 let hashmap;
71 unsafe {
72 let ptr = ast_exporter(
73 args_ptrs.len() as c_int,
74 args_ptrs.as_ptr(),
75 debug.into(),
76 &mut res,
77 );
78 hashmap = marshal_result(ptr);
79 drop_export_result(ptr);
80 }
81 hashmap
82}
83
84#[allow(non_camel_case_types)]
85#[allow(non_snake_case)]
86#[allow(dead_code)]
87mod ffi {
88 include!(concat!(env!("OUT_DIR"), "/cppbindings.rs"));
89}
90
91extern "C" {
92 fn ast_exporter(
94 argc: c_int,
95 argv: *const *const c_char,
96 debug: c_int,
97 res: *mut c_int,
98 ) -> *mut ffi::ExportResult;
99
100 fn drop_export_result(ptr: *mut ffi::ExportResult);
102
103 fn clang_version() -> *const c_char;
104}
105
106unsafe fn marshal_result(result: *const ffi::ExportResult) -> HashMap<String, Vec<u8>> {
107 let mut output = HashMap::new();
108
109 let n = (*result).entries as isize;
110 for i in 0..n {
111 let res = &*result;
112
113 let cname = CStr::from_ptr(*res.names.offset(i));
115 let name = cname.to_str().unwrap().to_owned();
116
117 let csize = *res.sizes.offset(i);
119 let cbytes = *res.bytes.offset(i);
120 #[allow(clippy::unnecessary_cast )]
121 let bytes = slice::from_raw_parts(cbytes, csize as usize);
122 let mut v = Vec::new();
123 v.extend_from_slice(bytes);
124
125 output.insert(name, v);
126 }
127 output
128}