1#![allow(non_upper_case_globals)]
8
9use crate::diagnostic::{Diagnostic, DiagnosticError, Severity};
10use anyhow::{Context, Result};
11use clang_sys::*;
12use std::ffi::{CStr, CString};
13use std::path::Path;
14use std::process::Command;
15use std::ptr;
16
17fn discover_system_includes() -> Vec<String> {
22 let mut includes = Vec::new();
23
24 let output = Command::new("clang")
26 .args(["-E", "-x", "c", "-", "-v"])
27 .stdin(std::process::Stdio::null())
28 .output();
29
30 if let Ok(output) = output {
31 let stderr = String::from_utf8_lossy(&output.stderr);
32 let mut in_include_section = false;
33
34 for line in stderr.lines() {
35 if line.contains("#include <...> search starts here:") {
36 in_include_section = true;
37 continue;
38 }
39 if line.contains("End of search list.") {
40 break;
41 }
42 if in_include_section {
43 let path = line.trim();
44 if !path.is_empty() && !path.contains("(framework directory)") {
46 includes.push(path.to_string());
47 }
48 }
49 }
50 }
51
52 if includes.is_empty() {
54 if cfg!(target_os = "macos") {
56 includes.extend([
57 "/usr/local/include".to_string(),
58 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include".to_string(),
59 ]);
60 }
61 if cfg!(target_os = "linux") {
63 includes.extend(["/usr/include".to_string(), "/usr/local/include".to_string()]);
64 }
65 }
66
67 includes
68}
69
70#[derive(Debug)]
83pub struct CParser {
84 index: CXIndex,
85 system_includes: Vec<String>,
87}
88
89impl CParser {
90 pub fn new() -> Result<Self> {
103 let index = unsafe { clang_createIndex(0, 0) };
105 if index.is_null() {
106 anyhow::bail!("Failed to create clang index");
107 }
108
109 let system_includes = discover_system_includes();
111
112 Ok(Self {
113 index,
114 system_includes,
115 })
116 }
117
118 pub fn parse(&self, source: &str) -> Result<Ast> {
139 let filename = CString::new("input.c").context("Failed to create filename")?;
140 let source_cstr = CString::new(source).context("Failed to convert source to CString")?;
141
142 let mut ast = Ast::new();
143
144 if source.trim().is_empty() {
146 return Ok(ast);
147 }
148
149 let unsaved_file = CXUnsavedFile {
151 Filename: filename.as_ptr(),
152 Contents: source_cstr.as_ptr(),
153 Length: source.len() as std::os::raw::c_ulong,
154 };
155
156 let has_extern_c = source.contains("extern \"C\"");
160 let has_ifdef_guard =
161 source.contains("#ifdef __cplusplus") || source.contains("#if defined(__cplusplus)");
162 let needs_cpp_mode = has_extern_c && !has_ifdef_guard;
163
164 let isystem_flag = CString::new("-isystem").unwrap();
167 let include_cstrings: Vec<CString> = self
168 .system_includes
169 .iter()
170 .map(|p| CString::new(p.as_str()).unwrap())
171 .collect();
172
173 let cpp_flag = CString::new("-x").unwrap();
175 let cpp_lang = CString::new("c++").unwrap();
176
177 let define_eof = CString::new("-DEOF=-1").unwrap();
180 let define_null = CString::new("-DNULL=0").unwrap();
181 let define_bufsiz = CString::new("-DBUFSIZ=8192").unwrap();
183
184 let mut args_vec: Vec<*const std::os::raw::c_char> = Vec::new();
186
187 if needs_cpp_mode {
189 args_vec.push(cpp_flag.as_ptr());
190 args_vec.push(cpp_lang.as_ptr());
191 }
192
193 args_vec.push(define_eof.as_ptr());
195 args_vec.push(define_null.as_ptr());
196 args_vec.push(define_bufsiz.as_ptr());
197
198 for include_path in &include_cstrings {
200 args_vec.push(isystem_flag.as_ptr());
201 args_vec.push(include_path.as_ptr());
202 }
203
204 let flags = 1;
208
209 let mut tu = ptr::null_mut();
210 let result = unsafe {
211 clang_parseTranslationUnit2(
212 self.index,
213 filename.as_ptr(),
214 if args_vec.is_empty() {
215 ptr::null()
216 } else {
217 args_vec.as_ptr()
218 },
219 args_vec.len() as std::os::raw::c_int,
220 &unsaved_file as *const CXUnsavedFile as *mut CXUnsavedFile,
221 1,
222 flags,
223 &mut tu,
224 )
225 };
226
227 if result != CXError_Success || tu.is_null() {
228 anyhow::bail!("Failed to parse C source");
229 }
230
231 let diagnostics = extract_diagnostics(tu, source, None);
233 if diagnostics.iter().any(|d| d.severity >= Severity::Error) {
234 unsafe { clang_disposeTranslationUnit(tu) };
235 return Err(DiagnosticError::new(diagnostics).into());
236 }
237
238 let cursor = unsafe { clang_getTranslationUnitCursor(tu) };
240
241 let ast_ptr = &mut ast as *mut Ast;
243
244 unsafe {
246 clang_visitChildren(cursor, visit_function, ast_ptr as CXClientData);
247
248 clang_disposeTranslationUnit(tu);
250 }
251
252 Ok(ast)
253 }
254
255 pub fn parse_file(&self, path: &Path) -> Result<Ast> {
271 let source = std::fs::read_to_string(path)
272 .with_context(|| format!("Failed to read file: {}", path.display()))?;
273
274 let abs_path = if path.is_absolute() {
276 path.to_path_buf()
277 } else {
278 std::env::current_dir()?.join(path)
279 };
280
281 let filename =
282 CString::new(abs_path.to_string_lossy().as_bytes()).context("Invalid path")?;
283 let source_cstr = CString::new(source.as_str()).context("Invalid source")?;
284
285 let mut ast = Ast::new();
286
287 if source.trim().is_empty() {
289 return Ok(ast);
290 }
291
292 let unsaved_file = CXUnsavedFile {
294 Filename: filename.as_ptr(),
295 Contents: source_cstr.as_ptr(),
296 Length: source.len() as std::os::raw::c_ulong,
297 };
298
299 let has_extern_c = source.contains("extern \"C\"");
301 let has_ifdef_guard =
302 source.contains("#ifdef __cplusplus") || source.contains("#if defined(__cplusplus)");
303 let needs_cpp_mode = has_extern_c && !has_ifdef_guard;
304
305 let cpp_flag = CString::new("-x").unwrap();
307 let cpp_lang = CString::new("c++").unwrap();
308
309 let define_eof = CString::new("-DEOF=-1").unwrap();
311 let define_null = CString::new("-DNULL=0").unwrap();
312 let define_bufsiz = CString::new("-DBUFSIZ=8192").unwrap();
313
314 let define_char_bit = CString::new("-DCHAR_BIT=8").unwrap();
316 let define_char_min = CString::new("-DCHAR_MIN=-128").unwrap();
317 let define_char_max = CString::new("-DCHAR_MAX=127").unwrap();
318 let define_schar_min = CString::new("-DSCHAR_MIN=-128").unwrap();
319 let define_schar_max = CString::new("-DSCHAR_MAX=127").unwrap();
320 let define_uchar_max = CString::new("-DUCHAR_MAX=255").unwrap();
321 let define_shrt_min = CString::new("-DSHRT_MIN=-32768").unwrap();
322 let define_shrt_max = CString::new("-DSHRT_MAX=32767").unwrap();
323 let define_ushrt_max = CString::new("-DUSHRT_MAX=65535").unwrap();
324 let define_int_min = CString::new("-DINT_MIN=-2147483648").unwrap();
325 let define_int_max = CString::new("-DINT_MAX=2147483647").unwrap();
326 let define_uint_max = CString::new("-DUINT_MAX=4294967295U").unwrap();
327 let define_long_min = CString::new("-DLONG_MIN=-9223372036854775808L").unwrap();
328 let define_long_max = CString::new("-DLONG_MAX=9223372036854775807L").unwrap();
329 let define_ulong_max = CString::new("-DULONG_MAX=18446744073709551615UL").unwrap();
330
331 let define_exit_success = CString::new("-DEXIT_SUCCESS=0").unwrap();
333 let define_exit_failure = CString::new("-DEXIT_FAILURE=1").unwrap();
334 let define_rand_max = CString::new("-DRAND_MAX=2147483647").unwrap();
335
336 let include_clang = CString::new("-I/usr/lib/llvm-14/lib/clang/14.0.0/include").unwrap();
338 let include_local = CString::new("-I/usr/local/include").unwrap();
339 let include_arch = CString::new("-I/usr/include/x86_64-linux-gnu").unwrap();
340 let include_usr = CString::new("-I/usr/include").unwrap();
341
342 let base_defines: Vec<*const std::os::raw::c_char> = vec![
344 define_eof.as_ptr(),
345 define_null.as_ptr(),
346 define_bufsiz.as_ptr(),
347 define_char_bit.as_ptr(),
348 define_char_min.as_ptr(),
349 define_char_max.as_ptr(),
350 define_schar_min.as_ptr(),
351 define_schar_max.as_ptr(),
352 define_uchar_max.as_ptr(),
353 define_shrt_min.as_ptr(),
354 define_shrt_max.as_ptr(),
355 define_ushrt_max.as_ptr(),
356 define_int_min.as_ptr(),
357 define_int_max.as_ptr(),
358 define_uint_max.as_ptr(),
359 define_long_min.as_ptr(),
360 define_long_max.as_ptr(),
361 define_ulong_max.as_ptr(),
362 define_exit_success.as_ptr(),
363 define_exit_failure.as_ptr(),
364 define_rand_max.as_ptr(),
365 include_clang.as_ptr(),
366 include_local.as_ptr(),
367 include_arch.as_ptr(),
368 include_usr.as_ptr(),
369 ];
370
371 let args_vec: Vec<*const std::os::raw::c_char> = if needs_cpp_mode {
372 let mut args = vec![cpp_flag.as_ptr(), cpp_lang.as_ptr()];
373 args.extend(base_defines);
374 args
375 } else {
376 base_defines
377 };
378
379 let flags = 1;
381
382 let mut tu = ptr::null_mut();
383 let result = unsafe {
384 clang_parseTranslationUnit2(
385 self.index,
386 filename.as_ptr(),
387 if args_vec.is_empty() {
388 ptr::null()
389 } else {
390 args_vec.as_ptr()
391 },
392 args_vec.len() as std::os::raw::c_int,
393 &unsaved_file as *const CXUnsavedFile as *mut CXUnsavedFile,
394 1,
395 flags,
396 &mut tu,
397 )
398 };
399
400 if result != CXError_Success || tu.is_null() {
401 anyhow::bail!("Failed to parse C source file: {}", path.display());
402 }
403
404 let file_name = path.to_string_lossy().to_string();
406 let diagnostics = extract_diagnostics(tu, &source, Some(&file_name));
407 if diagnostics.iter().any(|d| d.severity >= Severity::Error) {
408 unsafe { clang_disposeTranslationUnit(tu) };
409 return Err(DiagnosticError::new(diagnostics).into());
410 }
411
412 let cursor = unsafe { clang_getTranslationUnitCursor(tu) };
414 let ast_ptr = &mut ast as *mut Ast;
415
416 unsafe {
417 clang_visitChildren(cursor, visit_function, ast_ptr as CXClientData);
418 clang_disposeTranslationUnit(tu);
419 }
420
421 Ok(ast)
422 }
423}
424
425impl Drop for CParser {
426 fn drop(&mut self) {
427 unsafe {
429 clang_disposeIndex(self.index);
430 }
431 }
432}
433
434fn extract_diagnostics(
443 tu: CXTranslationUnit,
444 source: &str,
445 file_override: Option<&str>,
446) -> Vec<Diagnostic> {
447 let num_diagnostics = unsafe { clang_getNumDiagnostics(tu) };
448 let mut diagnostics = Vec::new();
449
450 for i in 0..num_diagnostics {
451 let diag = unsafe { clang_getDiagnostic(tu, i) };
452 let raw_severity = unsafe { clang_getDiagnosticSeverity(diag) };
453
454 let severity = match raw_severity {
455 CXDiagnostic_Note => Severity::Note,
456 CXDiagnostic_Warning => Severity::Warning,
457 CXDiagnostic_Error => Severity::Error,
458 CXDiagnostic_Fatal => Severity::Fatal,
459 _ => {
460 unsafe { clang_disposeDiagnostic(diag) };
461 continue; }
463 };
464
465 let diag_str = unsafe { clang_getDiagnosticSpelling(diag) };
467 let c_str = unsafe { CStr::from_ptr(clang_getCString(diag_str)) };
468 let message = c_str.to_str().unwrap_or("unknown error").to_string();
469 unsafe { clang_disposeString(diag_str) };
470
471 let mut d = Diagnostic::new(severity, message);
472
473 let loc = unsafe { clang_getDiagnosticLocation(diag) };
475 let mut file: CXFile = ptr::null_mut();
476 let mut line: u32 = 0;
477 let mut column: u32 = 0;
478 unsafe {
479 clang_getFileLocation(loc, &mut file, &mut line, &mut column, ptr::null_mut());
480 }
481
482 if line > 0 {
483 d.line = Some(line);
484 d.column = Some(column);
485 }
486
487 if let Some(name) = file_override {
489 d.file = Some(name.to_string());
490 } else if !file.is_null() {
491 let file_name = unsafe {
492 let name_cx = clang_getFileName(file);
493 let name_c = CStr::from_ptr(clang_getCString(name_cx));
494 let name = name_c.to_string_lossy().into_owned();
495 clang_disposeString(name_cx);
496 name
497 };
498 d.file = Some(file_name);
499 } else {
500 d.file = Some("input.c".to_string());
501 }
502
503 let cat_idx = unsafe { clang_getDiagnosticCategory(diag) };
505 if cat_idx != 0 {
506 let cat_str = unsafe { clang_getDiagnosticCategoryText(diag) };
507 let cat_c = unsafe { CStr::from_ptr(clang_getCString(cat_str)) };
508 let category = cat_c.to_str().unwrap_or("").to_string();
509 unsafe { clang_disposeString(cat_str) };
510 if !category.is_empty() {
511 d.category = Some(category);
512 }
513 }
514
515 let num_fix_its = unsafe { clang_getDiagnosticNumFixIts(diag) };
517 for fi in 0..num_fix_its {
518 let mut range = unsafe { std::mem::zeroed::<CXSourceRange>() };
519 let fix_str = unsafe { clang_getDiagnosticFixIt(diag, fi, &mut range) };
520 let fix_c = unsafe { CStr::from_ptr(clang_getCString(fix_str)) };
521 let fix_text = fix_c.to_str().unwrap_or("").to_string();
522 unsafe { clang_disposeString(fix_str) };
523 if !fix_text.is_empty() {
524 d.fix_its.push(format!("insert '{}'", fix_text));
525 }
526 }
527
528 if let Some(line_num) = d.line {
530 d.snippet = Diagnostic::build_snippet(source, line_num, d.column);
531 }
532
533 d.infer_note_and_help();
535
536 unsafe { clang_disposeDiagnostic(diag) };
537 diagnostics.push(d);
538 }
539
540 diagnostics
541}
542
543extern "C" fn visit_function(
549 cursor: CXCursor,
550 _parent: CXCursor,
551 client_data: CXClientData,
552) -> CXChildVisitResult {
553 let ast = unsafe { &mut *(client_data as *mut Ast) };
555
556 let kind = unsafe { clang_getCursorKind(cursor) };
558
559 if kind == 23 {
562 unsafe {
565 clang_visitChildren(cursor, visit_function, client_data);
566 }
567 return CXChildVisit_Continue;
568 }
569
570 if kind == CXCursor_FunctionDecl {
571 if let Some(function) = extract_function(cursor) {
573 ast.add_function(function);
574 }
575 } else if kind == CXCursor_TypedefDecl {
576 let (typedef_opt, struct_opt) = extract_typedef(cursor);
579 if let Some(typedef) = typedef_opt {
580 ast.add_typedef(typedef);
581 }
582 if let Some(struct_def) = struct_opt {
583 ast.add_struct(struct_def);
584 }
585 } else if kind == CXCursor_StructDecl {
586 if let Some(struct_def) = extract_struct(cursor) {
588 ast.add_struct(struct_def);
589 }
590 } else if kind == CXCursor_VarDecl {
591 let semantic_parent = unsafe { clang_getCursorSemanticParent(cursor) };
594 let parent_kind = unsafe { clang_getCursorKind(semantic_parent) };
595
596 let is_file_scope = parent_kind != CXCursor_FunctionDecl;
600
601 if is_file_scope {
602 if let Some(variable) = extract_variable(cursor) {
603 ast.add_variable(variable);
604 }
605 }
606 } else if kind == 5 {
608 if let Some(enum_def) = extract_enum(cursor) {
611 ast.add_enum(enum_def);
612 }
613 } else if kind == CXCursor_MacroDefinition {
614 let location = unsafe { clang_getCursorLocation(cursor) };
616 let mut file: CXFile = ptr::null_mut();
617 unsafe {
618 clang_getFileLocation(
619 location,
620 &mut file,
621 ptr::null_mut(),
622 ptr::null_mut(),
623 ptr::null_mut(),
624 );
625 }
626
627 if !file.is_null() {
629 let file_name = unsafe {
630 let name_cxstring = clang_getFileName(file);
631 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
632 let name = c_str.to_string_lossy().into_owned();
633 clang_disposeString(name_cxstring);
634 name
635 };
636
637 if file_name.ends_with("input.c") {
639 if let Some(macro_def) = extract_macro(cursor) {
640 ast.add_macro(macro_def);
641 }
642 }
643 }
644 }
645
646 CXChildVisit_Recurse
649}
650
651fn extract_function(cursor: CXCursor) -> Option<Function> {
653 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
655 let name = unsafe {
656 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
657 let name = c_str.to_string_lossy().into_owned();
658 clang_disposeString(name_cxstring);
659 name
660 };
661
662 let cx_type = unsafe { clang_getCursorType(cursor) };
664 let return_cx_type = unsafe { clang_getResultType(cx_type) };
665 let return_type = convert_type(return_cx_type)?;
666
667 let num_args = unsafe { clang_Cursor_getNumArguments(cursor) };
669 let mut parameters = Vec::new();
670
671 for i in 0..num_args {
672 let arg_cursor = unsafe { clang_Cursor_getArgument(cursor, i as u32) };
674
675 let param_name_cxstring = unsafe { clang_getCursorSpelling(arg_cursor) };
677 let param_name = unsafe {
678 let c_str = CStr::from_ptr(clang_getCString(param_name_cxstring));
679 let name = c_str.to_string_lossy().into_owned();
680 clang_disposeString(param_name_cxstring);
681 name
682 };
683
684 let param_cx_type = unsafe { clang_getCursorType(arg_cursor) };
686 if let Some(param_type) = convert_type(param_cx_type) {
687 let is_pointee_const = unsafe {
689 if param_cx_type.kind == clang_sys::CXType_Pointer {
690 let pointee = clang_sys::clang_getPointeeType(param_cx_type);
691 clang_isConstQualifiedType(pointee) != 0
692 } else {
693 false
694 }
695 };
696 parameters.push(Parameter::new_with_const(
697 param_name,
698 param_type,
699 is_pointee_const,
700 ));
701 }
702 }
703
704 let mut body = Vec::new();
706 let body_ptr = &mut body as *mut Vec<Statement>;
707
708 unsafe {
709 clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
710 }
711
712 Some(Function::new_with_body(name, return_type, parameters, body))
713}
714
715fn extract_typedef(cursor: CXCursor) -> (Option<Typedef>, Option<Struct>) {
718 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
720 let name = unsafe {
721 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
722 let name = c_str.to_string_lossy().into_owned();
723 clang_disposeString(name_cxstring);
724 name
725 };
726
727 let cx_type = unsafe { clang_getTypedefDeclUnderlyingType(cursor) };
729
730 let canonical = unsafe { clang_getCanonicalType(cx_type) };
733 if canonical.kind == CXType_Record {
734 let decl = unsafe { clang_getTypeDeclaration(canonical) };
735 let struct_name_cxstring = unsafe { clang_getCursorSpelling(decl) };
736 let struct_name = unsafe {
737 let c_str = CStr::from_ptr(clang_getCString(struct_name_cxstring));
738 let sn = c_str.to_string_lossy().into_owned();
739 clang_disposeString(struct_name_cxstring);
740 sn
741 };
742
743 if struct_name.is_empty() {
745 let mut fields = Vec::new();
747 let fields_ptr = &mut fields as *mut Vec<StructField>;
748
749 unsafe {
750 clang_visitChildren(decl, visit_struct_fields, fields_ptr as CXClientData);
751 }
752
753 return (None, Some(Struct::new(name, fields)));
755 }
756 }
757
758 let underlying_type = convert_type(cx_type);
759 match underlying_type {
760 Some(ut) => (Some(Typedef::new(name, ut)), None),
761 None => (None, None),
762 }
763}
764
765fn extract_struct(cursor: CXCursor) -> Option<Struct> {
767 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
769 let name = unsafe {
770 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
771 let name = c_str.to_string_lossy().into_owned();
772 clang_disposeString(name_cxstring);
773 name
774 };
775
776 if name.is_empty() {
778 return None;
779 }
780
781 let mut fields = Vec::new();
783 let fields_ptr = &mut fields as *mut Vec<StructField>;
784
785 unsafe {
786 clang_visitChildren(cursor, visit_struct_fields, fields_ptr as CXClientData);
787 }
788
789 Some(Struct::new(name, fields))
790}
791
792fn extract_enum(cursor: CXCursor) -> Option<Enum> {
796 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
798 let name = unsafe {
799 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
800 let name = c_str.to_string_lossy().into_owned();
801 clang_disposeString(name_cxstring);
802 name
803 };
804
805 let mut variants: Vec<EnumVariant> = Vec::new();
807 let variants_ptr = &mut variants as *mut Vec<EnumVariant>;
808
809 extern "C" fn visit_enum_constants(
811 cursor: CXCursor,
812 _parent: CXCursor,
813 client_data: CXClientData,
814 ) -> CXChildVisitResult {
815 let variants = unsafe { &mut *(client_data as *mut Vec<EnumVariant>) };
816
817 let kind = unsafe { clang_getCursorKind(cursor) };
819
820 if kind == 7 {
822 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
824 let variant_name = unsafe {
825 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
826 let name = c_str.to_string_lossy().into_owned();
827 clang_disposeString(name_cxstring);
828 name
829 };
830
831 let value = unsafe { clang_getEnumConstantDeclValue(cursor) };
833
834 variants.push(EnumVariant::new(variant_name, Some(value)));
835 }
836
837 CXChildVisit_Continue
838 }
839
840 unsafe {
841 clang_visitChildren(cursor, visit_enum_constants, variants_ptr as CXClientData);
842 }
843
844 if variants.is_empty() {
846 return None;
847 }
848
849 Some(Enum::new(name, variants))
850}
851
852fn extract_variable(cursor: CXCursor) -> Option<Variable> {
863 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
865 let name = unsafe {
866 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
867 let name = c_str.to_string_lossy().into_owned();
868 clang_disposeString(name_cxstring);
869 name
870 };
871
872 let cx_type = unsafe { clang_getCursorType(cursor) };
874 let var_type = convert_type(cx_type)?;
875
876 let storage_class = unsafe { clang_Cursor_getStorageClass(cursor) };
882 let is_static = storage_class == 3; let is_extern = storage_class == 2; let is_const = unsafe { clang_isConstQualifiedType(cx_type) != 0 };
887
888 let mut initializer: Option<Expression> = None;
890 let initializer_ptr = &mut initializer as *mut Option<Expression>;
891
892 unsafe {
893 clang_visitChildren(
894 cursor,
895 visit_variable_initializer,
896 initializer_ptr as CXClientData,
897 );
898 }
899
900 Some(Variable::new_with_storage_class(
901 name,
902 var_type,
903 initializer,
904 is_static,
905 is_extern,
906 is_const,
907 ))
908}
909
910#[allow(non_upper_case_globals)]
913fn try_extract_expression(cursor: CXCursor) -> Option<Expression> {
914 let kind = unsafe { clang_getCursorKind(cursor) };
915
916 match kind {
917 CXCursor_IntegerLiteral => extract_int_literal(cursor),
918 107 => extract_float_literal(cursor), CXCursor_StringLiteral => extract_string_literal(cursor),
920 110 => extract_char_literal(cursor), CXCursor_DeclRefExpr => extract_variable_ref(cursor),
922 CXCursor_BinaryOperator => extract_binary_op(cursor),
923 CXCursor_CallExpr => extract_function_call(cursor),
924 CXCursor_UnaryOperator => extract_unary_op(cursor),
925 CXCursor_ArraySubscriptExpr => extract_array_index(cursor),
926 CXCursor_MemberRefExpr => extract_field_access(cursor),
927 116 => extract_conditional_op(cursor), 117 => extract_cast(cursor), 118 => extract_compound_literal(cursor), 111 => {
931 let mut result: Option<Expression> = None;
934 let result_ptr = &mut result as *mut Option<Expression>;
935 unsafe {
936 clang_visitChildren(
937 cursor,
938 visit_variable_initializer,
939 result_ptr as CXClientData,
940 );
941 }
942 result
943 }
944 CXCursor_UnexposedExpr => {
945 let mut result: Option<Expression> = None;
947 let result_ptr = &mut result as *mut Option<Expression>;
948 unsafe {
949 clang_visitChildren(
950 cursor,
951 visit_variable_initializer,
952 result_ptr as CXClientData,
953 );
954 }
955 result
956 }
957 _ => None,
958 }
959}
960
961#[allow(non_upper_case_globals)]
963extern "C" fn visit_variable_initializer(
964 cursor: CXCursor,
965 _parent: CXCursor,
966 client_data: CXClientData,
967) -> CXChildVisitResult {
968 let initializer = unsafe { &mut *(client_data as *mut Option<Expression>) };
969
970 if let Some(expr) = try_extract_expression(cursor) {
972 *initializer = Some(expr);
973 return CXChildVisit_Break;
974 }
975
976 CXChildVisit_Continue
977}
978
979fn extract_macro(cursor: CXCursor) -> Option<MacroDefinition> {
986 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
988 let name = unsafe {
989 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
990 let name = c_str.to_string_lossy().into_owned();
991 clang_disposeString(name_cxstring);
992 name
993 };
994
995 if name.is_empty() {
997 return None;
998 }
999
1000 let is_function_like = unsafe { clang_sys::clang_Cursor_isMacroFunctionLike(cursor) } != 0;
1003
1004 let range = unsafe { clang_getCursorExtent(cursor) };
1006 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1007
1008 let mut tokens: *mut CXToken = ptr::null_mut();
1009 let mut num_tokens: u32 = 0;
1010
1011 unsafe {
1012 clang_tokenize(tu, range, &mut tokens, &mut num_tokens);
1013 }
1014
1015 let mut parameters = Vec::new();
1018 let mut body_tokens = Vec::new();
1019 let mut in_params = false;
1020
1021 for i in 0..num_tokens {
1022 let token = unsafe { *tokens.offset(i as isize) };
1023 let token_kind = unsafe { clang_getTokenKind(token) };
1024 let token_spelling = unsafe { clang_getTokenSpelling(tu, token) };
1025 let token_str = unsafe {
1026 let c_str = CStr::from_ptr(clang_getCString(token_spelling));
1027 let s = c_str.to_string_lossy().into_owned();
1028 clang_disposeString(token_spelling);
1029 s
1030 };
1031
1032 if i == 0 {
1034 continue;
1035 }
1036
1037 if is_function_like && i == 1 && token_str == "(" {
1039 in_params = true;
1040 continue;
1041 }
1042
1043 if in_params {
1044 if token_str == ")" {
1045 in_params = false;
1046 continue;
1047 } else if token_str != ","
1048 && (token_kind == CXToken_Identifier || token_kind == CXToken_Keyword)
1049 {
1050 parameters.push(token_str);
1053 }
1054 } else {
1055 body_tokens.push(token_str);
1056 }
1057 }
1058
1059 unsafe {
1061 clang_disposeTokens(tu, tokens, num_tokens);
1062 }
1063
1064 let body = body_tokens.join("");
1066
1067 if is_function_like {
1068 Some(MacroDefinition::new_function_like(name, parameters, body))
1069 } else {
1070 Some(MacroDefinition::new_object_like(name, body))
1071 }
1072}
1073
1074#[allow(non_upper_case_globals)]
1080extern "C" fn visit_struct_fields(
1081 cursor: CXCursor,
1082 _parent: CXCursor,
1083 client_data: CXClientData,
1084) -> CXChildVisitResult {
1085 let fields = unsafe { &mut *(client_data as *mut Vec<StructField>) };
1087
1088 let kind = unsafe { clang_getCursorKind(cursor) };
1090
1091 if kind == CXCursor_FieldDecl {
1092 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
1094 let name = unsafe {
1095 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
1096 let name = c_str.to_string_lossy().into_owned();
1097 clang_disposeString(name_cxstring);
1098 name
1099 };
1100
1101 let cx_type = unsafe { clang_getCursorType(cursor) };
1103 if let Some(field_type) = convert_type(cx_type) {
1104 fields.push(StructField::new(name, field_type));
1105 }
1106 }
1107
1108 CXChildVisit_Continue
1109}
1110
1111#[allow(non_upper_case_globals)]
1117extern "C" fn visit_statement(
1118 cursor: CXCursor,
1119 _parent: CXCursor,
1120 client_data: CXClientData,
1121) -> CXChildVisitResult {
1122 let statements = unsafe { &mut *(client_data as *mut Vec<Statement>) };
1124
1125 let kind = unsafe { clang_getCursorKind(cursor) };
1127
1128 match kind {
1129 CXCursor_CompoundStmt => {
1130 CXChildVisit_Recurse
1132 }
1133 CXCursor_DeclStmt => {
1134 CXChildVisit_Recurse
1136 }
1137 CXCursor_VarDecl => {
1138 if let Some(stmt) = extract_var_decl(cursor) {
1140 statements.push(stmt);
1141 }
1142 CXChildVisit_Continue
1143 }
1144 CXCursor_ReturnStmt => {
1145 if let Some(stmt) = extract_return_stmt(cursor) {
1147 statements.push(stmt);
1148 }
1149 CXChildVisit_Continue
1150 }
1151 CXCursor_BinaryOperator => {
1152 if let Some(stmt) = extract_assignment_stmt(cursor) {
1154 statements.push(stmt);
1155 }
1156 CXChildVisit_Continue
1157 }
1158 CXCursor_IfStmt => {
1159 if let Some(stmt) = extract_if_stmt(cursor) {
1161 statements.push(stmt);
1162 }
1163 CXChildVisit_Continue
1164 }
1165 CXCursor_ForStmt => {
1166 if let Some(stmt) = extract_for_stmt(cursor) {
1168 statements.push(stmt);
1169 }
1170 CXChildVisit_Continue
1171 }
1172 CXCursor_WhileStmt => {
1173 if let Some(stmt) = extract_while_stmt(cursor) {
1175 statements.push(stmt);
1176 }
1177 CXChildVisit_Continue
1178 }
1179 CXCursor_SwitchStmt => {
1180 if let Some(stmt) = extract_switch_stmt(cursor) {
1182 statements.push(stmt);
1183 }
1184 CXChildVisit_Continue
1185 }
1186 CXCursor_BreakStmt => {
1187 statements.push(Statement::Break);
1189 CXChildVisit_Continue
1190 }
1191 CXCursor_ContinueStmt => {
1192 statements.push(Statement::Continue);
1194 CXChildVisit_Continue
1195 }
1196 CXCursor_UnaryOperator => {
1197 if let Some(stmt) = extract_inc_dec_stmt(cursor) {
1199 statements.push(stmt);
1200 }
1201 CXChildVisit_Continue
1202 }
1203 CXCursor_CompoundAssignOperator => {
1204 if let Some(stmt) = extract_compound_assignment_stmt(cursor) {
1206 statements.push(stmt);
1207 }
1208 CXChildVisit_Continue
1209 }
1210 CXCursor_CallExpr => {
1211 if let Some(stmt) = extract_statement(cursor) {
1214 statements.push(stmt);
1215 }
1216 CXChildVisit_Continue
1217 }
1218 _ => CXChildVisit_Recurse, }
1220}
1221
1222fn extract_var_decl(cursor: CXCursor) -> Option<Statement> {
1224 let storage_class = unsafe { clang_Cursor_getStorageClass(cursor) };
1228 let is_extern = storage_class == 2;
1229
1230 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
1232 let name = unsafe {
1233 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
1234 let name = c_str.to_string_lossy().into_owned();
1235 clang_disposeString(name_cxstring);
1236 name
1237 };
1238
1239 let cx_type = unsafe { clang_getCursorType(cursor) };
1241 let var_type = convert_type(cx_type)?;
1242
1243 if is_extern {
1246 let mut has_real_initializer = false;
1248 extern "C" fn check_initializer(
1249 cursor: CXCursor,
1250 _parent: CXCursor,
1251 client_data: CXClientData,
1252 ) -> CXChildVisitResult {
1253 let has_init = unsafe { &mut *(client_data as *mut bool) };
1254 let kind = unsafe { clang_getCursorKind(cursor) };
1255 if kind == CXCursor_IntegerLiteral
1257 || kind == 107 || kind == CXCursor_StringLiteral
1259 || kind == CXCursor_CallExpr
1260 || kind == CXCursor_BinaryOperator
1261 || kind == CXCursor_UnaryOperator
1262 {
1263 *has_init = true;
1264 return CXChildVisit_Break;
1265 }
1266 CXChildVisit_Continue
1267 }
1268 let init_ptr = &mut has_real_initializer as *mut bool;
1269 unsafe {
1270 clang_visitChildren(cursor, check_initializer, init_ptr as CXClientData);
1271 }
1272 if !has_real_initializer {
1274 return None;
1275 }
1276 }
1277
1278 let mut initializer: Option<Expression> = None;
1280 let init_ptr = &mut initializer as *mut Option<Expression>;
1281
1282 unsafe {
1283 clang_visitChildren(cursor, visit_expression, init_ptr as CXClientData);
1284 }
1285
1286 let initializer = match (&var_type, &initializer) {
1293 (
1294 Type::Array {
1295 size: Some(array_size),
1296 ..
1297 },
1298 Some(Expression::IntLiteral(init_val)),
1299 ) if i64::from(*init_val) == *array_size => {
1300 None
1302 }
1303 _ => initializer,
1304 };
1305
1306 Some(Statement::VariableDeclaration {
1307 name,
1308 var_type,
1309 initializer,
1310 })
1311}
1312
1313fn extract_return_stmt(cursor: CXCursor) -> Option<Statement> {
1315 let mut return_expr: Option<Expression> = None;
1317 let expr_ptr = &mut return_expr as *mut Option<Expression>;
1318
1319 unsafe {
1320 clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1321 }
1322
1323 Some(Statement::Return(return_expr))
1324}
1325
1326fn extract_assignment_stmt(cursor: CXCursor) -> Option<Statement> {
1328 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1331 if tu.is_null() {
1332 return None;
1333 }
1334
1335 let extent = unsafe { clang_getCursorExtent(cursor) };
1337
1338 let mut tokens = ptr::null_mut();
1340 let mut num_tokens = 0;
1341
1342 unsafe {
1343 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1344 }
1345
1346 let mut is_assignment = false;
1347
1348 for i in 0..num_tokens {
1350 unsafe {
1351 let token = *tokens.add(i as usize);
1352 let token_kind = clang_getTokenKind(token);
1353
1354 if token_kind == CXToken_Punctuation {
1355 let token_cxstring = clang_getTokenSpelling(tu, token);
1356 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1357 if let Ok(token_str) = c_str.to_str() {
1358 if token_str == "=" {
1360 is_assignment = true;
1361 clang_disposeString(token_cxstring);
1362 break;
1363 } else if token_str == "=="
1364 || token_str == "!="
1365 || token_str == "<="
1366 || token_str == ">="
1367 {
1368 clang_disposeString(token_cxstring);
1370 break;
1371 }
1372 }
1373 clang_disposeString(token_cxstring);
1374 }
1375 }
1376 }
1377
1378 unsafe {
1379 clang_disposeTokens(tu, tokens, num_tokens);
1380 }
1381
1382 if !is_assignment {
1383 return None;
1384 }
1385
1386 let mut operands: Vec<Expression> = Vec::new();
1388 let operands_ptr = &mut operands as *mut Vec<Expression>;
1389
1390 unsafe {
1391 clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
1392 }
1393
1394 if operands.len() != 2 {
1396 return None;
1397 }
1398
1399 if let Expression::Dereference(inner) = &operands[0] {
1401 return Some(Statement::DerefAssignment {
1402 target: (**inner).clone(), value: operands[1].clone(),
1404 });
1405 }
1406
1407 if let Expression::ArrayIndex { array, index } = &operands[0] {
1409 return Some(Statement::ArrayIndexAssignment {
1410 array: array.clone(),
1411 index: index.clone(),
1412 value: operands[1].clone(),
1413 });
1414 }
1415
1416 if matches!(
1418 &operands[0],
1419 Expression::PointerFieldAccess { .. } | Expression::FieldAccess { .. }
1420 ) {
1421 let field = match &operands[0] {
1423 Expression::PointerFieldAccess { field, .. } => field.clone(),
1424 Expression::FieldAccess { field, .. } => field.clone(),
1425 _ => unreachable!(),
1426 };
1427
1428 let object = match &operands[0] {
1430 Expression::PointerFieldAccess { pointer, .. } => (**pointer).clone(),
1431 Expression::FieldAccess { object, .. } => (**object).clone(),
1432 _ => unreachable!(),
1433 };
1434
1435 return Some(Statement::FieldAssignment {
1436 object,
1437 field,
1438 value: operands[1].clone(),
1439 });
1440 }
1441
1442 let target = match &operands[0] {
1444 Expression::Variable(name) => name.clone(),
1445 _ => return None, };
1447
1448 Some(Statement::Assignment {
1449 target,
1450 value: operands[1].clone(),
1451 })
1452}
1453
1454fn extract_inc_dec_stmt(cursor: CXCursor) -> Option<Statement> {
1456 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1458 if tu.is_null() {
1459 return None;
1460 }
1461
1462 let extent = unsafe { clang_getCursorExtent(cursor) };
1464
1465 let mut tokens = ptr::null_mut();
1467 let mut num_tokens = 0;
1468
1469 unsafe {
1470 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1471 }
1472
1473 let mut operator: Option<String> = None;
1474 let mut operator_position = 0;
1475
1476 for i in 0..num_tokens {
1478 unsafe {
1479 let token = *tokens.add(i as usize);
1480 let token_kind = clang_getTokenKind(token);
1481
1482 if token_kind == CXToken_Punctuation {
1483 let token_cxstring = clang_getTokenSpelling(tu, token);
1484 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1485 if let Ok(token_str) = c_str.to_str() {
1486 if token_str == "++" || token_str == "--" {
1487 operator = Some(token_str.to_string()); operator_position = i;
1489 clang_disposeString(token_cxstring);
1490 break;
1491 }
1492 }
1493 clang_disposeString(token_cxstring);
1494 }
1495 }
1496 }
1497
1498 let is_pre = operator_position == 0;
1502
1503 unsafe {
1504 clang_disposeTokens(tu, tokens, num_tokens);
1505 }
1506
1507 let mut member_expr: Option<Expression> = None;
1510 let mut simple_var: Option<String> = None;
1511
1512 extern "C" fn visit_for_inc_target(
1514 cursor: CXCursor,
1515 _parent: CXCursor,
1516 client_data: CXClientData,
1517 ) -> CXChildVisitResult {
1518 let data = unsafe { &mut *(client_data as *mut (Option<Expression>, Option<String>)) };
1519 let kind = unsafe { clang_getCursorKind(cursor) };
1520
1521 if kind == CXCursor_ArraySubscriptExpr {
1524 if let Some(expr) = extract_array_index(cursor) {
1525 data.0 = Some(expr);
1526 return CXChildVisit_Break;
1527 }
1528 }
1529
1530 if kind == CXCursor_MemberRefExpr {
1532 if let Some(expr) = extract_field_access(cursor) {
1533 data.0 = Some(expr);
1534 return CXChildVisit_Break;
1535 }
1536 }
1537
1538 if kind == CXCursor_DeclRefExpr {
1540 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
1541 let name = unsafe {
1542 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
1543 let var_name = c_str.to_string_lossy().into_owned();
1544 clang_disposeString(name_cxstring);
1545 var_name
1546 };
1547 data.1 = Some(name);
1548 CXChildVisit_Break
1549 } else {
1550 CXChildVisit_Recurse
1551 }
1552 }
1553
1554 let mut target_data = (member_expr, simple_var);
1555 let target_ptr = &mut target_data as *mut (Option<Expression>, Option<String>);
1556 unsafe {
1557 clang_visitChildren(cursor, visit_for_inc_target, target_ptr as CXClientData);
1558 }
1559 member_expr = target_data.0;
1560 simple_var = target_data.1;
1561
1562 let operator = operator?;
1563 let op_str = operator.as_str();
1564
1565 if let Some(expr) = member_expr {
1568 let delta = match op_str {
1570 "++" => 1,
1571 "--" => -1,
1572 _ => return None,
1573 };
1574
1575 match expr {
1577 Expression::PointerFieldAccess { pointer, field } => {
1578 let value = if delta > 0 {
1580 Expression::BinaryOp {
1581 left: Box::new(Expression::PointerFieldAccess {
1582 pointer: pointer.clone(),
1583 field: field.clone(),
1584 }),
1585 op: BinaryOperator::Add,
1586 right: Box::new(Expression::IntLiteral(1)),
1587 }
1588 } else {
1589 Expression::BinaryOp {
1590 left: Box::new(Expression::PointerFieldAccess {
1591 pointer: pointer.clone(),
1592 field: field.clone(),
1593 }),
1594 op: BinaryOperator::Subtract,
1595 right: Box::new(Expression::IntLiteral(1)),
1596 }
1597 };
1598
1599 return Some(Statement::FieldAssignment {
1600 object: *pointer,
1601 field,
1602 value,
1603 });
1604 }
1605 Expression::FieldAccess { object, field } => {
1606 let value = if delta > 0 {
1608 Expression::BinaryOp {
1609 left: Box::new(Expression::FieldAccess {
1610 object: object.clone(),
1611 field: field.clone(),
1612 }),
1613 op: BinaryOperator::Add,
1614 right: Box::new(Expression::IntLiteral(1)),
1615 }
1616 } else {
1617 Expression::BinaryOp {
1618 left: Box::new(Expression::FieldAccess {
1619 object: object.clone(),
1620 field: field.clone(),
1621 }),
1622 op: BinaryOperator::Subtract,
1623 right: Box::new(Expression::IntLiteral(1)),
1624 }
1625 };
1626
1627 return Some(Statement::FieldAssignment {
1628 object: *object,
1629 field,
1630 value,
1631 });
1632 }
1633 Expression::ArrayIndex { array, index } => {
1635 let value = if delta > 0 {
1637 Expression::BinaryOp {
1638 left: Box::new(Expression::ArrayIndex {
1639 array: array.clone(),
1640 index: index.clone(),
1641 }),
1642 op: BinaryOperator::Add,
1643 right: Box::new(Expression::IntLiteral(1)),
1644 }
1645 } else {
1646 Expression::BinaryOp {
1647 left: Box::new(Expression::ArrayIndex {
1648 array: array.clone(),
1649 index: index.clone(),
1650 }),
1651 op: BinaryOperator::Subtract,
1652 right: Box::new(Expression::IntLiteral(1)),
1653 }
1654 };
1655
1656 return Some(Statement::ArrayIndexAssignment {
1657 array,
1658 index,
1659 value,
1660 });
1661 }
1662 _ => {} }
1664 }
1665
1666 let target = simple_var?;
1668
1669 match op_str {
1670 "++" => {
1671 if is_pre {
1672 Some(Statement::PreIncrement { target })
1673 } else {
1674 Some(Statement::PostIncrement { target })
1675 }
1676 }
1677 "--" => {
1678 if is_pre {
1679 Some(Statement::PreDecrement { target })
1680 } else {
1681 Some(Statement::PostDecrement { target })
1682 }
1683 }
1684 _ => None,
1685 }
1686}
1687
1688fn extract_compound_assignment_stmt(cursor: CXCursor) -> Option<Statement> {
1690 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1692 if tu.is_null() {
1693 return None;
1694 }
1695
1696 let extent = unsafe { clang_getCursorExtent(cursor) };
1698
1699 let mut tokens = ptr::null_mut();
1701 let mut num_tokens = 0;
1702
1703 unsafe {
1704 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1705 }
1706
1707 let mut operator: Option<BinaryOperator> = None;
1708
1709 for i in 0..num_tokens {
1711 unsafe {
1712 let token = *tokens.add(i as usize);
1713 let token_kind = clang_getTokenKind(token);
1714
1715 if token_kind == CXToken_Punctuation {
1716 let token_cxstring = clang_getTokenSpelling(tu, token);
1717 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1718 if let Ok(token_str) = c_str.to_str() {
1719 operator = match token_str {
1720 "+=" => Some(BinaryOperator::Add),
1721 "-=" => Some(BinaryOperator::Subtract),
1722 "*=" => Some(BinaryOperator::Multiply),
1723 "/=" => Some(BinaryOperator::Divide),
1724 "%=" => Some(BinaryOperator::Modulo),
1725 _ => None,
1726 };
1727 if operator.is_some() {
1728 clang_disposeString(token_cxstring);
1729 break;
1730 }
1731 }
1732 clang_disposeString(token_cxstring);
1733 }
1734 }
1735 }
1736
1737 unsafe {
1738 clang_disposeTokens(tu, tokens, num_tokens);
1739 }
1740
1741 let op = operator?;
1742
1743 let mut operands: Vec<Expression> = Vec::new();
1745 let operands_ptr = &mut operands as *mut Vec<Expression>;
1746
1747 unsafe {
1748 clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
1749 }
1750
1751 if operands.len() != 2 {
1753 return None;
1754 }
1755
1756 if let Expression::Dereference(inner) = &operands[0] {
1761 return Some(Statement::DerefCompoundAssignment {
1762 target: (**inner).clone(), op,
1764 value: operands[1].clone(),
1765 });
1766 }
1767
1768 if let Expression::PointerFieldAccess { .. } = &operands[0] {
1770 return Some(Statement::DerefCompoundAssignment {
1771 target: operands[0].clone(), op,
1773 value: operands[1].clone(),
1774 });
1775 }
1776
1777 if let Expression::FieldAccess { .. } = &operands[0] {
1779 return Some(Statement::DerefCompoundAssignment {
1780 target: operands[0].clone(), op,
1782 value: operands[1].clone(),
1783 });
1784 }
1785
1786 if let Expression::ArrayIndex { .. } = &operands[0] {
1788 return Some(Statement::DerefCompoundAssignment {
1789 target: operands[0].clone(), op,
1791 value: operands[1].clone(),
1792 });
1793 }
1794
1795 let target = match &operands[0] {
1797 Expression::Variable(name) => name.clone(),
1798 _ => return None, };
1800
1801 Some(Statement::CompoundAssignment {
1802 target,
1803 op,
1804 value: operands[1].clone(),
1805 })
1806}
1807
1808fn extract_if_stmt(cursor: CXCursor) -> Option<Statement> {
1810 #[repr(C)]
1816 struct IfData {
1817 condition: Option<Expression>,
1818 then_block: Vec<Statement>,
1819 else_block: Option<Vec<Statement>>,
1820 child_index: u32,
1821 }
1822
1823 let mut if_data = IfData {
1824 condition: None,
1825 then_block: Vec::new(),
1826 else_block: None,
1827 child_index: 0,
1828 };
1829
1830 let data_ptr = &mut if_data as *mut IfData;
1831
1832 unsafe {
1833 clang_visitChildren(cursor, visit_if_children, data_ptr as CXClientData);
1834 }
1835
1836 Some(Statement::If {
1837 condition: if_data.condition?,
1838 then_block: if_data.then_block,
1839 else_block: if_data.else_block,
1840 })
1841}
1842
1843#[allow(non_upper_case_globals)]
1845extern "C" fn visit_if_children(
1846 cursor: CXCursor,
1847 _parent: CXCursor,
1848 client_data: CXClientData,
1849) -> CXChildVisitResult {
1850 #[repr(C)]
1851 struct IfData {
1852 condition: Option<Expression>,
1853 then_block: Vec<Statement>,
1854 else_block: Option<Vec<Statement>>,
1855 child_index: u32,
1856 }
1857
1858 let if_data = unsafe { &mut *(client_data as *mut IfData) };
1859 let kind = unsafe { clang_getCursorKind(cursor) };
1860
1861 match if_data.child_index {
1862 0 => {
1863 if_data.condition = match kind {
1866 CXCursor_BinaryOperator => extract_binary_op(cursor),
1867 CXCursor_IntegerLiteral => extract_int_literal(cursor),
1868 107 => extract_float_literal(cursor), 110 => extract_char_literal(cursor), CXCursor_DeclRefExpr => extract_variable_ref(cursor),
1871 CXCursor_CallExpr => extract_function_call(cursor),
1872 CXCursor_UnaryOperator => extract_unary_op(cursor),
1873 _ => {
1874 let mut cond_expr: Option<Expression> = None;
1876 let expr_ptr = &mut cond_expr as *mut Option<Expression>;
1877 unsafe {
1878 clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1879 }
1880 cond_expr
1881 }
1882 };
1883 if_data.child_index += 1;
1884 CXChildVisit_Continue
1885 }
1886 1 => {
1887 if kind == CXCursor_CompoundStmt {
1890 let body_ptr = &mut if_data.then_block as *mut Vec<Statement>;
1891 unsafe {
1892 clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1893 }
1894 } else {
1895 if let Some(stmt) = extract_single_statement(cursor) {
1897 if_data.then_block.push(stmt);
1898 }
1899 }
1900 if_data.child_index += 1;
1901 CXChildVisit_Continue
1902 }
1903 2 => {
1904 if kind == CXCursor_CompoundStmt {
1907 let mut else_stmts = Vec::new();
1908 let body_ptr = &mut else_stmts as *mut Vec<Statement>;
1909 unsafe {
1910 clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1911 }
1912 if_data.else_block = Some(else_stmts);
1913 } else if kind == CXCursor_IfStmt {
1914 let mut else_stmts = Vec::new();
1916 let body_ptr = &mut else_stmts as *mut Vec<Statement>;
1917 unsafe {
1918 clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1919 }
1920 if_data.else_block = Some(else_stmts);
1921 } else {
1922 if let Some(stmt) = extract_single_statement(cursor) {
1924 if_data.else_block = Some(vec![stmt]);
1925 }
1926 }
1927 if_data.child_index += 1;
1928 CXChildVisit_Continue
1929 }
1930 _ => CXChildVisit_Continue,
1931 }
1932}
1933
1934fn extract_for_stmt(cursor: CXCursor) -> Option<Statement> {
1936 #[repr(C)]
1943 struct ForChildInfo {
1944 cursor: CXCursor,
1945 kind: i32,
1946 }
1947
1948 #[repr(C)]
1949 struct ForCollector {
1950 children: Vec<ForChildInfo>,
1951 }
1952
1953 extern "C" fn collect_for_children(
1955 cursor: CXCursor,
1956 _parent: CXCursor,
1957 client_data: CXClientData,
1958 ) -> CXChildVisitResult {
1959 let collector = unsafe { &mut *(client_data as *mut ForCollector) };
1960 let kind = unsafe { clang_getCursorKind(cursor) };
1961 collector.children.push(ForChildInfo { cursor, kind });
1962 CXChildVisit_Continue
1963 }
1964
1965 let mut collector = ForCollector {
1966 children: Vec::new(),
1967 };
1968
1969 unsafe {
1970 clang_visitChildren(
1971 cursor,
1972 collect_for_children,
1973 &mut collector as *mut _ as CXClientData,
1974 );
1975 }
1976
1977 let mut init: Vec<Statement> = Vec::new();
1980 let mut condition: Option<Expression> = None;
1981 let mut increment: Vec<Statement> = Vec::new();
1982 let mut body: Vec<Statement> = Vec::new();
1983
1984 let num_children = collector.children.len();
1985
1986 fn is_assignment_op(cursor: CXCursor) -> bool {
1992 if let Some(op) = extract_binary_operator(cursor) {
1993 matches!(op, BinaryOperator::Assign)
1994 } else {
1995 false
1996 }
1997 }
1998
1999 fn is_condition_op(cursor: CXCursor) -> bool {
2001 if let Some(op) = extract_binary_operator(cursor) {
2002 matches!(
2003 op,
2004 BinaryOperator::Equal
2005 | BinaryOperator::NotEqual
2006 | BinaryOperator::LessThan
2007 | BinaryOperator::GreaterThan
2008 | BinaryOperator::LessEqual
2009 | BinaryOperator::GreaterEqual
2010 | BinaryOperator::LogicalAnd
2011 | BinaryOperator::LogicalOr
2012 )
2013 } else {
2014 false
2015 }
2016 }
2017
2018 fn extract_increment_stmts(cursor: CXCursor) -> Vec<Statement> {
2020 let kind = unsafe { clang_getCursorKind(cursor) };
2021 let mut stmts = Vec::new();
2022
2023 if kind == CXCursor_BinaryOperator {
2025 if let Some(BinaryOperator::Comma) = extract_binary_operator(cursor) {
2027 let mut children: Vec<CXCursor> = Vec::new();
2029 let children_ptr = &mut children as *mut Vec<CXCursor>;
2030
2031 extern "C" fn collect_children(
2032 cursor: CXCursor,
2033 _parent: CXCursor,
2034 client_data: CXClientData,
2035 ) -> CXChildVisitResult {
2036 let children = unsafe { &mut *(client_data as *mut Vec<CXCursor>) };
2037 children.push(cursor);
2038 CXChildVisit_Continue
2039 }
2040
2041 unsafe {
2042 clang_visitChildren(cursor, collect_children, children_ptr as CXClientData);
2043 }
2044
2045 for child in children {
2046 stmts.extend(extract_increment_stmts(child));
2047 }
2048 return stmts;
2049 }
2050 if let Some(stmt) = extract_assignment_stmt(cursor) {
2052 stmts.push(stmt);
2053 }
2054 } else if kind == CXCursor_UnaryOperator {
2055 if let Some(stmt) = extract_inc_dec_stmt(cursor) {
2056 stmts.push(stmt);
2057 }
2058 }
2059 stmts
2060 }
2061
2062 if num_children == 0 {
2063 return Some(Statement::For {
2064 init,
2065 condition,
2066 increment,
2067 body,
2068 });
2069 }
2070
2071 let body_idx = num_children - 1;
2074 let body_child = &collector.children[body_idx];
2075
2076 if body_child.kind == CXCursor_CompoundStmt {
2078 let body_ptr = &mut body as *mut Vec<Statement>;
2079 unsafe {
2080 clang_visitChildren(body_child.cursor, visit_statement, body_ptr as CXClientData);
2081 }
2082 } else {
2083 if let Some(stmt) = extract_single_statement(body_child.cursor) {
2085 body.push(stmt);
2086 }
2087 }
2088
2089 let pre_body = &collector.children[..body_idx];
2091
2092 match pre_body.len() {
2093 0 => {
2094 }
2096 1 => {
2097 let child = &pre_body[0];
2100 if child.kind == CXCursor_DeclStmt {
2101 let mut init_stmts = Vec::new();
2103 let ptr = &mut init_stmts as *mut Vec<Statement>;
2104 unsafe {
2105 clang_visitChildren(child.cursor, visit_statement, ptr as CXClientData);
2106 }
2107 } else if child.kind == CXCursor_BinaryOperator {
2108 if is_assignment_op(child.cursor) {
2109 if let Some(stmt) = extract_assignment_stmt(child.cursor) {
2111 init.push(stmt);
2112 }
2113 } else if is_condition_op(child.cursor) {
2114 condition = extract_binary_op(child.cursor);
2116 } else {
2117 condition = extract_binary_op(child.cursor);
2119 }
2120 } else if child.kind == CXCursor_UnaryOperator {
2121 increment = extract_increment_stmts(child.cursor);
2122 } else {
2123 condition = extract_expression_from_cursor(child.cursor);
2125 }
2126 }
2127 2 => {
2128 let child0 = &pre_body[0];
2131 let child1 = &pre_body[1];
2132
2133 let first_is_init = child0.kind == CXCursor_DeclStmt
2135 || (child0.kind == CXCursor_BinaryOperator && is_assignment_op(child0.cursor));
2136
2137 if first_is_init {
2138 if child0.kind == CXCursor_DeclStmt {
2140 let ptr = &mut init as *mut Vec<Statement>;
2142 unsafe {
2143 clang_visitChildren(child0.cursor, visit_statement, ptr as CXClientData);
2144 }
2145 } else if let Some(stmt) = extract_assignment_stmt(child0.cursor) {
2146 init.push(stmt);
2147 }
2148 condition = extract_expression_from_cursor(child1.cursor);
2149 } else {
2150 condition = extract_expression_from_cursor(child0.cursor);
2152 increment = extract_increment_stmts(child1.cursor);
2153 }
2154 }
2155 3 => {
2156 let child0 = &pre_body[0];
2158 let child1 = &pre_body[1];
2159 let child2 = &pre_body[2];
2160
2161 if child0.kind == CXCursor_DeclStmt {
2163 let ptr = &mut init as *mut Vec<Statement>;
2164 unsafe {
2165 clang_visitChildren(child0.cursor, visit_statement, ptr as CXClientData);
2166 }
2167 } else if child0.kind == CXCursor_BinaryOperator {
2168 if let Some(stmt) = extract_assignment_stmt(child0.cursor) {
2169 init.push(stmt);
2170 }
2171 }
2172
2173 condition = extract_expression_from_cursor(child1.cursor);
2175
2176 increment = extract_increment_stmts(child2.cursor);
2178 }
2179 _ => {
2180 }
2182 }
2183
2184 Some(Statement::For {
2185 init,
2186 condition,
2187 increment,
2188 body,
2189 })
2190}
2191
2192fn extract_expression_from_cursor(cursor: CXCursor) -> Option<Expression> {
2194 let kind = unsafe { clang_getCursorKind(cursor) };
2195 match kind {
2196 CXCursor_BinaryOperator => extract_binary_op(cursor),
2197 CXCursor_IntegerLiteral => extract_int_literal(cursor),
2198 107 => extract_float_literal(cursor), 110 => extract_char_literal(cursor), CXCursor_DeclRefExpr => extract_variable_ref(cursor),
2201 CXCursor_CallExpr => extract_function_call(cursor),
2202 CXCursor_UnaryOperator => extract_unary_op(cursor),
2203 _ => {
2204 let mut expr: Option<Expression> = None;
2205 let expr_ptr = &mut expr as *mut Option<Expression>;
2206 unsafe {
2207 clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
2208 }
2209 expr
2210 }
2211 }
2212}
2213
2214fn extract_single_statement(cursor: CXCursor) -> Option<Statement> {
2216 let kind = unsafe { clang_getCursorKind(cursor) };
2217 match kind {
2218 CXCursor_IfStmt => extract_if_stmt(cursor),
2219 CXCursor_ForStmt => extract_for_stmt(cursor),
2220 CXCursor_WhileStmt => extract_while_stmt(cursor),
2221 CXCursor_ReturnStmt => extract_return_stmt(cursor),
2222 CXCursor_SwitchStmt => extract_switch_stmt(cursor),
2223 CXCursor_UnaryOperator => extract_inc_dec_stmt(cursor),
2224 CXCursor_BinaryOperator => extract_assignment_stmt(cursor),
2225 CXCursor_CallExpr => {
2226 if let Some(Expression::FunctionCall {
2227 function,
2228 arguments,
2229 }) = extract_function_call(cursor)
2230 {
2231 Some(Statement::FunctionCall {
2232 function,
2233 arguments,
2234 })
2235 } else {
2236 None
2237 }
2238 }
2239 CXCursor_BreakStmt => Some(Statement::Break),
2240 CXCursor_ContinueStmt => Some(Statement::Continue),
2241 CXCursor_DoStmt | CXCursor_NullStmt => None, _ => None,
2243 }
2244}
2245fn extract_while_stmt(cursor: CXCursor) -> Option<Statement> {
2247 #[repr(C)]
2252 struct WhileData {
2253 condition: Option<Expression>,
2254 body: Vec<Statement>,
2255 child_index: u32,
2256 }
2257
2258 let mut while_data = WhileData {
2259 condition: None,
2260 body: Vec::new(),
2261 child_index: 0,
2262 };
2263
2264 let data_ptr = &mut while_data as *mut WhileData;
2265
2266 unsafe {
2267 clang_visitChildren(cursor, visit_while_children, data_ptr as CXClientData);
2268 }
2269
2270 Some(Statement::While {
2271 condition: while_data.condition?,
2272 body: while_data.body,
2273 })
2274}
2275
2276#[allow(non_upper_case_globals)]
2278extern "C" fn visit_while_children(
2279 cursor: CXCursor,
2280 _parent: CXCursor,
2281 client_data: CXClientData,
2282) -> CXChildVisitResult {
2283 #[repr(C)]
2284 struct WhileData {
2285 condition: Option<Expression>,
2286 body: Vec<Statement>,
2287 child_index: u32,
2288 }
2289
2290 let while_data = unsafe { &mut *(client_data as *mut WhileData) };
2291 let kind = unsafe { clang_getCursorKind(cursor) };
2292
2293 match while_data.child_index {
2294 0 => {
2295 while_data.condition = match kind {
2298 CXCursor_BinaryOperator => extract_binary_op(cursor),
2299 CXCursor_IntegerLiteral => extract_int_literal(cursor),
2300 107 => extract_float_literal(cursor), 110 => extract_char_literal(cursor), CXCursor_DeclRefExpr => extract_variable_ref(cursor),
2303 CXCursor_CallExpr => extract_function_call(cursor),
2304 CXCursor_UnaryOperator => extract_unary_op(cursor),
2305 _ => {
2306 let mut cond_expr: Option<Expression> = None;
2307 let expr_ptr = &mut cond_expr as *mut Option<Expression>;
2308 unsafe {
2309 clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
2310 }
2311 cond_expr
2312 }
2313 };
2314 while_data.child_index += 1;
2315 CXChildVisit_Continue
2316 }
2317 1 => {
2318 if kind == CXCursor_CompoundStmt {
2320 let body_ptr = &mut while_data.body as *mut Vec<Statement>;
2321 unsafe {
2322 clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
2323 }
2324 }
2325 while_data.child_index += 1;
2326 CXChildVisit_Continue
2327 }
2328 _ => CXChildVisit_Continue,
2329 }
2330}
2331
2332#[allow(non_upper_case_globals)]
2336fn extract_switch_stmt(cursor: CXCursor) -> Option<Statement> {
2337 #[repr(C)]
2342 struct SwitchData {
2343 condition: Option<Expression>,
2344 cases: Vec<SwitchCase>,
2345 default_case: Option<Vec<Statement>>,
2346 child_index: u32,
2347 }
2348
2349 let mut switch_data = SwitchData {
2350 condition: None,
2351 cases: Vec::new(),
2352 default_case: None,
2353 child_index: 0,
2354 };
2355
2356 let data_ptr = &mut switch_data as *mut SwitchData;
2357
2358 unsafe {
2359 clang_visitChildren(cursor, visit_switch_children, data_ptr as CXClientData);
2360 }
2361
2362 Some(Statement::Switch {
2363 condition: switch_data.condition?,
2364 cases: switch_data.cases,
2365 default_case: switch_data.default_case,
2366 })
2367}
2368
2369#[allow(non_upper_case_globals)]
2371extern "C" fn visit_switch_children(
2372 cursor: CXCursor,
2373 _parent: CXCursor,
2374 client_data: CXClientData,
2375) -> CXChildVisitResult {
2376 #[repr(C)]
2377 struct SwitchData {
2378 condition: Option<Expression>,
2379 cases: Vec<SwitchCase>,
2380 default_case: Option<Vec<Statement>>,
2381 child_index: u32,
2382 }
2383
2384 let switch_data = unsafe { &mut *(client_data as *mut SwitchData) };
2385 let kind = unsafe { clang_getCursorKind(cursor) };
2386
2387 match switch_data.child_index {
2388 0 => {
2389 if let Some(expr) = try_extract_expression(cursor) {
2391 switch_data.condition = Some(expr);
2392 }
2393 switch_data.child_index += 1;
2394 CXChildVisit_Continue
2395 }
2396 1 => {
2397 if kind == CXCursor_CompoundStmt {
2400 unsafe {
2401 clang_visitChildren(cursor, visit_switch_body, client_data);
2402 }
2403 }
2404 switch_data.child_index += 1;
2405 CXChildVisit_Continue
2406 }
2407 _ => CXChildVisit_Continue,
2408 }
2409}
2410
2411#[allow(non_upper_case_globals)]
2413extern "C" fn visit_switch_body(
2414 cursor: CXCursor,
2415 _parent: CXCursor,
2416 client_data: CXClientData,
2417) -> CXChildVisitResult {
2418 #[repr(C)]
2419 struct SwitchData {
2420 condition: Option<Expression>,
2421 cases: Vec<SwitchCase>,
2422 default_case: Option<Vec<Statement>>,
2423 child_index: u32,
2424 }
2425
2426 let switch_data = unsafe { &mut *(client_data as *mut SwitchData) };
2427 let kind = unsafe { clang_getCursorKind(cursor) };
2428
2429 match kind {
2430 CXCursor_CaseStmt => {
2431 if let Some(case) = extract_case_stmt(cursor) {
2433 switch_data.cases.push(case);
2434 }
2435 CXChildVisit_Continue
2436 }
2437 CXCursor_DefaultStmt => {
2438 if let Some(body) = extract_default_stmt(cursor) {
2440 switch_data.default_case = Some(body);
2441 }
2442 CXChildVisit_Continue
2443 }
2444 _ => CXChildVisit_Continue,
2445 }
2446}
2447
2448fn extract_case_stmt(cursor: CXCursor) -> Option<SwitchCase> {
2450 #[repr(C)]
2455 struct CaseData {
2456 value: Option<Expression>,
2457 body: Vec<Statement>,
2458 child_index: u32,
2459 }
2460
2461 let mut case_data = CaseData {
2462 value: None,
2463 body: Vec::new(),
2464 child_index: 0,
2465 };
2466
2467 let data_ptr = &mut case_data as *mut CaseData;
2468
2469 unsafe {
2470 clang_visitChildren(cursor, visit_case_children, data_ptr as CXClientData);
2471 }
2472
2473 Some(SwitchCase {
2474 value: case_data.value,
2475 body: case_data.body,
2476 })
2477}
2478
2479#[allow(non_upper_case_globals)]
2481extern "C" fn visit_case_children(
2482 cursor: CXCursor,
2483 _parent: CXCursor,
2484 client_data: CXClientData,
2485) -> CXChildVisitResult {
2486 #[repr(C)]
2487 struct CaseData {
2488 value: Option<Expression>,
2489 body: Vec<Statement>,
2490 child_index: u32,
2491 }
2492
2493 let case_data = unsafe { &mut *(client_data as *mut CaseData) };
2494 let _kind = unsafe { clang_getCursorKind(cursor) };
2495
2496 match case_data.child_index {
2497 0 => {
2498 if let Some(expr) = try_extract_expression(cursor) {
2500 case_data.value = Some(expr);
2501 }
2502 case_data.child_index += 1;
2503 CXChildVisit_Continue
2504 }
2505 _ => {
2506 if let Some(stmt) = extract_statement(cursor) {
2509 case_data.body.push(stmt);
2510 }
2511 CXChildVisit_Recurse
2513 }
2514 }
2515}
2516
2517fn extract_default_stmt(cursor: CXCursor) -> Option<Vec<Statement>> {
2519 let mut body: Vec<Statement> = Vec::new();
2521 let body_ptr = &mut body as *mut Vec<Statement>;
2522
2523 unsafe {
2524 clang_visitChildren(cursor, visit_default_children, body_ptr as CXClientData);
2525 }
2526
2527 Some(body)
2528}
2529
2530#[allow(non_upper_case_globals)]
2532extern "C" fn visit_default_children(
2533 cursor: CXCursor,
2534 _parent: CXCursor,
2535 client_data: CXClientData,
2536) -> CXChildVisitResult {
2537 let body = unsafe { &mut *(client_data as *mut Vec<Statement>) };
2538
2539 if let Some(stmt) = extract_statement(cursor) {
2541 body.push(stmt);
2542 }
2543
2544 CXChildVisit_Continue
2545}
2546
2547#[allow(non_upper_case_globals)]
2549fn extract_statement(cursor: CXCursor) -> Option<Statement> {
2550 let kind = unsafe { clang_getCursorKind(cursor) };
2551
2552 match kind {
2553 CXCursor_ReturnStmt => extract_return_stmt(cursor),
2554 CXCursor_VarDecl => extract_var_decl(cursor),
2555 CXCursor_IfStmt => extract_if_stmt(cursor),
2556 CXCursor_ForStmt => extract_for_stmt(cursor),
2557 CXCursor_WhileStmt => extract_while_stmt(cursor),
2558 CXCursor_BreakStmt => Some(Statement::Break),
2559 CXCursor_ContinueStmt => Some(Statement::Continue),
2560 CXCursor_UnaryOperator => extract_inc_dec_stmt(cursor),
2561 CXCursor_BinaryOperator => extract_assignment_stmt(cursor),
2562 CXCursor_CallExpr => {
2563 if let Some(Expression::FunctionCall {
2565 function,
2566 arguments,
2567 }) = extract_function_call(cursor)
2568 {
2569 return Some(Statement::FunctionCall {
2570 function,
2571 arguments,
2572 });
2573 }
2574 None
2575 }
2576 _ => None,
2577 }
2578}
2579
2580#[allow(non_upper_case_globals)]
2586extern "C" fn visit_expression(
2587 cursor: CXCursor,
2588 _parent: CXCursor,
2589 client_data: CXClientData,
2590) -> CXChildVisitResult {
2591 let expr_opt = unsafe { &mut *(client_data as *mut Option<Expression>) };
2593
2594 let kind = unsafe { clang_getCursorKind(cursor) };
2596
2597 match kind {
2598 CXCursor_IntegerLiteral => {
2599 if let Some(expr) = extract_int_literal(cursor) {
2601 *expr_opt = Some(expr);
2602 }
2603 CXChildVisit_Continue
2604 }
2605 107 => {
2606 if let Some(expr) = extract_float_literal(cursor) {
2608 *expr_opt = Some(expr);
2609 }
2610 CXChildVisit_Continue
2611 }
2612 CXCursor_StringLiteral => {
2613 if let Some(expr) = extract_string_literal(cursor) {
2615 *expr_opt = Some(expr);
2616 }
2617 CXChildVisit_Continue
2618 }
2619 110 => {
2620 if let Some(expr) = extract_char_literal(cursor) {
2622 *expr_opt = Some(expr);
2623 }
2624 CXChildVisit_Continue
2625 }
2626 CXCursor_DeclRefExpr => {
2627 if let Some(expr) = extract_variable_ref(cursor) {
2629 *expr_opt = Some(expr);
2630 }
2631 CXChildVisit_Continue
2632 }
2633 CXCursor_BinaryOperator => {
2634 if let Some(expr) = extract_binary_op(cursor) {
2636 *expr_opt = Some(expr);
2637 }
2638 CXChildVisit_Continue
2639 }
2640 CXCursor_CallExpr => {
2641 if let Some(expr) = extract_function_call(cursor) {
2643 *expr_opt = Some(expr);
2644 }
2645 CXChildVisit_Continue
2646 }
2647 CXCursor_UnaryOperator => {
2648 if let Some(expr) = extract_unary_op(cursor) {
2650 *expr_opt = Some(expr);
2651 }
2652 CXChildVisit_Continue
2653 }
2654 CXCursor_ArraySubscriptExpr => {
2655 if let Some(expr) = extract_array_index(cursor) {
2657 *expr_opt = Some(expr);
2658 }
2659 CXChildVisit_Continue
2660 }
2661 CXCursor_MemberRefExpr => {
2662 if let Some(expr) = extract_field_access(cursor) {
2664 *expr_opt = Some(expr);
2665 }
2666 CXChildVisit_Continue
2667 }
2668 116 => {
2669 if let Some(expr) = extract_conditional_op(cursor) {
2672 *expr_opt = Some(expr);
2673 }
2674 CXChildVisit_Continue
2675 }
2676 117 => {
2677 if let Some(expr) = extract_cast(cursor) {
2680 *expr_opt = Some(expr);
2681 }
2682 CXChildVisit_Continue
2683 }
2684 CXCursor_UnexposedExpr => {
2685 CXChildVisit_Recurse
2688 }
2689 CXCursor_ParenExpr => {
2690 CXChildVisit_Recurse
2692 }
2693 136 => {
2694 if let Some(expr) = extract_sizeof(cursor) {
2696 *expr_opt = Some(expr);
2697 CXChildVisit_Continue
2698 } else {
2699 CXChildVisit_Recurse
2701 }
2702 }
2703 119 => {
2704 if let Some(expr) = extract_init_list(cursor) {
2707 *expr_opt = Some(expr);
2708 }
2709 CXChildVisit_Continue
2710 }
2711 _ => CXChildVisit_Recurse,
2712 }
2713}
2714
2715fn extract_int_literal(cursor: CXCursor) -> Option<Expression> {
2717 let extent = unsafe { clang_getCursorExtent(cursor) };
2719
2720 let tu = unsafe {
2722 let loc = clang_getCursorLocation(cursor);
2723 let mut file = ptr::null_mut();
2724 let mut line = 0;
2725 let mut column = 0;
2726 let mut offset = 0;
2727 clang_getFileLocation(loc, &mut file, &mut line, &mut column, &mut offset);
2728
2729 clang_Cursor_getTranslationUnit(cursor)
2732 };
2733
2734 if tu.is_null() {
2735 return Some(Expression::IntLiteral(0));
2736 }
2737
2738 let mut tokens = ptr::null_mut();
2740 let mut num_tokens = 0;
2741
2742 unsafe {
2743 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2744 }
2745
2746 let mut value = 0;
2747
2748 if num_tokens > 0 {
2749 unsafe {
2751 let token_cxstring = clang_getTokenSpelling(tu, *tokens);
2752 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2753 if let Ok(token_str) = c_str.to_str() {
2754 value = token_str.parse().unwrap_or(0);
2755 }
2756 clang_disposeString(token_cxstring);
2757
2758 clang_disposeTokens(tu, tokens, num_tokens);
2760 }
2761 } else {
2762 unsafe {
2765 let eval_result = clang_Cursor_Evaluate(cursor);
2766 if !eval_result.is_null() {
2767 value = clang_EvalResult_getAsInt(eval_result);
2768 clang_EvalResult_dispose(eval_result);
2769 }
2770 }
2771 }
2772
2773 Some(Expression::IntLiteral(value))
2774}
2775
2776fn extract_float_literal(cursor: CXCursor) -> Option<Expression> {
2778 let extent = unsafe { clang_getCursorExtent(cursor) };
2780
2781 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2783
2784 if tu.is_null() {
2785 return Some(Expression::FloatLiteral("0.0".to_string()));
2786 }
2787
2788 let mut tokens = ptr::null_mut();
2790 let mut num_tokens = 0;
2791
2792 unsafe {
2793 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2794 }
2795
2796 let mut value = "0.0".to_string();
2797
2798 if num_tokens > 0 {
2799 unsafe {
2801 let token_cxstring = clang_getTokenSpelling(tu, *tokens);
2802 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2803 if let Ok(token_str) = c_str.to_str() {
2804 value = token_str.to_string();
2806 }
2807 clang_disposeString(token_cxstring);
2808
2809 clang_disposeTokens(tu, tokens, num_tokens);
2811 }
2812 } else {
2813 unsafe {
2815 let eval_result = clang_Cursor_Evaluate(cursor);
2816 if !eval_result.is_null() {
2817 let float_val = clang_EvalResult_getAsDouble(eval_result);
2818 value = format!("{}", float_val);
2819 clang_EvalResult_dispose(eval_result);
2820 }
2821 }
2822 }
2823
2824 Some(Expression::FloatLiteral(value))
2825}
2826
2827fn extract_string_literal(cursor: CXCursor) -> Option<Expression> {
2829 let extent = unsafe { clang_getCursorExtent(cursor) };
2831
2832 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2834
2835 if tu.is_null() {
2836 return Some(Expression::StringLiteral(String::new()));
2837 }
2838
2839 let mut tokens = ptr::null_mut();
2841 let mut num_tokens = 0;
2842
2843 unsafe {
2844 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2845 }
2846
2847 let mut value = String::new();
2848
2849 if num_tokens > 0 {
2850 unsafe {
2852 let token_cxstring = clang_getTokenSpelling(tu, *tokens);
2853 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2854 if let Ok(token_str) = c_str.to_str() {
2855 value = token_str.trim_matches('"').to_string();
2857 }
2858 clang_disposeString(token_cxstring);
2859
2860 clang_disposeTokens(tu, tokens, num_tokens);
2862 }
2863 }
2864
2865 Some(Expression::StringLiteral(value))
2866}
2867
2868fn extract_char_literal(cursor: CXCursor) -> Option<Expression> {
2871 let extent = unsafe { clang_getCursorExtent(cursor) };
2873
2874 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2876
2877 if tu.is_null() {
2878 return Some(Expression::CharLiteral(0));
2879 }
2880
2881 let mut tokens = ptr::null_mut();
2883 let mut num_tokens = 0;
2884
2885 unsafe {
2886 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2887 }
2888
2889 let mut value: i8 = 0;
2890
2891 if num_tokens > 0 {
2892 unsafe {
2894 let token_cxstring = clang_getTokenSpelling(tu, *tokens);
2895 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2896 if let Ok(token_str) = c_str.to_str() {
2897 let inner = token_str.trim_matches('\'');
2899 value = parse_char_literal(inner);
2900 }
2901 clang_disposeString(token_cxstring);
2902
2903 clang_disposeTokens(tu, tokens, num_tokens);
2905 }
2906 }
2907
2908 Some(Expression::CharLiteral(value))
2909}
2910
2911fn parse_char_literal(s: &str) -> i8 {
2914 if s.is_empty() {
2915 return 0;
2916 }
2917
2918 let mut chars = s.chars();
2919 let first = chars.next().unwrap();
2920
2921 if first == '\\' {
2922 match chars.next() {
2924 Some('0') => 0, Some('n') => b'\n' as i8,
2926 Some('t') => b'\t' as i8,
2927 Some('r') => b'\r' as i8,
2928 Some('\\') => b'\\' as i8,
2929 Some('\'') => b'\'' as i8,
2930 Some('"') => b'"' as i8,
2931 Some('a') => 7, Some('b') => 8, Some('f') => 12, Some('v') => 11, Some('x') => {
2936 let hex: String = chars.take(2).collect();
2938 i8::from_str_radix(&hex, 16).unwrap_or(0)
2939 }
2940 Some(c) if c.is_ascii_digit() => {
2941 let mut octal = String::new();
2943 octal.push(c);
2944 for _ in 0..2 {
2945 if let Some(d) = chars.next() {
2946 if d.is_ascii_digit() && d < '8' {
2947 octal.push(d);
2948 } else {
2949 break;
2950 }
2951 }
2952 }
2953 i8::from_str_radix(&octal, 8).unwrap_or(0)
2954 }
2955 _ => first as i8,
2956 }
2957 } else {
2958 first as i8
2960 }
2961}
2962
2963fn extract_variable_ref(cursor: CXCursor) -> Option<Expression> {
2965 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
2967 let name = unsafe {
2968 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
2969 let var_name = c_str.to_string_lossy().into_owned();
2970 clang_disposeString(name_cxstring);
2971 var_name
2972 };
2973
2974 Some(Expression::Variable(name))
2975}
2976
2977fn extract_binary_op(cursor: CXCursor) -> Option<Expression> {
2979 let op = extract_binary_operator(cursor)?;
2981
2982 let mut operands: Vec<Expression> = Vec::new();
2984 let operands_ptr = &mut operands as *mut Vec<Expression>;
2985
2986 unsafe {
2987 clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
2988 }
2989
2990 if operands.len() != 2 {
2992 return None;
2993 }
2994
2995 Some(Expression::BinaryOp {
2996 op,
2997 left: Box::new(operands[0].clone()),
2998 right: Box::new(operands[1].clone()),
2999 })
3000}
3001
3002#[allow(non_upper_case_globals)]
3004extern "C" fn visit_binary_operand(
3005 cursor: CXCursor,
3006 _parent: CXCursor,
3007 client_data: CXClientData,
3008) -> CXChildVisitResult {
3009 let operands = unsafe { &mut *(client_data as *mut Vec<Expression>) };
3010 let kind = unsafe { clang_getCursorKind(cursor) };
3011
3012 match kind {
3013 CXCursor_IntegerLiteral => {
3014 if let Some(expr) = extract_int_literal(cursor) {
3015 operands.push(expr);
3016 }
3017 CXChildVisit_Continue
3018 }
3019 107 => {
3020 if let Some(expr) = extract_float_literal(cursor) {
3022 operands.push(expr);
3023 }
3024 CXChildVisit_Continue
3025 }
3026 CXCursor_StringLiteral => {
3027 if let Some(expr) = extract_string_literal(cursor) {
3028 operands.push(expr);
3029 }
3030 CXChildVisit_Continue
3031 }
3032 110 => {
3033 if let Some(expr) = extract_char_literal(cursor) {
3035 operands.push(expr);
3036 }
3037 CXChildVisit_Continue
3038 }
3039 CXCursor_DeclRefExpr => {
3040 if let Some(expr) = extract_variable_ref(cursor) {
3041 operands.push(expr);
3042 }
3043 CXChildVisit_Continue
3044 }
3045 CXCursor_BinaryOperator => {
3046 if let Some(expr) = extract_binary_op(cursor) {
3048 operands.push(expr);
3049 }
3050 CXChildVisit_Continue
3051 }
3052 CXCursor_UnaryOperator => {
3053 if let Some(expr) = extract_unary_op(cursor) {
3055 operands.push(expr);
3056 }
3057 CXChildVisit_Continue
3058 }
3059 CXCursor_ArraySubscriptExpr => {
3060 if let Some(expr) = extract_array_index(cursor) {
3062 operands.push(expr);
3063 }
3064 CXChildVisit_Continue
3065 }
3066 CXCursor_MemberRefExpr => {
3067 if let Some(expr) = extract_field_access(cursor) {
3069 operands.push(expr);
3070 }
3071 CXChildVisit_Continue
3072 }
3073 CXCursor_UnexposedExpr | CXCursor_ParenExpr => {
3074 if let Some(expr) = extract_sizeof(cursor) {
3076 operands.push(expr);
3077 CXChildVisit_Continue
3078 } else {
3079 CXChildVisit_Recurse
3080 }
3081 }
3082 136 => {
3083 if let Some(expr) = extract_sizeof(cursor) {
3085 operands.push(expr);
3086 CXChildVisit_Continue
3087 } else {
3088 CXChildVisit_Recurse
3089 }
3090 }
3091 CXCursor_CallExpr => {
3092 if let Some(expr) = extract_function_call(cursor) {
3094 operands.push(expr);
3095 }
3096 CXChildVisit_Continue
3097 }
3098 116 => {
3099 if let Some(expr) = extract_conditional_op(cursor) {
3101 operands.push(expr);
3102 }
3103 CXChildVisit_Continue
3104 }
3105 _ => CXChildVisit_Recurse,
3106 }
3107}
3108
3109#[allow(non_upper_case_globals)]
3112fn extract_binary_operator_from_children(
3113 cursor: CXCursor,
3114 tu: CXTranslationUnit,
3115) -> Option<BinaryOperator> {
3116 let mut children: Vec<CXCursor> = Vec::new();
3118 let children_ptr = &mut children as *mut Vec<CXCursor>;
3119
3120 extern "C" fn collect_children(
3121 cursor: CXCursor,
3122 _parent: CXCursor,
3123 client_data: CXClientData,
3124 ) -> CXChildVisitResult {
3125 let children = unsafe { &mut *(client_data as *mut Vec<CXCursor>) };
3126 children.push(cursor);
3127 CXChildVisit_Continue
3128 }
3129
3130 unsafe {
3131 clang_visitChildren(cursor, collect_children, children_ptr as CXClientData);
3132 }
3133
3134 if children.len() != 2 {
3136 return None;
3137 }
3138
3139 let first_extent = unsafe { clang_getCursorExtent(children[0]) };
3141 let second_extent = unsafe { clang_getCursorExtent(children[1]) };
3142
3143 let first_end = unsafe { clang_getRangeEnd(first_extent) };
3144 let second_start = unsafe { clang_getRangeStart(second_extent) };
3145
3146 let operator_range = unsafe { clang_getRange(first_end, second_start) };
3148
3149 let mut tokens = ptr::null_mut();
3151 let mut num_tokens = 0;
3152
3153 unsafe {
3154 clang_tokenize(tu, operator_range, &mut tokens, &mut num_tokens);
3155 }
3156
3157 if tokens.is_null() || num_tokens == 0 {
3158 return None;
3159 }
3160
3161 let mut result = None;
3163 for i in 0..num_tokens {
3164 unsafe {
3165 let token = *tokens.add(i as usize);
3166 let token_kind = clang_getTokenKind(token);
3167
3168 if token_kind == CXToken_Punctuation {
3169 let token_cxstring = clang_getTokenSpelling(tu, token);
3170 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
3171 if let Ok(token_str) = c_str.to_str() {
3172 result = match token_str {
3173 "+" => Some(BinaryOperator::Add),
3174 "-" => Some(BinaryOperator::Subtract),
3175 "*" => Some(BinaryOperator::Multiply),
3176 "/" => Some(BinaryOperator::Divide),
3177 "%" => Some(BinaryOperator::Modulo),
3178 "==" => Some(BinaryOperator::Equal),
3179 "!=" => Some(BinaryOperator::NotEqual),
3180 "<" => Some(BinaryOperator::LessThan),
3181 ">" => Some(BinaryOperator::GreaterThan),
3182 "<=" => Some(BinaryOperator::LessEqual),
3183 ">=" => Some(BinaryOperator::GreaterEqual),
3184 "&&" => Some(BinaryOperator::LogicalAnd),
3185 "||" => Some(BinaryOperator::LogicalOr),
3186 "<<" => Some(BinaryOperator::LeftShift),
3187 ">>" => Some(BinaryOperator::RightShift),
3188 "&" => Some(BinaryOperator::BitwiseAnd),
3189 "|" => Some(BinaryOperator::BitwiseOr),
3190 "^" => Some(BinaryOperator::BitwiseXor),
3191 "=" => Some(BinaryOperator::Assign),
3192 "," => Some(BinaryOperator::Comma),
3193 _ => None,
3194 };
3195 if result.is_some() {
3196 clang_disposeString(token_cxstring);
3197 break;
3198 }
3199 }
3200 clang_disposeString(token_cxstring);
3201 }
3202 }
3203 }
3204
3205 unsafe {
3207 clang_disposeTokens(tu, tokens, num_tokens);
3208 }
3209
3210 result
3211}
3212
3213#[allow(non_upper_case_globals)]
3215fn extract_binary_operator(cursor: CXCursor) -> Option<BinaryOperator> {
3216 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
3218 if tu.is_null() {
3219 return None;
3220 }
3221
3222 if let Some(op) = extract_binary_operator_from_children(cursor, tu) {
3225 return Some(op);
3226 }
3227
3228 let extent = unsafe { clang_getCursorExtent(cursor) };
3230
3231 let mut tokens = ptr::null_mut();
3233 let mut num_tokens = 0;
3234
3235 unsafe {
3236 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
3237 }
3238
3239 let cursor_loc = unsafe { clang_getCursorLocation(cursor) };
3243 let mut cursor_file: CXFile = ptr::null_mut();
3244 let mut _line = 0u32;
3245 let mut _col = 0u32;
3246 let mut _offset = 0u32;
3247 unsafe {
3248 clang_getExpansionLocation(
3249 cursor_loc,
3250 &mut cursor_file,
3251 &mut _line,
3252 &mut _col,
3253 &mut _offset,
3254 );
3255 }
3256
3257 let mut operator = None;
3258
3259 let mut candidates: Vec<(usize, BinaryOperator)> = Vec::new();
3266 let mut found_first_operand = false;
3267 let mut paren_depth: i32 = 0; let extent_start = unsafe { clang_getRangeStart(extent) };
3271 let extent_end = unsafe { clang_getRangeEnd(extent) };
3272 let mut start_line = 0u32;
3273 let mut end_line = 0u32;
3274 unsafe {
3275 clang_getExpansionLocation(
3276 extent_start,
3277 ptr::null_mut(),
3278 &mut start_line,
3279 ptr::null_mut(),
3280 ptr::null_mut(),
3281 );
3282 clang_getExpansionLocation(
3283 extent_end,
3284 ptr::null_mut(),
3285 &mut end_line,
3286 ptr::null_mut(),
3287 ptr::null_mut(),
3288 );
3289 }
3290
3291 for i in 0..num_tokens {
3292 unsafe {
3293 let token = *tokens.add(i as usize);
3294 let token_kind = clang_getTokenKind(token);
3295
3296 let token_loc = clang_getTokenLocation(tu, token);
3298 let mut token_file: CXFile = ptr::null_mut();
3299 let mut token_line = 0u32;
3300 clang_getExpansionLocation(
3301 token_loc,
3302 &mut token_file,
3303 &mut token_line,
3304 &mut _col,
3305 &mut _offset,
3306 );
3307
3308 if !cursor_file.is_null() && !token_file.is_null() && token_file != cursor_file {
3310 continue;
3311 }
3312
3313 if start_line > 0
3318 && end_line > 0
3319 && token_line > 0
3320 && (token_line < start_line || token_line > end_line)
3321 {
3322 continue;
3323 }
3324
3325 if token_kind == CXToken_Identifier || token_kind == CXToken_Literal {
3327 found_first_operand = true;
3328 }
3329
3330 if token_kind == CXToken_Punctuation {
3332 let token_cxstring = clang_getTokenSpelling(tu, token);
3333 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
3334 if let Ok(token_str) = c_str.to_str() {
3335 match token_str {
3336 "(" => paren_depth += 1,
3337 ")" => paren_depth = paren_depth.saturating_sub(1),
3338 _ => {}
3339 }
3340
3341 if found_first_operand && paren_depth == 0 {
3344 let op = match token_str {
3345 "+" => Some(BinaryOperator::Add),
3346 "-" => Some(BinaryOperator::Subtract),
3347 "*" => Some(BinaryOperator::Multiply),
3348 "/" => Some(BinaryOperator::Divide),
3349 "%" => Some(BinaryOperator::Modulo),
3350 "==" => Some(BinaryOperator::Equal),
3351 "!=" => Some(BinaryOperator::NotEqual),
3352 "<" => Some(BinaryOperator::LessThan),
3353 ">" => Some(BinaryOperator::GreaterThan),
3354 "<=" => Some(BinaryOperator::LessEqual),
3355 ">=" => Some(BinaryOperator::GreaterEqual),
3356 "&&" => Some(BinaryOperator::LogicalAnd),
3357 "||" => Some(BinaryOperator::LogicalOr),
3358 "<<" => Some(BinaryOperator::LeftShift),
3360 ">>" => Some(BinaryOperator::RightShift),
3361 "&" => Some(BinaryOperator::BitwiseAnd),
3362 "|" => Some(BinaryOperator::BitwiseOr),
3363 "^" => Some(BinaryOperator::BitwiseXor),
3364 "=" => Some(BinaryOperator::Assign),
3366 "," => Some(BinaryOperator::Comma),
3368 _ => None,
3369 };
3370 if let Some(op) = op {
3371 candidates.push((i as usize, op));
3372 }
3373 }
3374 }
3375 clang_disposeString(token_cxstring);
3376 }
3377 }
3378 }
3379
3380 if !candidates.is_empty() {
3384 let has_arithmetic = candidates.iter().any(|(_, op)| {
3388 matches!(
3389 op,
3390 BinaryOperator::Add
3391 | BinaryOperator::Subtract
3392 | BinaryOperator::Multiply
3393 | BinaryOperator::Divide
3394 | BinaryOperator::Modulo
3395 )
3396 });
3397 let has_comparison = candidates.iter().any(|(_, op)| {
3398 matches!(
3399 op,
3400 BinaryOperator::LessThan
3401 | BinaryOperator::GreaterThan
3402 | BinaryOperator::LessEqual
3403 | BinaryOperator::GreaterEqual
3404 | BinaryOperator::Equal
3405 | BinaryOperator::NotEqual
3406 )
3407 });
3408
3409 if has_arithmetic || has_comparison {
3411 candidates.retain(|(_, op)| !matches!(op, BinaryOperator::Comma));
3412 }
3413
3414 for (_, op) in &candidates {
3416 if matches!(op, BinaryOperator::Assign) {
3417 operator = Some(*op);
3418 break;
3419 }
3420 }
3421 if operator.is_none() {
3423 for (_, op) in &candidates {
3424 if matches!(op, BinaryOperator::LogicalOr) {
3425 operator = Some(*op);
3426 break;
3427 }
3428 }
3429 }
3430 if operator.is_none() {
3432 for (_, op) in &candidates {
3433 if matches!(op, BinaryOperator::LogicalAnd) {
3434 operator = Some(*op);
3435 break;
3436 }
3437 }
3438 }
3439 if operator.is_none() {
3441 for (_, op) in &candidates {
3442 if matches!(op, BinaryOperator::BitwiseOr) {
3443 operator = Some(*op);
3444 break;
3445 }
3446 }
3447 }
3448 if operator.is_none() {
3450 for (_, op) in &candidates {
3451 if matches!(op, BinaryOperator::BitwiseXor) {
3452 operator = Some(*op);
3453 break;
3454 }
3455 }
3456 }
3457 if operator.is_none() {
3459 for (_, op) in &candidates {
3460 if matches!(op, BinaryOperator::BitwiseAnd) {
3461 operator = Some(*op);
3462 break;
3463 }
3464 }
3465 }
3466 if operator.is_none() {
3468 for (_, op) in &candidates {
3469 if matches!(op, BinaryOperator::Equal | BinaryOperator::NotEqual) {
3470 operator = Some(*op);
3471 break;
3472 }
3473 }
3474 }
3475 if operator.is_none() {
3477 for (_, op) in &candidates {
3478 if matches!(
3479 op,
3480 BinaryOperator::LessThan
3481 | BinaryOperator::GreaterThan
3482 | BinaryOperator::LessEqual
3483 | BinaryOperator::GreaterEqual
3484 ) {
3485 operator = Some(*op);
3486 break;
3487 }
3488 }
3489 }
3490 if operator.is_none() {
3492 for (_, op) in &candidates {
3493 if matches!(op, BinaryOperator::LeftShift | BinaryOperator::RightShift) {
3494 operator = Some(*op);
3495 break;
3496 }
3497 }
3498 }
3499 if operator.is_none() {
3501 for (_, op) in &candidates {
3502 if matches!(op, BinaryOperator::Add | BinaryOperator::Subtract) {
3503 operator = Some(*op);
3504 break;
3505 }
3506 }
3507 }
3508 if operator.is_none() {
3510 operator = Some(candidates[0].1);
3511 }
3512 }
3513
3514 unsafe {
3515 clang_disposeTokens(tu, tokens, num_tokens);
3516 }
3517
3518 operator
3519}
3520
3521fn extract_function_call(cursor: CXCursor) -> Option<Expression> {
3523 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
3525 let function = unsafe {
3526 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
3527 let name = c_str.to_string_lossy().into_owned();
3528 clang_disposeString(name_cxstring);
3529 name
3530 };
3531
3532 #[repr(C)]
3535 struct ArgData {
3536 arguments: Vec<Expression>,
3537 skip_first_declref: bool,
3538 }
3539
3540 let mut arg_data = ArgData {
3541 arguments: Vec::new(),
3542 skip_first_declref: true, };
3544 let args_ptr = &mut arg_data as *mut ArgData;
3545
3546 unsafe {
3547 clang_visitChildren(cursor, visit_call_argument, args_ptr as CXClientData);
3548 }
3549
3550 Some(Expression::FunctionCall {
3551 function,
3552 arguments: arg_data.arguments,
3553 })
3554}
3555
3556#[allow(non_upper_case_globals)]
3562extern "C" fn visit_call_argument(
3563 cursor: CXCursor,
3564 _parent: CXCursor,
3565 client_data: CXClientData,
3566) -> CXChildVisitResult {
3567 #[repr(C)]
3568 struct ArgData {
3569 arguments: Vec<Expression>,
3570 skip_first_declref: bool,
3571 }
3572
3573 let arg_data = unsafe { &mut *(client_data as *mut ArgData) };
3575
3576 let kind = unsafe { clang_getCursorKind(cursor) };
3578
3579 match kind {
3580 CXCursor_IntegerLiteral => {
3581 if let Some(expr) = extract_int_literal(cursor) {
3582 arg_data.arguments.push(expr);
3583 }
3584 CXChildVisit_Continue
3585 }
3586 107 => {
3587 if let Some(expr) = extract_float_literal(cursor) {
3589 arg_data.arguments.push(expr);
3590 }
3591 CXChildVisit_Continue
3592 }
3593 CXCursor_StringLiteral => {
3594 if let Some(expr) = extract_string_literal(cursor) {
3595 arg_data.arguments.push(expr);
3596 }
3597 CXChildVisit_Continue
3598 }
3599 110 => {
3600 if let Some(expr) = extract_char_literal(cursor) {
3602 arg_data.arguments.push(expr);
3603 }
3604 CXChildVisit_Continue
3605 }
3606 CXCursor_DeclRefExpr => {
3607 if arg_data.skip_first_declref {
3610 arg_data.skip_first_declref = false;
3611 CXChildVisit_Continue
3612 } else {
3613 if let Some(expr) = extract_variable_ref(cursor) {
3614 arg_data.arguments.push(expr);
3615 }
3616 CXChildVisit_Continue
3617 }
3618 }
3619 CXCursor_BinaryOperator => {
3620 if let Some(expr) = extract_binary_op(cursor) {
3622 arg_data.arguments.push(expr);
3623 }
3624 CXChildVisit_Continue
3625 }
3626 CXCursor_CallExpr => {
3627 if let Some(expr) = extract_function_call(cursor) {
3629 arg_data.arguments.push(expr);
3630 }
3631 CXChildVisit_Continue
3632 }
3633 CXCursor_UnaryOperator => {
3634 if let Some(expr) = extract_unary_op(cursor) {
3636 arg_data.arguments.push(expr);
3637 }
3638 CXChildVisit_Continue
3639 }
3640 CXCursor_ArraySubscriptExpr => {
3641 if let Some(expr) = extract_array_index(cursor) {
3643 arg_data.arguments.push(expr);
3644 }
3645 CXChildVisit_Continue
3646 }
3647 CXCursor_MemberRefExpr => {
3648 if let Some(expr) = extract_field_access(cursor) {
3650 arg_data.arguments.push(expr);
3651 }
3652 CXChildVisit_Continue
3653 }
3654 116 => {
3655 if let Some(expr) = extract_conditional_op(cursor) {
3657 arg_data.arguments.push(expr);
3658 }
3659 CXChildVisit_Continue
3660 }
3661 CXCursor_UnexposedExpr | CXCursor_ParenExpr => {
3662 if let Some(expr) = extract_sizeof(cursor) {
3664 arg_data.arguments.push(expr);
3665 CXChildVisit_Continue
3666 } else {
3667 CXChildVisit_Recurse
3668 }
3669 }
3670 136 => {
3671 if let Some(expr) = extract_sizeof(cursor) {
3673 arg_data.arguments.push(expr);
3674 CXChildVisit_Continue
3675 } else {
3676 CXChildVisit_Recurse
3677 }
3678 }
3679 117 => {
3680 if let Some(expr) = extract_cast(cursor) {
3682 arg_data.arguments.push(expr);
3683 }
3684 CXChildVisit_Continue
3685 }
3686 _ => CXChildVisit_Continue, }
3688}
3689
3690fn extract_unary_op(cursor: CXCursor) -> Option<Expression> {
3692 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
3694 if tu.is_null() {
3695 return None;
3696 }
3697
3698 let extent = unsafe { clang_getCursorExtent(cursor) };
3700
3701 let mut tokens = ptr::null_mut();
3703 let mut num_tokens = 0;
3704
3705 unsafe {
3706 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
3707 }
3708
3709 let mut operator: Option<UnaryOperator> = None;
3710 let mut is_dereference = false;
3711 let mut is_increment = false;
3712 let mut is_decrement = false;
3713 let mut operator_position = 0;
3714
3715 let mut found_star_at_zero = false;
3720 let mut found_open_paren_at_zero = false;
3721 let mut found_increment: Option<u32> = None;
3722 let mut found_decrement: Option<u32> = None;
3723
3724 for i in 0..num_tokens {
3725 unsafe {
3726 let token = *tokens.add(i as usize);
3727 let token_kind = clang_getTokenKind(token);
3728
3729 if token_kind == CXToken_Punctuation {
3730 let token_cxstring = clang_getTokenSpelling(tu, token);
3731 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
3732 if let Ok(token_str) = c_str.to_str() {
3733 match token_str {
3734 "*" if i == 0 => found_star_at_zero = true,
3735 "(" if i == 0 => found_open_paren_at_zero = true,
3736 "++" => {
3737 found_increment = Some(i);
3738 }
3739 "--" => {
3740 found_decrement = Some(i);
3741 }
3742 "-" if i == 0 && operator.is_none() => {
3743 operator = Some(UnaryOperator::Minus);
3744 }
3745 "!" if i == 0 && operator.is_none() => {
3746 operator = Some(UnaryOperator::LogicalNot);
3747 }
3748 "~" if i == 0 && operator.is_none() => {
3749 operator = Some(UnaryOperator::BitwiseNot);
3750 }
3751 "&" if i == 0 && operator.is_none() => {
3752 operator = Some(UnaryOperator::AddressOf);
3753 }
3754 _ => {}
3755 }
3756 }
3757 clang_disposeString(token_cxstring);
3758 }
3759 }
3760 }
3761
3762 let has_unary_op_at_zero = operator.is_some();
3769
3770 if let Some(pos) = found_increment {
3771 if pos == 0 {
3776 is_increment = true;
3777 operator_position = pos;
3778 } else if found_open_paren_at_zero {
3779 is_increment = true;
3781 operator_position = pos;
3782 } else if !has_unary_op_at_zero && !found_star_at_zero {
3783 is_increment = true;
3785 operator_position = pos;
3786 }
3787 }
3788 if let Some(pos) = found_decrement {
3789 if pos == 0 || found_open_paren_at_zero || (!has_unary_op_at_zero && !found_star_at_zero) {
3791 is_decrement = true;
3792 operator_position = pos;
3793 }
3794 }
3795
3796 if !is_increment && !is_decrement && found_star_at_zero {
3798 is_dereference = true;
3799 }
3800 unsafe {
3803 clang_disposeTokens(tu, tokens, num_tokens);
3804 }
3805
3806 let mut operand: Option<Expression> = None;
3808 let operand_ptr = &mut operand as *mut Option<Expression>;
3809
3810 unsafe {
3811 clang_visitChildren(cursor, visit_expression, operand_ptr as CXClientData);
3812 }
3813
3814 let operand_expr = operand?;
3815
3816 if is_dereference {
3818 return Some(Expression::Dereference(Box::new(operand_expr)));
3819 }
3820
3821 if is_increment {
3823 let is_pre = operator_position == 0;
3825 if is_pre {
3826 return Some(Expression::PreIncrement {
3827 operand: Box::new(operand_expr),
3828 });
3829 } else {
3830 return Some(Expression::PostIncrement {
3831 operand: Box::new(operand_expr),
3832 });
3833 }
3834 }
3835
3836 if is_decrement {
3837 let is_pre = operator_position == 0;
3839 if is_pre {
3840 return Some(Expression::PreDecrement {
3841 operand: Box::new(operand_expr),
3842 });
3843 } else {
3844 return Some(Expression::PostDecrement {
3845 operand: Box::new(operand_expr),
3846 });
3847 }
3848 }
3849
3850 if let Some(op) = operator {
3852 return Some(Expression::UnaryOp {
3853 op,
3854 operand: Box::new(operand_expr),
3855 });
3856 }
3857
3858 if let Expression::IntLiteral(_) = &operand_expr {
3866 return Some(Expression::UnaryOp {
3868 op: UnaryOperator::Minus,
3869 operand: Box::new(operand_expr),
3870 });
3871 }
3872
3873 None
3874}
3875
3876fn extract_array_index(cursor: CXCursor) -> Option<Expression> {
3878 let mut operands: Vec<Expression> = Vec::new();
3880 let operands_ptr = &mut operands as *mut Vec<Expression>;
3881
3882 unsafe {
3883 clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
3884 }
3885
3886 if operands.len() != 2 {
3888 return None;
3889 }
3890
3891 Some(Expression::ArrayIndex {
3892 array: Box::new(operands[0].clone()),
3893 index: Box::new(operands[1].clone()),
3894 })
3895}
3896
3897fn extract_field_access(cursor: CXCursor) -> Option<Expression> {
3899 let field_name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
3901 let field = unsafe {
3902 let c_str = CStr::from_ptr(clang_getCString(field_name_cxstring));
3903 let name = c_str.to_string_lossy().into_owned();
3904 clang_disposeString(field_name_cxstring);
3905 name
3906 };
3907
3908 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
3910 if tu.is_null() {
3911 return None;
3912 }
3913
3914 let extent = unsafe { clang_getCursorExtent(cursor) };
3915 let mut tokens = ptr::null_mut();
3916 let mut num_tokens = 0;
3917
3918 unsafe {
3919 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
3920 }
3921
3922 let mut is_arrow = false;
3923
3924 for i in 0..num_tokens {
3929 unsafe {
3930 let token = *tokens.add(i as usize);
3931 let token_kind = clang_getTokenKind(token);
3932
3933 if token_kind == CXToken_Punctuation {
3934 let token_cxstring = clang_getTokenSpelling(tu, token);
3935 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
3936 if let Ok(token_str) = c_str.to_str() {
3937 if token_str == "->" {
3938 is_arrow = true;
3939 } else if token_str == "." {
3941 is_arrow = false;
3942 }
3944 }
3945 clang_disposeString(token_cxstring);
3946 }
3947 }
3948 }
3949
3950 unsafe {
3951 clang_disposeTokens(tu, tokens, num_tokens);
3952 }
3953
3954 let mut object_expr: Option<Expression> = None;
3956 let expr_ptr = &mut object_expr as *mut Option<Expression>;
3957
3958 unsafe {
3959 clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
3960 }
3961
3962 let object = object_expr?;
3963
3964 if is_arrow {
3965 Some(Expression::PointerFieldAccess {
3966 pointer: Box::new(object),
3967 field,
3968 })
3969 } else {
3970 Some(Expression::FieldAccess {
3971 object: Box::new(object),
3972 field,
3973 })
3974 }
3975}
3976
3977fn extract_sizeof(cursor: CXCursor) -> Option<Expression> {
3980 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
3982 if tu.is_null() {
3983 return None;
3984 }
3985
3986 let extent = unsafe { clang_getCursorExtent(cursor) };
3988
3989 let mut tokens = ptr::null_mut();
3991 let mut num_tokens = 0;
3992
3993 unsafe {
3994 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
3995 }
3996
3997 if num_tokens == 0 {
4000 unsafe {
4001 clang_disposeTokens(tu, tokens, num_tokens);
4002 }
4003 return None;
4004 }
4005
4006 let first_token_is_sizeof = unsafe {
4007 let token = *tokens.add(0);
4008 let token_cxstring = clang_getTokenSpelling(tu, token);
4009 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
4010 let is_sizeof = c_str.to_str().map(|s| s == "sizeof").unwrap_or(false);
4011 clang_disposeString(token_cxstring);
4012 is_sizeof
4013 };
4014
4015 if !first_token_is_sizeof {
4016 unsafe {
4017 clang_disposeTokens(tu, tokens, num_tokens);
4018 }
4019 return None;
4020 }
4021
4022 let mut type_name = String::new();
4023 let mut paren_depth = 0;
4024 let mut in_sizeof_parens = false;
4025
4026 for i in 1..num_tokens {
4029 unsafe {
4030 let token = *tokens.add(i as usize);
4031 let token_kind = clang_getTokenKind(token);
4032 let token_cxstring = clang_getTokenSpelling(tu, token);
4033 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
4034
4035 if let Ok(token_str) = c_str.to_str() {
4036 if token_str == "(" {
4037 paren_depth += 1;
4038 in_sizeof_parens = true;
4039 } else if token_str == ")" {
4040 paren_depth -= 1;
4041 if paren_depth == 0 && in_sizeof_parens {
4043 clang_disposeString(token_cxstring);
4044 break;
4045 }
4046 } else if in_sizeof_parens
4047 && (token_kind == CXToken_Identifier || token_kind == CXToken_Keyword)
4048 {
4049 if !type_name.is_empty() {
4051 type_name.push(' ');
4052 }
4053 type_name.push_str(token_str);
4054 }
4055 }
4056
4057 clang_disposeString(token_cxstring);
4058 }
4059 }
4060
4061 unsafe {
4062 clang_disposeTokens(tu, tokens, num_tokens);
4063 }
4064
4065 if !type_name.is_empty() {
4067 Some(Expression::Sizeof { type_name })
4068 } else {
4069 None
4070 }
4071}
4072
4073#[allow(non_upper_case_globals)]
4075fn extract_cast(cursor: CXCursor) -> Option<Expression> {
4080 let target_cx_type = unsafe { clang_getCursorType(cursor) };
4082 let target_type = convert_type(target_cx_type)?;
4083
4084 let mut inner_expr: Option<Expression> = None;
4086 let inner_ptr = &mut inner_expr as *mut Option<Expression>;
4087
4088 unsafe {
4089 clang_visitChildren(cursor, visit_cast_inner, inner_ptr as CXClientData);
4090 }
4091
4092 inner_expr.map(|expr| Expression::Cast {
4093 target_type,
4094 expr: Box::new(expr),
4095 })
4096}
4097
4098#[allow(non_upper_case_globals)]
4100extern "C" fn visit_cast_inner(
4101 cursor: CXCursor,
4102 _parent: CXCursor,
4103 client_data: CXClientData,
4104) -> CXChildVisitResult {
4105 let inner_expr = unsafe { &mut *(client_data as *mut Option<Expression>) };
4106 let kind = unsafe { clang_getCursorKind(cursor) };
4107
4108 if let Some(expr) = try_extract_expression(cursor) {
4110 *inner_expr = Some(expr);
4111 return CXChildVisit_Break; }
4113
4114 match kind {
4116 CXCursor_UnexposedExpr | CXCursor_ParenExpr => CXChildVisit_Recurse,
4117 _ => CXChildVisit_Continue,
4118 }
4119}
4120
4121fn extract_compound_literal(cursor: CXCursor) -> Option<Expression> {
4126 let literal_cx_type = unsafe { clang_getCursorType(cursor) };
4128 let literal_type = convert_type(literal_cx_type)?;
4129
4130 let mut initializers: Vec<Expression> = Vec::new();
4132 let initializers_ptr = &mut initializers as *mut Vec<Expression>;
4133
4134 unsafe {
4135 clang_visitChildren(
4136 cursor,
4137 visit_compound_literal_initializers,
4138 initializers_ptr as CXClientData,
4139 );
4140 }
4141
4142 Some(Expression::CompoundLiteral {
4143 literal_type,
4144 initializers,
4145 })
4146}
4147
4148fn extract_conditional_op(cursor: CXCursor) -> Option<Expression> {
4153 let mut operands: Vec<Expression> = Vec::new();
4155 let operands_ptr = &mut operands as *mut Vec<Expression>;
4156
4157 unsafe {
4158 clang_visitChildren(
4159 cursor,
4160 visit_conditional_operand,
4161 operands_ptr as CXClientData,
4162 );
4163 }
4164
4165 if operands.len() >= 3 {
4168 Some(Expression::Ternary {
4169 condition: Box::new(operands[0].clone()),
4170 then_expr: Box::new(operands[1].clone()),
4171 else_expr: Box::new(operands[2].clone()),
4172 })
4173 } else if operands.len() == 2 {
4174 Some(Expression::Ternary {
4177 condition: Box::new(operands[0].clone()),
4178 then_expr: Box::new(operands[0].clone()),
4179 else_expr: Box::new(operands[1].clone()),
4180 })
4181 } else {
4182 None
4183 }
4184}
4185
4186#[allow(non_upper_case_globals)]
4189extern "C" fn visit_conditional_operand(
4190 cursor: CXCursor,
4191 _parent: CXCursor,
4192 client_data: CXClientData,
4193) -> CXChildVisitResult {
4194 let operands = unsafe { &mut *(client_data as *mut Vec<Expression>) };
4195
4196 if let Some(expr) = try_extract_expression(cursor) {
4198 operands.push(expr);
4199 }
4200
4201 CXChildVisit_Continue
4202}
4203
4204fn extract_init_list(cursor: CXCursor) -> Option<Expression> {
4210 let literal_cx_type = unsafe { clang_getCursorType(cursor) };
4212 let literal_type = convert_type(literal_cx_type)?;
4213
4214 let mut initializers: Vec<Expression> = Vec::new();
4216 let initializers_ptr = &mut initializers as *mut Vec<Expression>;
4217
4218 unsafe {
4219 clang_visitChildren(
4220 cursor,
4221 visit_init_list_children,
4222 initializers_ptr as CXClientData,
4223 );
4224 }
4225
4226 Some(Expression::CompoundLiteral {
4227 literal_type,
4228 initializers,
4229 })
4230}
4231
4232#[allow(non_upper_case_globals)]
4235extern "C" fn visit_init_list_children(
4236 cursor: CXCursor,
4237 _parent: CXCursor,
4238 client_data: CXClientData,
4239) -> CXChildVisitResult {
4240 let initializers = unsafe { &mut *(client_data as *mut Vec<Expression>) };
4241 let kind = unsafe { clang_getCursorKind(cursor) };
4242
4243 if kind == 115 {
4246 let cx_type = unsafe { clang_getCursorType(cursor) };
4248 if let Some(var_type) = convert_type(cx_type) {
4249 let default_expr = match var_type {
4251 Type::Int => Expression::IntLiteral(0),
4252 Type::Float | Type::Double => Expression::IntLiteral(0), Type::Char => Expression::IntLiteral(0),
4254 _ => Expression::IntLiteral(0), };
4256 initializers.push(default_expr);
4257 }
4258 return CXChildVisit_Continue;
4259 }
4260
4261 if kind == CXCursor_UnexposedExpr {
4265 #[repr(C)]
4267 struct ChildInfo {
4268 kinds: Vec<u32>,
4269 exprs: Vec<Expression>,
4270 }
4271
4272 let mut info = ChildInfo {
4273 kinds: Vec::new(),
4274 exprs: Vec::new(),
4275 };
4276 let info_ptr = &mut info as *mut ChildInfo;
4277
4278 extern "C" fn collect_child_info(
4279 cursor: CXCursor,
4280 _parent: CXCursor,
4281 client_data: CXClientData,
4282 ) -> CXChildVisitResult {
4283 let info = unsafe { &mut *(client_data as *mut ChildInfo) };
4284 let kind = unsafe { clang_getCursorKind(cursor) };
4285 info.kinds.push(kind as u32);
4286
4287 if kind == 119 {
4289 if let Some(expr) = extract_init_list(cursor) {
4291 info.exprs.push(expr);
4292 }
4293 } else if let Some(expr) = try_extract_expression(cursor) {
4294 info.exprs.push(expr);
4295 }
4296 CXChildVisit_Continue
4297 }
4298
4299 unsafe {
4300 clang_visitChildren(cursor, collect_child_info, info_ptr as CXClientData);
4301 }
4302
4303 if info.exprs.len() == 2 && matches!(&info.exprs[0], Expression::IntLiteral(_)) {
4305 initializers.push(info.exprs[1].clone());
4306 return CXChildVisit_Continue;
4307 }
4308
4309 if info.kinds.len() == 2 && info.kinds[0] == 47 && !info.exprs.is_empty() {
4312 initializers.push(info.exprs.last().unwrap().clone());
4314 return CXChildVisit_Continue;
4315 }
4316
4317 return CXChildVisit_Recurse;
4319 }
4320
4321 if let Some(expr) = try_extract_expression(cursor) {
4323 initializers.push(expr);
4324 return CXChildVisit_Continue;
4325 }
4326
4327 match kind {
4329 CXCursor_ParenExpr => CXChildVisit_Recurse,
4330 _ => CXChildVisit_Continue,
4331 }
4332}
4333
4334#[allow(non_upper_case_globals)]
4336extern "C" fn visit_compound_literal_initializers(
4337 cursor: CXCursor,
4338 _parent: CXCursor,
4339 client_data: CXClientData,
4340) -> CXChildVisitResult {
4341 let initializers = unsafe { &mut *(client_data as *mut Vec<Expression>) };
4342 let kind = unsafe { clang_getCursorKind(cursor) };
4343
4344 if kind == 119 {
4347 return CXChildVisit_Recurse;
4349 }
4350
4351 if let Some(expr) = try_extract_expression(cursor) {
4353 initializers.push(expr);
4354 return CXChildVisit_Continue;
4355 }
4356
4357 match kind {
4359 CXCursor_UnexposedExpr | CXCursor_ParenExpr => CXChildVisit_Recurse,
4360 _ => CXChildVisit_Continue,
4361 }
4362}
4363
4364#[allow(non_upper_case_globals)]
4365fn convert_type(cx_type: CXType) -> Option<Type> {
4366 match cx_type.kind {
4368 CXType_Void => Some(Type::Void),
4369 3 => Some(Type::Bool), CXType_Int => Some(Type::Int),
4371 CXType_UInt => Some(Type::UnsignedInt), CXType_UChar => Some(Type::Char), CXType_UShort => Some(Type::UnsignedInt), CXType_ULong => Some(Type::UnsignedInt), CXType_Short => Some(Type::Int), CXType_Long => Some(Type::Int), CXType_LongLong => Some(Type::Int), CXType_ULongLong => Some(Type::UnsignedInt), CXType_Float => Some(Type::Float),
4380 CXType_Double => Some(Type::Double),
4381 23 => Some(Type::Double), CXType_Char_S | CXType_Char_U => Some(Type::Char),
4383 14 => Some(Type::SignedChar), CXType_Pointer => {
4385 let pointee = unsafe { clang_getPointeeType(cx_type) };
4387
4388 if pointee.kind == CXType_FunctionProto || pointee.kind == CXType_FunctionNoProto {
4390 let return_cx_type = unsafe { clang_getResultType(pointee) };
4393 let return_type = convert_type(return_cx_type)?;
4394
4395 let num_args = unsafe { clang_getNumArgTypes(pointee) };
4397 let mut param_types = Vec::new();
4398
4399 for i in 0..num_args {
4400 let arg_type = unsafe { clang_getArgType(pointee, i as u32) };
4401 if let Some(param_type) = convert_type(arg_type) {
4402 param_types.push(param_type);
4403 }
4404 }
4405
4406 return Some(Type::FunctionPointer {
4407 param_types,
4408 return_type: Box::new(return_type),
4409 });
4410 }
4411
4412 convert_type(pointee).map(|t| Type::Pointer(Box::new(t)))
4414 }
4415 CXType_FunctionProto | CXType_FunctionNoProto => {
4416 let return_cx_type = unsafe { clang_getResultType(cx_type) };
4420 let return_type = convert_type(return_cx_type)?;
4421
4422 let num_args = unsafe { clang_getNumArgTypes(cx_type) };
4424 let mut param_types = Vec::new();
4425
4426 for i in 0..num_args {
4427 let arg_type = unsafe { clang_getArgType(cx_type, i as u32) };
4428 if let Some(param_type) = convert_type(arg_type) {
4429 param_types.push(param_type);
4430 }
4431 }
4432
4433 Some(Type::FunctionPointer {
4434 param_types,
4435 return_type: Box::new(return_type),
4436 })
4437 }
4438 CXType_Record => {
4439 let decl = unsafe { clang_getTypeDeclaration(cx_type) };
4441 let name_cxstring = unsafe { clang_getCursorSpelling(decl) };
4442 let name = unsafe {
4443 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
4444 let struct_name = c_str.to_string_lossy().into_owned();
4445 clang_disposeString(name_cxstring);
4446 struct_name
4447 };
4448 Some(Type::Struct(name))
4449 }
4450 CXType_Elaborated => {
4451 let canonical = unsafe { clang_getCanonicalType(cx_type) };
4454 convert_type(canonical)
4455 }
4456 CXType_Typedef => {
4457 let typedef_decl = unsafe { clang_getTypeDeclaration(cx_type) };
4459 let typedef_name_cxstring = unsafe { clang_getCursorSpelling(typedef_decl) };
4460 let typedef_name = unsafe {
4461 let c_str = CStr::from_ptr(clang_getCString(typedef_name_cxstring));
4462 let tn = c_str.to_string_lossy().into_owned();
4463 clang_disposeString(typedef_name_cxstring);
4464 tn
4465 };
4466
4467 match typedef_name.as_str() {
4470 "size_t" | "ssize_t" | "ptrdiff_t" => {
4471 return Some(Type::TypeAlias(typedef_name));
4472 }
4473 _ => {}
4474 }
4475
4476 let canonical = unsafe { clang_getCanonicalType(cx_type) };
4479
4480 if canonical.kind == CXType_Record {
4482 let decl = unsafe { clang_getTypeDeclaration(canonical) };
4483 let struct_name_cxstring = unsafe { clang_getCursorSpelling(decl) };
4484 let struct_name = unsafe {
4485 let c_str = CStr::from_ptr(clang_getCString(struct_name_cxstring));
4486 let sn = c_str.to_string_lossy().into_owned();
4487 clang_disposeString(struct_name_cxstring);
4488 sn
4489 };
4490
4491 if struct_name.is_empty() {
4493 return Some(Type::Struct(typedef_name));
4494 }
4495 }
4496
4497 convert_type(canonical)
4499 }
4500 CXType_ConstantArray => {
4501 let element_cx_type = unsafe { clang_getArrayElementType(cx_type) };
4503 let element_type = convert_type(element_cx_type)?;
4504
4505 let array_size = unsafe { clang_getArraySize(cx_type) };
4507 let size = if array_size >= 0 {
4508 Some(array_size)
4509 } else {
4510 None
4511 };
4512
4513 Some(Type::Array {
4514 element_type: Box::new(element_type),
4515 size,
4516 })
4517 }
4518 114 => {
4519 let element_cx_type = unsafe { clang_getArrayElementType(cx_type) };
4523 let element_type = convert_type(element_cx_type)?;
4524
4525 Some(Type::Array {
4527 element_type: Box::new(element_type),
4528 size: None,
4529 })
4530 }
4531 106 => {
4532 Some(Type::Int)
4535 }
4536 _ => None,
4537 }
4538}
4539
4540#[derive(Debug, Clone, PartialEq)]
4542pub struct SwitchCase {
4543 pub value: Option<Expression>,
4545 pub body: Vec<Statement>,
4547}
4548
4549#[derive(Debug, Clone, PartialEq)]
4551pub enum Statement {
4552 VariableDeclaration {
4554 name: String,
4556 var_type: Type,
4558 initializer: Option<Expression>,
4560 },
4561 Return(Option<Expression>),
4563 Assignment {
4565 target: String,
4567 value: Expression,
4569 },
4570 If {
4572 condition: Expression,
4574 then_block: Vec<Statement>,
4576 else_block: Option<Vec<Statement>>,
4578 },
4579 For {
4581 init: Vec<Statement>,
4583 condition: Option<Expression>,
4585 increment: Vec<Statement>,
4587 body: Vec<Statement>,
4589 },
4590 While {
4592 condition: Expression,
4594 body: Vec<Statement>,
4596 },
4597 DerefAssignment {
4599 target: Expression,
4601 value: Expression,
4603 },
4604 ArrayIndexAssignment {
4606 array: Box<Expression>,
4608 index: Box<Expression>,
4610 value: Expression,
4612 },
4613 FieldAssignment {
4615 object: Expression,
4617 field: String,
4619 value: Expression,
4621 },
4622 Break,
4624 Continue,
4626 Switch {
4628 condition: Expression,
4630 cases: Vec<SwitchCase>,
4632 default_case: Option<Vec<Statement>>,
4634 },
4635 PostIncrement {
4637 target: String,
4639 },
4640 PreIncrement {
4642 target: String,
4644 },
4645 PostDecrement {
4647 target: String,
4649 },
4650 PreDecrement {
4652 target: String,
4654 },
4655 CompoundAssignment {
4657 target: String,
4659 op: BinaryOperator,
4661 value: Expression,
4663 },
4664 DerefCompoundAssignment {
4667 target: Expression,
4669 op: BinaryOperator,
4671 value: Expression,
4673 },
4674 FunctionCall {
4676 function: String,
4678 arguments: Vec<Expression>,
4680 },
4681}
4682
4683impl Statement {
4684 pub fn is_string_function_call(&self) -> bool {
4686 match self {
4687 Statement::FunctionCall { function, .. } => {
4688 matches!(function.as_str(), "strlen" | "strcmp" | "strcpy" | "strdup")
4689 }
4690 _ => false,
4691 }
4692 }
4693
4694 pub fn is_function_call(&self) -> bool {
4696 matches!(self, Statement::FunctionCall { .. })
4697 }
4698
4699 pub fn as_function_call(&self) -> Option<&Expression> {
4708 None
4709 }
4710}
4711
4712#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4714pub enum UnaryOperator {
4715 Minus,
4717 LogicalNot,
4719 BitwiseNot,
4721 AddressOf,
4723}
4724
4725#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4727pub enum BinaryOperator {
4728 Add,
4730 Subtract,
4732 Multiply,
4734 Divide,
4736 Modulo,
4738 Equal,
4740 NotEqual,
4742 LessThan,
4744 GreaterThan,
4746 LessEqual,
4748 GreaterEqual,
4750 LogicalAnd,
4752 LogicalOr,
4754 LeftShift,
4756 RightShift,
4758 BitwiseAnd,
4760 BitwiseOr,
4762 BitwiseXor,
4764 Assign,
4766 Comma,
4768}
4769
4770#[derive(Debug, Clone, PartialEq)]
4772pub enum Expression {
4773 IntLiteral(i32),
4775 FloatLiteral(String),
4777 StringLiteral(String),
4779 CharLiteral(i8),
4781 Variable(String),
4783 BinaryOp {
4785 op: BinaryOperator,
4787 left: Box<Expression>,
4789 right: Box<Expression>,
4791 },
4792 FunctionCall {
4794 function: String,
4796 arguments: Vec<Expression>,
4798 },
4799 Dereference(Box<Expression>),
4801 UnaryOp {
4803 op: UnaryOperator,
4805 operand: Box<Expression>,
4807 },
4808 ArrayIndex {
4810 array: Box<Expression>,
4812 index: Box<Expression>,
4814 },
4815 FieldAccess {
4817 object: Box<Expression>,
4819 field: String,
4821 },
4822 PointerFieldAccess {
4824 pointer: Box<Expression>,
4826 field: String,
4828 },
4829 PostIncrement {
4831 operand: Box<Expression>,
4833 },
4834 PreIncrement {
4836 operand: Box<Expression>,
4838 },
4839 PostDecrement {
4841 operand: Box<Expression>,
4843 },
4844 PreDecrement {
4846 operand: Box<Expression>,
4848 },
4849 Sizeof {
4851 type_name: String,
4853 },
4854 Cast {
4867 target_type: Type,
4869 expr: Box<Expression>,
4871 },
4872 CompoundLiteral {
4885 literal_type: Type,
4887 initializers: Vec<Expression>,
4889 },
4890 Ternary {
4906 condition: Box<Expression>,
4908 then_expr: Box<Expression>,
4910 else_expr: Box<Expression>,
4912 },
4913}
4914
4915impl Expression {
4916 pub fn is_string_function_call(&self) -> bool {
4918 match self {
4919 Expression::FunctionCall { function, .. } => {
4920 matches!(function.as_str(), "strlen" | "strcmp" | "strcpy" | "strdup")
4921 }
4922 _ => false,
4923 }
4924 }
4925
4926 pub fn string_function_name(&self) -> Option<&str> {
4928 match self {
4929 Expression::FunctionCall { function, .. } if self.is_string_function_call() => {
4930 Some(function.as_str())
4931 }
4932 _ => None,
4933 }
4934 }
4935
4936 pub fn has_string_literal_argument(&self) -> bool {
4938 match self {
4939 Expression::FunctionCall { arguments, .. } => arguments
4940 .iter()
4941 .any(|arg| matches!(arg, Expression::StringLiteral(_))),
4942 _ => false,
4943 }
4944 }
4945}
4946
4947#[derive(Debug, Clone, PartialEq)]
4949pub struct Typedef {
4950 pub name: String,
4952 pub underlying_type: Type,
4954}
4955
4956impl Typedef {
4957 pub fn new(name: String, underlying_type: Type) -> Self {
4959 Self {
4960 name,
4961 underlying_type,
4962 }
4963 }
4964
4965 pub fn name(&self) -> &str {
4967 &self.name
4968 }
4969
4970 pub fn underlying_type(&self) -> &str {
4972 match &self.underlying_type {
4974 Type::Void => "void",
4975 Type::Bool => "_Bool",
4976 Type::Int => "int",
4977 Type::UnsignedInt => "unsigned int", Type::Float => "float",
4979 Type::Double => "double",
4980 Type::Char => "char",
4981 Type::SignedChar => "signed char", Type::Pointer(inner) => match **inner {
4983 Type::Char => "char*",
4984 Type::SignedChar => "signed char*", Type::Int => "int*",
4986 Type::UnsignedInt => "unsigned int*", Type::Float => "float*",
4988 Type::Double => "double*",
4989 Type::Void => "void*",
4990 _ => "pointer",
4991 },
4992 Type::Struct(name) => name,
4993 Type::FunctionPointer { .. } => "function pointer",
4994 Type::Array { .. } => "array",
4995 Type::TypeAlias(name) => name,
4997 }
4998 }
4999
5000 pub fn is_pointer(&self) -> bool {
5002 matches!(self.underlying_type, Type::Pointer(_))
5003 }
5004
5005 pub fn is_struct(&self) -> bool {
5007 matches!(self.underlying_type, Type::Struct(_))
5008 }
5009
5010 pub fn is_function_pointer(&self) -> bool {
5012 matches!(self.underlying_type, Type::FunctionPointer { .. })
5013 }
5014
5015 pub fn is_array(&self) -> bool {
5017 false
5019 }
5020}
5021
5022#[derive(Debug, Clone, PartialEq)]
5024pub struct StructField {
5025 pub name: String,
5027 pub field_type: Type,
5029}
5030
5031impl StructField {
5032 pub fn new(name: String, field_type: Type) -> Self {
5034 Self { name, field_type }
5035 }
5036
5037 pub fn name(&self) -> &str {
5039 &self.name
5040 }
5041
5042 pub fn is_function_pointer(&self) -> bool {
5044 matches!(self.field_type, Type::FunctionPointer { .. })
5045 }
5046}
5047
5048#[derive(Debug, Clone, PartialEq)]
5050pub struct Struct {
5051 pub name: String,
5053 pub fields: Vec<StructField>,
5055}
5056
5057impl Struct {
5058 pub fn new(name: String, fields: Vec<StructField>) -> Self {
5060 Self { name, fields }
5061 }
5062
5063 pub fn name(&self) -> &str {
5065 &self.name
5066 }
5067
5068 pub fn fields(&self) -> &[StructField] {
5070 &self.fields
5071 }
5072}
5073
5074#[derive(Debug, Clone, PartialEq)]
5076pub struct Variable {
5077 name: String,
5079 var_type: Type,
5081 initializer: Option<Expression>,
5083 is_static: bool,
5085 is_extern: bool,
5087 is_const: bool,
5089}
5090
5091impl Variable {
5092 pub fn new(name: String, var_type: Type) -> Self {
5094 Self {
5095 name,
5096 var_type,
5097 initializer: None,
5098 is_static: false,
5099 is_extern: false,
5100 is_const: false,
5101 }
5102 }
5103
5104 pub fn new_with_initializer(name: String, var_type: Type, initializer: Expression) -> Self {
5106 Self {
5107 name,
5108 var_type,
5109 initializer: Some(initializer),
5110 is_static: false,
5111 is_extern: false,
5112 is_const: false,
5113 }
5114 }
5115
5116 pub fn new_with_storage_class(
5118 name: String,
5119 var_type: Type,
5120 initializer: Option<Expression>,
5121 is_static: bool,
5122 is_extern: bool,
5123 is_const: bool,
5124 ) -> Self {
5125 Self {
5126 name,
5127 var_type,
5128 initializer,
5129 is_static,
5130 is_extern,
5131 is_const,
5132 }
5133 }
5134
5135 pub fn name(&self) -> &str {
5137 &self.name
5138 }
5139
5140 pub fn var_type(&self) -> &Type {
5142 &self.var_type
5143 }
5144
5145 pub fn is_function_pointer(&self) -> bool {
5147 matches!(self.var_type, Type::FunctionPointer { .. })
5148 }
5149
5150 pub fn function_pointer_param_count(&self) -> usize {
5152 match &self.var_type {
5153 Type::FunctionPointer { param_types, .. } => param_types.len(),
5154 _ => 0,
5155 }
5156 }
5157
5158 pub fn function_pointer_has_void_return(&self) -> bool {
5160 match &self.var_type {
5161 Type::FunctionPointer { return_type, .. } => matches!(**return_type, Type::Void),
5162 _ => false,
5163 }
5164 }
5165
5166 pub fn is_string_literal(&self) -> bool {
5178 let is_char_ptr =
5180 matches!(self.var_type, Type::Pointer(ref inner) if **inner == Type::Char);
5181
5182 if let Some(initializer) = &self.initializer {
5184 is_char_ptr && matches!(initializer, Expression::StringLiteral(_))
5185 } else {
5186 false
5187 }
5188 }
5189
5190 pub fn is_string_buffer(&self) -> bool {
5200 let is_char_ptr =
5202 matches!(self.var_type, Type::Pointer(ref inner) if **inner == Type::Char);
5203
5204 if let Some(Expression::FunctionCall { function, .. }) = &self.initializer {
5206 is_char_ptr && (function == "malloc" || function == "calloc")
5207 } else {
5208 false
5209 }
5210 }
5211
5212 pub fn initializer(&self) -> Option<&Expression> {
5216 self.initializer.as_ref()
5217 }
5218
5219 pub fn is_static(&self) -> bool {
5221 self.is_static
5222 }
5223
5224 pub fn is_extern(&self) -> bool {
5226 self.is_extern
5227 }
5228
5229 pub fn is_const(&self) -> bool {
5231 self.is_const
5232 }
5233}
5234
5235#[derive(Debug, Clone, PartialEq)]
5237pub struct EnumVariant {
5238 pub name: String,
5240 pub value: Option<i64>,
5242}
5243
5244impl EnumVariant {
5245 pub fn new(name: String, value: Option<i64>) -> Self {
5247 Self { name, value }
5248 }
5249}
5250
5251#[derive(Debug, Clone, PartialEq)]
5253pub struct Enum {
5254 pub name: String,
5256 pub variants: Vec<EnumVariant>,
5258}
5259
5260impl Enum {
5261 pub fn new(name: String, variants: Vec<EnumVariant>) -> Self {
5263 Self { name, variants }
5264 }
5265}
5266
5267#[derive(Debug, Clone, PartialEq)]
5269pub struct Ast {
5270 functions: Vec<Function>,
5271 typedefs: Vec<Typedef>,
5272 structs: Vec<Struct>,
5273 macros: Vec<MacroDefinition>,
5274 variables: Vec<Variable>,
5275 enums: Vec<Enum>,
5276}
5277
5278#[derive(Debug, Clone, PartialEq)]
5308pub struct MacroDefinition {
5309 pub name: String,
5311 pub parameters: Vec<String>,
5313 pub body: String,
5315}
5316
5317impl MacroDefinition {
5318 pub fn new_object_like(name: String, body: String) -> Self {
5320 Self {
5321 name,
5322 parameters: vec![],
5323 body,
5324 }
5325 }
5326
5327 pub fn new_function_like(name: String, parameters: Vec<String>, body: String) -> Self {
5329 Self {
5330 name,
5331 parameters,
5332 body,
5333 }
5334 }
5335
5336 pub fn name(&self) -> &str {
5338 &self.name
5339 }
5340
5341 pub fn parameters(&self) -> &[String] {
5343 &self.parameters
5344 }
5345
5346 pub fn body(&self) -> &str {
5348 &self.body
5349 }
5350
5351 pub fn is_function_like(&self) -> bool {
5353 !self.parameters.is_empty()
5354 }
5355
5356 pub fn is_object_like(&self) -> bool {
5358 self.parameters.is_empty()
5359 }
5360}
5361
5362impl Ast {
5363 pub fn new() -> Self {
5365 Self {
5366 functions: Vec::new(),
5367 typedefs: Vec::new(),
5368 structs: Vec::new(),
5369 macros: Vec::new(),
5370 variables: Vec::new(),
5371 enums: Vec::new(),
5372 }
5373 }
5374
5375 pub fn functions(&self) -> &[Function] {
5377 &self.functions
5378 }
5379
5380 pub fn add_function(&mut self, function: Function) {
5382 self.functions.push(function);
5383 }
5384
5385 pub fn typedefs(&self) -> &[Typedef] {
5387 &self.typedefs
5388 }
5389
5390 pub fn add_typedef(&mut self, typedef: Typedef) {
5392 self.typedefs.push(typedef);
5393 }
5394
5395 pub fn structs(&self) -> &[Struct] {
5397 &self.structs
5398 }
5399
5400 pub fn add_struct(&mut self, struct_def: Struct) {
5403 if !self.structs.iter().any(|s| s.name() == struct_def.name()) {
5405 self.structs.push(struct_def);
5406 }
5407 }
5408
5409 pub fn macros(&self) -> &[MacroDefinition] {
5411 &self.macros
5412 }
5413
5414 pub fn add_macro(&mut self, macro_def: MacroDefinition) {
5416 self.macros.push(macro_def);
5417 }
5418
5419 pub fn variables(&self) -> &[Variable] {
5421 &self.variables
5422 }
5423
5424 pub fn add_variable(&mut self, variable: Variable) {
5426 self.variables.push(variable);
5427 }
5428
5429 pub fn enums(&self) -> &[Enum] {
5431 &self.enums
5432 }
5433
5434 pub fn add_enum(&mut self, enum_def: Enum) {
5436 self.enums.push(enum_def);
5437 }
5438}
5439
5440impl Default for Ast {
5441 fn default() -> Self {
5442 Self::new()
5443 }
5444}
5445
5446#[derive(Debug, Clone, PartialEq)]
5448pub struct Function {
5449 pub name: String,
5451 pub return_type: Type,
5453 pub parameters: Vec<Parameter>,
5455 pub body: Vec<Statement>,
5457}
5458
5459impl Function {
5460 pub fn new(name: String, return_type: Type, parameters: Vec<Parameter>) -> Self {
5462 Self {
5463 name,
5464 return_type,
5465 parameters,
5466 body: Vec::new(),
5467 }
5468 }
5469
5470 pub fn new_with_body(
5472 name: String,
5473 return_type: Type,
5474 parameters: Vec<Parameter>,
5475 body: Vec<Statement>,
5476 ) -> Self {
5477 Self {
5478 name,
5479 return_type,
5480 parameters,
5481 body,
5482 }
5483 }
5484}
5485
5486#[derive(Debug, Clone, PartialEq)]
5488#[allow(clippy::enum_variant_names)] pub enum Type {
5490 Void,
5492 Bool,
5494 Int,
5496 UnsignedInt,
5498 Float,
5500 Double,
5502 Char,
5504 SignedChar,
5506 Pointer(Box<Type>),
5508 Struct(String),
5510 FunctionPointer {
5512 param_types: Vec<Type>,
5514 return_type: Box<Type>,
5516 },
5517 Array {
5520 element_type: Box<Type>,
5522 size: Option<i64>,
5524 },
5525 TypeAlias(String),
5528}
5529
5530#[derive(Debug, Clone, PartialEq)]
5532pub struct Parameter {
5533 pub name: String,
5535 pub param_type: Type,
5537 pub is_pointee_const: bool,
5540}
5541
5542impl Parameter {
5543 pub fn new(name: String, param_type: Type) -> Self {
5545 Self {
5546 name,
5547 param_type,
5548 is_pointee_const: false,
5549 }
5550 }
5551
5552 pub fn new_with_const(name: String, param_type: Type, is_pointee_const: bool) -> Self {
5555 Self {
5556 name,
5557 param_type,
5558 is_pointee_const,
5559 }
5560 }
5561
5562 pub fn is_function_pointer(&self) -> bool {
5564 matches!(self.param_type, Type::FunctionPointer { .. })
5565 }
5566
5567 pub fn is_const_char_pointer(&self) -> bool {
5572 self.is_pointee_const
5573 && matches!(self.param_type, Type::Pointer(ref inner) if matches!(**inner, Type::Char))
5574 }
5575
5576 pub fn is_char_pointer(&self) -> bool {
5578 matches!(self.param_type, Type::Pointer(ref inner) if matches!(**inner, Type::Char))
5579 }
5580}
5581
5582#[cfg(test)]
5583#[path = "parser_tests.rs"]
5584mod parser_tests;
5585
5586#[cfg(test)]
5587#[path = "pointer_arithmetic_tests.rs"]
5588mod pointer_arithmetic_tests;
5589
5590#[cfg(test)]
5591#[path = "break_continue_tests.rs"]
5592mod break_continue_tests;