1use anyhow::{Context, Result};
7use clang_sys::*;
8use std::ffi::{CStr, CString};
9use std::path::Path;
10use std::ptr;
11
12#[derive(Debug)]
25pub struct CParser {
26 index: CXIndex,
27}
28
29impl CParser {
30 pub fn new() -> Result<Self> {
41 let index = unsafe { clang_createIndex(0, 0) };
43 if index.is_null() {
44 anyhow::bail!("Failed to create clang index");
45 }
46 Ok(Self { index })
47 }
48
49 pub fn parse(&self, source: &str) -> Result<Ast> {
70 let filename = CString::new("input.c").context("Failed to create filename")?;
71 let source_cstr = CString::new(source).context("Failed to convert source to CString")?;
72
73 let mut ast = Ast::new();
74
75 if source.trim().is_empty() {
77 return Ok(ast);
78 }
79
80 let unsaved_file = CXUnsavedFile {
82 Filename: filename.as_ptr(),
83 Contents: source_cstr.as_ptr(),
84 Length: source.len() as std::os::raw::c_ulong,
85 };
86
87 let has_extern_c = source.contains("extern \"C\"");
91 let has_ifdef_guard =
92 source.contains("#ifdef __cplusplus") || source.contains("#if defined(__cplusplus)");
93 let needs_cpp_mode = has_extern_c && !has_ifdef_guard;
94
95 let cpp_flag = CString::new("-x").unwrap();
97 let cpp_lang = CString::new("c++").unwrap();
98 let args_vec: Vec<*const std::os::raw::c_char> = if needs_cpp_mode {
99 vec![cpp_flag.as_ptr(), cpp_lang.as_ptr()]
100 } else {
101 vec![]
102 };
103
104 let flags = 1;
108
109 let mut tu = ptr::null_mut();
110 let result = unsafe {
111 clang_parseTranslationUnit2(
112 self.index,
113 filename.as_ptr(),
114 if args_vec.is_empty() {
115 ptr::null()
116 } else {
117 args_vec.as_ptr()
118 },
119 args_vec.len() as std::os::raw::c_int,
120 &unsaved_file as *const CXUnsavedFile as *mut CXUnsavedFile,
121 1,
122 flags,
123 &mut tu,
124 )
125 };
126
127 if result != CXError_Success || tu.is_null() {
128 anyhow::bail!("Failed to parse C source");
129 }
130
131 let num_diagnostics = unsafe { clang_getNumDiagnostics(tu) };
133 for i in 0..num_diagnostics {
134 let diag = unsafe { clang_getDiagnostic(tu, i) };
135 let severity = unsafe { clang_getDiagnosticSeverity(diag) };
136
137 if severity >= CXDiagnostic_Error {
139 unsafe { clang_disposeDiagnostic(diag) };
140 unsafe { clang_disposeTranslationUnit(tu) };
141 anyhow::bail!("C source has syntax errors");
142 }
143
144 unsafe { clang_disposeDiagnostic(diag) };
145 }
146
147 let cursor = unsafe { clang_getTranslationUnitCursor(tu) };
149
150 let ast_ptr = &mut ast as *mut Ast;
152
153 unsafe {
155 clang_visitChildren(cursor, visit_function, ast_ptr as CXClientData);
156
157 clang_disposeTranslationUnit(tu);
159 }
160
161 Ok(ast)
162 }
163
164 pub fn parse_file(&self, _path: &Path) -> Result<Ast> {
175 Err(anyhow::anyhow!("Not implemented yet"))
177 }
178}
179
180impl Drop for CParser {
181 fn drop(&mut self) {
182 unsafe {
184 clang_disposeIndex(self.index);
185 }
186 }
187}
188
189extern "C" fn visit_function(
195 cursor: CXCursor,
196 _parent: CXCursor,
197 client_data: CXClientData,
198) -> CXChildVisitResult {
199 let ast = unsafe { &mut *(client_data as *mut Ast) };
201
202 let kind = unsafe { clang_getCursorKind(cursor) };
204
205 if kind == 23 {
208 unsafe {
211 clang_visitChildren(cursor, visit_function, client_data);
212 }
213 return CXChildVisit_Continue;
214 }
215
216 if kind == CXCursor_FunctionDecl {
217 if let Some(function) = extract_function(cursor) {
219 ast.add_function(function);
220 }
221 } else if kind == CXCursor_TypedefDecl {
222 if let Some(typedef) = extract_typedef(cursor) {
224 ast.add_typedef(typedef);
225 }
226 } else if kind == CXCursor_StructDecl {
227 if let Some(struct_def) = extract_struct(cursor) {
229 ast.add_struct(struct_def);
230 }
231 } else if kind == CXCursor_VarDecl {
232 let semantic_parent = unsafe { clang_getCursorSemanticParent(cursor) };
235 let parent_kind = unsafe { clang_getCursorKind(semantic_parent) };
236
237 let is_file_scope = parent_kind != CXCursor_FunctionDecl;
241
242 if is_file_scope {
243 if let Some(variable) = extract_variable(cursor) {
244 ast.add_variable(variable);
245 }
246 }
247 } else if kind == CXCursor_MacroDefinition {
249 let location = unsafe { clang_getCursorLocation(cursor) };
251 let mut file: CXFile = ptr::null_mut();
252 unsafe {
253 clang_getFileLocation(
254 location,
255 &mut file,
256 ptr::null_mut(),
257 ptr::null_mut(),
258 ptr::null_mut(),
259 );
260 }
261
262 if !file.is_null() {
264 let file_name = unsafe {
265 let name_cxstring = clang_getFileName(file);
266 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
267 let name = c_str.to_string_lossy().into_owned();
268 clang_disposeString(name_cxstring);
269 name
270 };
271
272 if file_name.ends_with("input.c") {
274 if let Some(macro_def) = extract_macro(cursor) {
275 ast.add_macro(macro_def);
276 }
277 }
278 }
279 }
280
281 CXChildVisit_Recurse
284}
285
286fn extract_function(cursor: CXCursor) -> Option<Function> {
288 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
290 let name = unsafe {
291 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
292 let name = c_str.to_string_lossy().into_owned();
293 clang_disposeString(name_cxstring);
294 name
295 };
296
297 let cx_type = unsafe { clang_getCursorType(cursor) };
299 let return_cx_type = unsafe { clang_getResultType(cx_type) };
300 let return_type = convert_type(return_cx_type)?;
301
302 let num_args = unsafe { clang_Cursor_getNumArguments(cursor) };
304 let mut parameters = Vec::new();
305
306 for i in 0..num_args {
307 let arg_cursor = unsafe { clang_Cursor_getArgument(cursor, i as u32) };
309
310 let param_name_cxstring = unsafe { clang_getCursorSpelling(arg_cursor) };
312 let param_name = unsafe {
313 let c_str = CStr::from_ptr(clang_getCString(param_name_cxstring));
314 let name = c_str.to_string_lossy().into_owned();
315 clang_disposeString(param_name_cxstring);
316 name
317 };
318
319 let param_cx_type = unsafe { clang_getCursorType(arg_cursor) };
321 if let Some(param_type) = convert_type(param_cx_type) {
322 parameters.push(Parameter::new(param_name, param_type));
323 }
324 }
325
326 let mut body = Vec::new();
328 let body_ptr = &mut body as *mut Vec<Statement>;
329
330 unsafe {
331 clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
332 }
333
334 Some(Function::new_with_body(name, return_type, parameters, body))
335}
336
337fn extract_typedef(cursor: CXCursor) -> Option<Typedef> {
339 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
341 let name = unsafe {
342 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
343 let name = c_str.to_string_lossy().into_owned();
344 clang_disposeString(name_cxstring);
345 name
346 };
347
348 let cx_type = unsafe { clang_getTypedefDeclUnderlyingType(cursor) };
350 let underlying_type = convert_type(cx_type)?;
351
352 Some(Typedef::new(name, underlying_type))
353}
354
355fn extract_struct(cursor: CXCursor) -> Option<Struct> {
357 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
359 let name = unsafe {
360 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
361 let name = c_str.to_string_lossy().into_owned();
362 clang_disposeString(name_cxstring);
363 name
364 };
365
366 if name.is_empty() {
368 return None;
369 }
370
371 let mut fields = Vec::new();
373 let fields_ptr = &mut fields as *mut Vec<StructField>;
374
375 unsafe {
376 clang_visitChildren(cursor, visit_struct_fields, fields_ptr as CXClientData);
377 }
378
379 Some(Struct::new(name, fields))
380}
381
382fn extract_variable(cursor: CXCursor) -> Option<Variable> {
393 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
395 let name = unsafe {
396 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
397 let name = c_str.to_string_lossy().into_owned();
398 clang_disposeString(name_cxstring);
399 name
400 };
401
402 let cx_type = unsafe { clang_getCursorType(cursor) };
404 let var_type = convert_type(cx_type)?;
405
406 let storage_class = unsafe { clang_Cursor_getStorageClass(cursor) };
412 let is_static = storage_class == 3; let is_extern = storage_class == 2; let is_const = unsafe { clang_isConstQualifiedType(cx_type) != 0 };
417
418 let mut initializer: Option<Expression> = None;
420 let initializer_ptr = &mut initializer as *mut Option<Expression>;
421
422 unsafe {
423 clang_visitChildren(
424 cursor,
425 visit_variable_initializer,
426 initializer_ptr as CXClientData,
427 );
428 }
429
430 Some(Variable::new_with_storage_class(
431 name,
432 var_type,
433 initializer,
434 is_static,
435 is_extern,
436 is_const,
437 ))
438}
439
440#[allow(non_upper_case_globals)]
443fn try_extract_expression(cursor: CXCursor) -> Option<Expression> {
444 let kind = unsafe { clang_getCursorKind(cursor) };
445
446 match kind {
447 CXCursor_IntegerLiteral => extract_int_literal(cursor),
448 CXCursor_StringLiteral => extract_string_literal(cursor),
449 CXCursor_DeclRefExpr => extract_variable_ref(cursor),
450 CXCursor_BinaryOperator => extract_binary_op(cursor),
451 CXCursor_CallExpr => extract_function_call(cursor),
452 CXCursor_UnaryOperator => extract_unary_op(cursor),
453 CXCursor_ArraySubscriptExpr => extract_array_index(cursor),
454 CXCursor_MemberRefExpr => extract_field_access(cursor),
455 117 => extract_cast(cursor), 118 => extract_compound_literal(cursor), CXCursor_UnexposedExpr => {
458 let mut result: Option<Expression> = None;
460 let result_ptr = &mut result as *mut Option<Expression>;
461 unsafe {
462 clang_visitChildren(
463 cursor,
464 visit_variable_initializer,
465 result_ptr as CXClientData,
466 );
467 }
468 result
469 }
470 _ => None,
471 }
472}
473
474#[allow(non_upper_case_globals)]
476extern "C" fn visit_variable_initializer(
477 cursor: CXCursor,
478 _parent: CXCursor,
479 client_data: CXClientData,
480) -> CXChildVisitResult {
481 let initializer = unsafe { &mut *(client_data as *mut Option<Expression>) };
482
483 if let Some(expr) = try_extract_expression(cursor) {
485 *initializer = Some(expr);
486 return CXChildVisit_Break;
487 }
488
489 CXChildVisit_Continue
490}
491
492fn extract_macro(cursor: CXCursor) -> Option<MacroDefinition> {
499 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
501 let name = unsafe {
502 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
503 let name = c_str.to_string_lossy().into_owned();
504 clang_disposeString(name_cxstring);
505 name
506 };
507
508 if name.is_empty() {
510 return None;
511 }
512
513 let is_function_like = unsafe { clang_sys::clang_Cursor_isMacroFunctionLike(cursor) } != 0;
516
517 let range = unsafe { clang_getCursorExtent(cursor) };
519 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
520
521 let mut tokens: *mut CXToken = ptr::null_mut();
522 let mut num_tokens: u32 = 0;
523
524 unsafe {
525 clang_tokenize(tu, range, &mut tokens, &mut num_tokens);
526 }
527
528 let mut parameters = Vec::new();
531 let mut body_tokens = Vec::new();
532 let mut in_params = false;
533
534 for i in 0..num_tokens {
535 let token = unsafe { *tokens.offset(i as isize) };
536 let token_kind = unsafe { clang_getTokenKind(token) };
537 let token_spelling = unsafe { clang_getTokenSpelling(tu, token) };
538 let token_str = unsafe {
539 let c_str = CStr::from_ptr(clang_getCString(token_spelling));
540 let s = c_str.to_string_lossy().into_owned();
541 clang_disposeString(token_spelling);
542 s
543 };
544
545 if i == 0 {
547 continue;
548 }
549
550 if is_function_like && i == 1 && token_str == "(" {
552 in_params = true;
553 continue;
554 }
555
556 if in_params {
557 if token_str == ")" {
558 in_params = false;
559 continue;
560 } else if token_str != ","
561 && (token_kind == CXToken_Identifier || token_kind == CXToken_Keyword)
562 {
563 parameters.push(token_str);
566 }
567 } else {
568 body_tokens.push(token_str);
569 }
570 }
571
572 unsafe {
574 clang_disposeTokens(tu, tokens, num_tokens);
575 }
576
577 let body = body_tokens.join("");
579
580 if is_function_like {
581 Some(MacroDefinition::new_function_like(name, parameters, body))
582 } else {
583 Some(MacroDefinition::new_object_like(name, body))
584 }
585}
586
587#[allow(non_upper_case_globals)]
593extern "C" fn visit_struct_fields(
594 cursor: CXCursor,
595 _parent: CXCursor,
596 client_data: CXClientData,
597) -> CXChildVisitResult {
598 let fields = unsafe { &mut *(client_data as *mut Vec<StructField>) };
600
601 let kind = unsafe { clang_getCursorKind(cursor) };
603
604 if kind == CXCursor_FieldDecl {
605 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
607 let name = unsafe {
608 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
609 let name = c_str.to_string_lossy().into_owned();
610 clang_disposeString(name_cxstring);
611 name
612 };
613
614 let cx_type = unsafe { clang_getCursorType(cursor) };
616 if let Some(field_type) = convert_type(cx_type) {
617 fields.push(StructField::new(name, field_type));
618 }
619 }
620
621 CXChildVisit_Continue
622}
623
624#[allow(non_upper_case_globals)]
630extern "C" fn visit_statement(
631 cursor: CXCursor,
632 _parent: CXCursor,
633 client_data: CXClientData,
634) -> CXChildVisitResult {
635 let statements = unsafe { &mut *(client_data as *mut Vec<Statement>) };
637
638 let kind = unsafe { clang_getCursorKind(cursor) };
640
641 match kind {
642 CXCursor_CompoundStmt => {
643 CXChildVisit_Recurse
645 }
646 CXCursor_DeclStmt => {
647 CXChildVisit_Recurse
649 }
650 CXCursor_VarDecl => {
651 if let Some(stmt) = extract_var_decl(cursor) {
653 statements.push(stmt);
654 }
655 CXChildVisit_Continue
656 }
657 CXCursor_ReturnStmt => {
658 if let Some(stmt) = extract_return_stmt(cursor) {
660 statements.push(stmt);
661 }
662 CXChildVisit_Continue
663 }
664 CXCursor_BinaryOperator => {
665 if let Some(stmt) = extract_assignment_stmt(cursor) {
667 statements.push(stmt);
668 }
669 CXChildVisit_Continue
670 }
671 CXCursor_IfStmt => {
672 if let Some(stmt) = extract_if_stmt(cursor) {
674 statements.push(stmt);
675 }
676 CXChildVisit_Continue
677 }
678 CXCursor_ForStmt => {
679 if let Some(stmt) = extract_for_stmt(cursor) {
681 statements.push(stmt);
682 }
683 CXChildVisit_Continue
684 }
685 CXCursor_WhileStmt => {
686 if let Some(stmt) = extract_while_stmt(cursor) {
688 statements.push(stmt);
689 }
690 CXChildVisit_Continue
691 }
692 CXCursor_SwitchStmt => {
693 if let Some(stmt) = extract_switch_stmt(cursor) {
695 statements.push(stmt);
696 }
697 CXChildVisit_Continue
698 }
699 CXCursor_BreakStmt => {
700 statements.push(Statement::Break);
702 CXChildVisit_Continue
703 }
704 CXCursor_ContinueStmt => {
705 statements.push(Statement::Continue);
707 CXChildVisit_Continue
708 }
709 CXCursor_UnaryOperator => {
710 if let Some(stmt) = extract_inc_dec_stmt(cursor) {
712 statements.push(stmt);
713 }
714 CXChildVisit_Continue
715 }
716 CXCursor_CompoundAssignOperator => {
717 if let Some(stmt) = extract_compound_assignment_stmt(cursor) {
719 statements.push(stmt);
720 }
721 CXChildVisit_Continue
722 }
723 CXCursor_CallExpr => {
724 if let Some(stmt) = extract_statement(cursor) {
727 statements.push(stmt);
728 }
729 CXChildVisit_Continue
730 }
731 _ => CXChildVisit_Recurse, }
733}
734
735fn extract_var_decl(cursor: CXCursor) -> Option<Statement> {
737 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
739 let name = unsafe {
740 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
741 let name = c_str.to_string_lossy().into_owned();
742 clang_disposeString(name_cxstring);
743 name
744 };
745
746 let cx_type = unsafe { clang_getCursorType(cursor) };
748 let var_type = convert_type(cx_type)?;
749
750 let mut initializer: Option<Expression> = None;
752 let init_ptr = &mut initializer as *mut Option<Expression>;
753
754 unsafe {
755 clang_visitChildren(cursor, visit_expression, init_ptr as CXClientData);
756 }
757
758 Some(Statement::VariableDeclaration {
759 name,
760 var_type,
761 initializer,
762 })
763}
764
765fn extract_return_stmt(cursor: CXCursor) -> Option<Statement> {
767 let mut return_expr: Option<Expression> = None;
769 let expr_ptr = &mut return_expr as *mut Option<Expression>;
770
771 unsafe {
772 clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
773 }
774
775 Some(Statement::Return(return_expr))
776}
777
778fn extract_assignment_stmt(cursor: CXCursor) -> Option<Statement> {
780 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
783 if tu.is_null() {
784 return None;
785 }
786
787 let extent = unsafe { clang_getCursorExtent(cursor) };
789
790 let mut tokens = ptr::null_mut();
792 let mut num_tokens = 0;
793
794 unsafe {
795 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
796 }
797
798 let mut is_assignment = false;
799
800 for i in 0..num_tokens {
802 unsafe {
803 let token = *tokens.add(i as usize);
804 let token_kind = clang_getTokenKind(token);
805
806 if token_kind == CXToken_Punctuation {
807 let token_cxstring = clang_getTokenSpelling(tu, token);
808 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
809 if let Ok(token_str) = c_str.to_str() {
810 if token_str == "=" {
812 is_assignment = true;
813 clang_disposeString(token_cxstring);
814 break;
815 } else if token_str == "=="
816 || token_str == "!="
817 || token_str == "<="
818 || token_str == ">="
819 {
820 clang_disposeString(token_cxstring);
822 break;
823 }
824 }
825 clang_disposeString(token_cxstring);
826 }
827 }
828 }
829
830 unsafe {
831 clang_disposeTokens(tu, tokens, num_tokens);
832 }
833
834 if !is_assignment {
835 return None;
836 }
837
838 let mut operands: Vec<Expression> = Vec::new();
840 let operands_ptr = &mut operands as *mut Vec<Expression>;
841
842 unsafe {
843 clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
844 }
845
846 if operands.len() != 2 {
848 return None;
849 }
850
851 if let Expression::Dereference(inner) = &operands[0] {
853 return Some(Statement::DerefAssignment {
854 target: (**inner).clone(), value: operands[1].clone(),
856 });
857 }
858
859 if let Expression::ArrayIndex { array, index } = &operands[0] {
861 return Some(Statement::ArrayIndexAssignment {
862 array: array.clone(),
863 index: index.clone(),
864 value: operands[1].clone(),
865 });
866 }
867
868 if matches!(
870 &operands[0],
871 Expression::PointerFieldAccess { .. } | Expression::FieldAccess { .. }
872 ) {
873 let field = match &operands[0] {
875 Expression::PointerFieldAccess { field, .. } => field.clone(),
876 Expression::FieldAccess { field, .. } => field.clone(),
877 _ => unreachable!(),
878 };
879
880 let object = match &operands[0] {
882 Expression::PointerFieldAccess { pointer, .. } => (**pointer).clone(),
883 Expression::FieldAccess { object, .. } => (**object).clone(),
884 _ => unreachable!(),
885 };
886
887 return Some(Statement::FieldAssignment {
888 object,
889 field,
890 value: operands[1].clone(),
891 });
892 }
893
894 let target = match &operands[0] {
896 Expression::Variable(name) => name.clone(),
897 _ => return None, };
899
900 Some(Statement::Assignment {
901 target,
902 value: operands[1].clone(),
903 })
904}
905
906fn extract_inc_dec_stmt(cursor: CXCursor) -> Option<Statement> {
908 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
910 if tu.is_null() {
911 return None;
912 }
913
914 let extent = unsafe { clang_getCursorExtent(cursor) };
916
917 let mut tokens = ptr::null_mut();
919 let mut num_tokens = 0;
920
921 unsafe {
922 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
923 }
924
925 let mut operator: Option<String> = None;
926 let mut operator_position = 0;
927
928 for i in 0..num_tokens {
930 unsafe {
931 let token = *tokens.add(i as usize);
932 let token_kind = clang_getTokenKind(token);
933
934 if token_kind == CXToken_Punctuation {
935 let token_cxstring = clang_getTokenSpelling(tu, token);
936 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
937 if let Ok(token_str) = c_str.to_str() {
938 if token_str == "++" || token_str == "--" {
939 operator = Some(token_str.to_string()); operator_position = i;
941 clang_disposeString(token_cxstring);
942 break;
943 }
944 }
945 clang_disposeString(token_cxstring);
946 }
947 }
948 }
949
950 let is_pre = operator_position == 0;
954
955 unsafe {
956 clang_disposeTokens(tu, tokens, num_tokens);
957 }
958
959 let mut target_name: Option<String> = None;
961
962 extern "C" fn visit_for_target(
964 cursor: CXCursor,
965 _parent: CXCursor,
966 client_data: CXClientData,
967 ) -> CXChildVisitResult {
968 let target = unsafe { &mut *(client_data as *mut Option<String>) };
969 let kind = unsafe { clang_getCursorKind(cursor) };
970
971 if kind == CXCursor_DeclRefExpr {
972 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
973 let name = unsafe {
974 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
975 let var_name = c_str.to_string_lossy().into_owned();
976 clang_disposeString(name_cxstring);
977 var_name
978 };
979 *target = Some(name);
980 CXChildVisit_Break
981 } else {
982 CXChildVisit_Recurse
983 }
984 }
985
986 let target_ptr = &mut target_name as *mut Option<String>;
987 unsafe {
988 clang_visitChildren(cursor, visit_for_target, target_ptr as CXClientData);
989 }
990
991 let target = target_name?;
992
993 match operator?.as_str() {
994 "++" => {
995 if is_pre {
996 Some(Statement::PreIncrement { target })
997 } else {
998 Some(Statement::PostIncrement { target })
999 }
1000 }
1001 "--" => {
1002 if is_pre {
1003 Some(Statement::PreDecrement { target })
1004 } else {
1005 Some(Statement::PostDecrement { target })
1006 }
1007 }
1008 _ => None,
1009 }
1010}
1011
1012fn extract_compound_assignment_stmt(cursor: CXCursor) -> Option<Statement> {
1014 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1016 if tu.is_null() {
1017 return None;
1018 }
1019
1020 let extent = unsafe { clang_getCursorExtent(cursor) };
1022
1023 let mut tokens = ptr::null_mut();
1025 let mut num_tokens = 0;
1026
1027 unsafe {
1028 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1029 }
1030
1031 let mut operator: Option<BinaryOperator> = None;
1032
1033 for i in 0..num_tokens {
1035 unsafe {
1036 let token = *tokens.add(i as usize);
1037 let token_kind = clang_getTokenKind(token);
1038
1039 if token_kind == CXToken_Punctuation {
1040 let token_cxstring = clang_getTokenSpelling(tu, token);
1041 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1042 if let Ok(token_str) = c_str.to_str() {
1043 operator = match token_str {
1044 "+=" => Some(BinaryOperator::Add),
1045 "-=" => Some(BinaryOperator::Subtract),
1046 "*=" => Some(BinaryOperator::Multiply),
1047 "/=" => Some(BinaryOperator::Divide),
1048 "%=" => Some(BinaryOperator::Modulo),
1049 _ => None,
1050 };
1051 if operator.is_some() {
1052 clang_disposeString(token_cxstring);
1053 break;
1054 }
1055 }
1056 clang_disposeString(token_cxstring);
1057 }
1058 }
1059 }
1060
1061 unsafe {
1062 clang_disposeTokens(tu, tokens, num_tokens);
1063 }
1064
1065 let op = operator?;
1066
1067 let mut operands: Vec<Expression> = Vec::new();
1069 let operands_ptr = &mut operands as *mut Vec<Expression>;
1070
1071 unsafe {
1072 clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
1073 }
1074
1075 if operands.len() != 2 {
1077 return None;
1078 }
1079
1080 let target = match &operands[0] {
1082 Expression::Variable(name) => name.clone(),
1083 _ => return None,
1084 };
1085
1086 Some(Statement::CompoundAssignment {
1087 target,
1088 op,
1089 value: operands[1].clone(),
1090 })
1091}
1092
1093fn extract_if_stmt(cursor: CXCursor) -> Option<Statement> {
1095 #[repr(C)]
1101 struct IfData {
1102 condition: Option<Expression>,
1103 then_block: Vec<Statement>,
1104 else_block: Option<Vec<Statement>>,
1105 child_index: u32,
1106 }
1107
1108 let mut if_data = IfData {
1109 condition: None,
1110 then_block: Vec::new(),
1111 else_block: None,
1112 child_index: 0,
1113 };
1114
1115 let data_ptr = &mut if_data as *mut IfData;
1116
1117 unsafe {
1118 clang_visitChildren(cursor, visit_if_children, data_ptr as CXClientData);
1119 }
1120
1121 Some(Statement::If {
1122 condition: if_data.condition?,
1123 then_block: if_data.then_block,
1124 else_block: if_data.else_block,
1125 })
1126}
1127
1128#[allow(non_upper_case_globals)]
1130extern "C" fn visit_if_children(
1131 cursor: CXCursor,
1132 _parent: CXCursor,
1133 client_data: CXClientData,
1134) -> CXChildVisitResult {
1135 #[repr(C)]
1136 struct IfData {
1137 condition: Option<Expression>,
1138 then_block: Vec<Statement>,
1139 else_block: Option<Vec<Statement>>,
1140 child_index: u32,
1141 }
1142
1143 let if_data = unsafe { &mut *(client_data as *mut IfData) };
1144 let kind = unsafe { clang_getCursorKind(cursor) };
1145
1146 match if_data.child_index {
1147 0 => {
1148 if_data.condition = match kind {
1151 CXCursor_BinaryOperator => extract_binary_op(cursor),
1152 CXCursor_IntegerLiteral => extract_int_literal(cursor),
1153 CXCursor_DeclRefExpr => extract_variable_ref(cursor),
1154 CXCursor_CallExpr => extract_function_call(cursor),
1155 CXCursor_UnaryOperator => extract_unary_op(cursor),
1156 _ => {
1157 let mut cond_expr: Option<Expression> = None;
1159 let expr_ptr = &mut cond_expr as *mut Option<Expression>;
1160 unsafe {
1161 clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1162 }
1163 cond_expr
1164 }
1165 };
1166 if_data.child_index += 1;
1167 CXChildVisit_Continue
1168 }
1169 1 => {
1170 if kind == CXCursor_CompoundStmt {
1172 let body_ptr = &mut if_data.then_block as *mut Vec<Statement>;
1173 unsafe {
1174 clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1175 }
1176 }
1177 if_data.child_index += 1;
1178 CXChildVisit_Continue
1179 }
1180 2 => {
1181 if kind == CXCursor_CompoundStmt || kind == CXCursor_IfStmt {
1183 let mut else_stmts = Vec::new();
1184 let body_ptr = &mut else_stmts as *mut Vec<Statement>;
1185 unsafe {
1186 clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1187 }
1188 if_data.else_block = Some(else_stmts);
1189 }
1190 if_data.child_index += 1;
1191 CXChildVisit_Continue
1192 }
1193 _ => CXChildVisit_Continue,
1194 }
1195}
1196
1197fn extract_for_stmt(cursor: CXCursor) -> Option<Statement> {
1199 #[repr(C)]
1206 struct ForData {
1207 init: Option<Box<Statement>>,
1208 condition: Option<Expression>,
1209 increment: Option<Box<Statement>>,
1210 body: Vec<Statement>,
1211 child_index: u32,
1212 }
1213
1214 let mut for_data = ForData {
1215 init: None,
1216 condition: None,
1217 increment: None,
1218 body: Vec::new(),
1219 child_index: 0,
1220 };
1221
1222 let data_ptr = &mut for_data as *mut ForData;
1223
1224 unsafe {
1225 clang_visitChildren(cursor, visit_for_children, data_ptr as CXClientData);
1226 }
1227
1228 Some(Statement::For {
1229 init: for_data.init,
1230 condition: for_data.condition,
1231 increment: for_data.increment,
1232 body: for_data.body,
1233 })
1234}
1235
1236#[allow(non_upper_case_globals)]
1238extern "C" fn visit_for_children(
1239 cursor: CXCursor,
1240 _parent: CXCursor,
1241 client_data: CXClientData,
1242) -> CXChildVisitResult {
1243 #[repr(C)]
1244 struct ForData {
1245 init: Option<Box<Statement>>,
1246 condition: Option<Expression>,
1247 increment: Option<Box<Statement>>,
1248 body: Vec<Statement>,
1249 child_index: u32,
1250 }
1251
1252 let for_data = unsafe { &mut *(client_data as *mut ForData) };
1253 let kind = unsafe { clang_getCursorKind(cursor) };
1254
1255 match for_data.child_index {
1256 0 => {
1257 if kind == CXCursor_DeclStmt {
1259 let mut init_stmts = Vec::new();
1261 let ptr = &mut init_stmts as *mut Vec<Statement>;
1262 unsafe {
1263 clang_visitChildren(cursor, visit_statement, ptr as CXClientData);
1264 }
1265 if let Some(stmt) = init_stmts.into_iter().next() {
1266 for_data.init = Some(Box::new(stmt));
1267 }
1268 } else if kind == CXCursor_BinaryOperator {
1269 if let Some(stmt) = extract_assignment_stmt(cursor) {
1271 for_data.init = Some(Box::new(stmt));
1272 }
1273 }
1274 for_data.child_index += 1;
1275 CXChildVisit_Continue
1276 }
1277 1 => {
1278 for_data.condition = match kind {
1281 CXCursor_BinaryOperator => extract_binary_op(cursor),
1282 CXCursor_IntegerLiteral => extract_int_literal(cursor),
1283 CXCursor_DeclRefExpr => extract_variable_ref(cursor),
1284 CXCursor_CallExpr => extract_function_call(cursor),
1285 CXCursor_UnaryOperator => extract_unary_op(cursor),
1286 _ => {
1287 let mut cond_expr: Option<Expression> = None;
1288 let expr_ptr = &mut cond_expr as *mut Option<Expression>;
1289 unsafe {
1290 clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1291 }
1292 cond_expr
1293 }
1294 };
1295 for_data.child_index += 1;
1296 CXChildVisit_Continue
1297 }
1298 2 => {
1299 if kind == CXCursor_BinaryOperator {
1301 if let Some(stmt) = extract_assignment_stmt(cursor) {
1302 for_data.increment = Some(Box::new(stmt));
1303 }
1304 } else if kind == CXCursor_UnaryOperator {
1305 if let Some(stmt) = extract_inc_dec_stmt(cursor) {
1307 for_data.increment = Some(Box::new(stmt));
1308 }
1309 }
1310 for_data.child_index += 1;
1311 CXChildVisit_Continue
1312 }
1313 3 => {
1314 if kind == CXCursor_CompoundStmt {
1316 let body_ptr = &mut for_data.body as *mut Vec<Statement>;
1317 unsafe {
1318 clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1319 }
1320 }
1321 for_data.child_index += 1;
1322 CXChildVisit_Continue
1323 }
1324 _ => CXChildVisit_Continue,
1325 }
1326}
1327
1328fn extract_while_stmt(cursor: CXCursor) -> Option<Statement> {
1330 #[repr(C)]
1335 struct WhileData {
1336 condition: Option<Expression>,
1337 body: Vec<Statement>,
1338 child_index: u32,
1339 }
1340
1341 let mut while_data = WhileData {
1342 condition: None,
1343 body: Vec::new(),
1344 child_index: 0,
1345 };
1346
1347 let data_ptr = &mut while_data as *mut WhileData;
1348
1349 unsafe {
1350 clang_visitChildren(cursor, visit_while_children, data_ptr as CXClientData);
1351 }
1352
1353 Some(Statement::While {
1354 condition: while_data.condition?,
1355 body: while_data.body,
1356 })
1357}
1358
1359#[allow(non_upper_case_globals)]
1361extern "C" fn visit_while_children(
1362 cursor: CXCursor,
1363 _parent: CXCursor,
1364 client_data: CXClientData,
1365) -> CXChildVisitResult {
1366 #[repr(C)]
1367 struct WhileData {
1368 condition: Option<Expression>,
1369 body: Vec<Statement>,
1370 child_index: u32,
1371 }
1372
1373 let while_data = unsafe { &mut *(client_data as *mut WhileData) };
1374 let kind = unsafe { clang_getCursorKind(cursor) };
1375
1376 match while_data.child_index {
1377 0 => {
1378 while_data.condition = match kind {
1381 CXCursor_BinaryOperator => extract_binary_op(cursor),
1382 CXCursor_IntegerLiteral => extract_int_literal(cursor),
1383 CXCursor_DeclRefExpr => extract_variable_ref(cursor),
1384 CXCursor_CallExpr => extract_function_call(cursor),
1385 CXCursor_UnaryOperator => extract_unary_op(cursor),
1386 _ => {
1387 let mut cond_expr: Option<Expression> = None;
1388 let expr_ptr = &mut cond_expr as *mut Option<Expression>;
1389 unsafe {
1390 clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1391 }
1392 cond_expr
1393 }
1394 };
1395 while_data.child_index += 1;
1396 CXChildVisit_Continue
1397 }
1398 1 => {
1399 if kind == CXCursor_CompoundStmt {
1401 let body_ptr = &mut while_data.body as *mut Vec<Statement>;
1402 unsafe {
1403 clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1404 }
1405 }
1406 while_data.child_index += 1;
1407 CXChildVisit_Continue
1408 }
1409 _ => CXChildVisit_Continue,
1410 }
1411}
1412
1413#[allow(non_upper_case_globals)]
1417fn extract_switch_stmt(cursor: CXCursor) -> Option<Statement> {
1418 #[repr(C)]
1423 struct SwitchData {
1424 condition: Option<Expression>,
1425 cases: Vec<SwitchCase>,
1426 default_case: Option<Vec<Statement>>,
1427 child_index: u32,
1428 }
1429
1430 let mut switch_data = SwitchData {
1431 condition: None,
1432 cases: Vec::new(),
1433 default_case: None,
1434 child_index: 0,
1435 };
1436
1437 let data_ptr = &mut switch_data as *mut SwitchData;
1438
1439 unsafe {
1440 clang_visitChildren(cursor, visit_switch_children, data_ptr as CXClientData);
1441 }
1442
1443 Some(Statement::Switch {
1444 condition: switch_data.condition?,
1445 cases: switch_data.cases,
1446 default_case: switch_data.default_case,
1447 })
1448}
1449
1450#[allow(non_upper_case_globals)]
1452extern "C" fn visit_switch_children(
1453 cursor: CXCursor,
1454 _parent: CXCursor,
1455 client_data: CXClientData,
1456) -> CXChildVisitResult {
1457 #[repr(C)]
1458 struct SwitchData {
1459 condition: Option<Expression>,
1460 cases: Vec<SwitchCase>,
1461 default_case: Option<Vec<Statement>>,
1462 child_index: u32,
1463 }
1464
1465 let switch_data = unsafe { &mut *(client_data as *mut SwitchData) };
1466 let kind = unsafe { clang_getCursorKind(cursor) };
1467
1468 match switch_data.child_index {
1469 0 => {
1470 if let Some(expr) = try_extract_expression(cursor) {
1472 switch_data.condition = Some(expr);
1473 }
1474 switch_data.child_index += 1;
1475 CXChildVisit_Continue
1476 }
1477 1 => {
1478 if kind == CXCursor_CompoundStmt {
1481 unsafe {
1482 clang_visitChildren(cursor, visit_switch_body, client_data);
1483 }
1484 }
1485 switch_data.child_index += 1;
1486 CXChildVisit_Continue
1487 }
1488 _ => CXChildVisit_Continue,
1489 }
1490}
1491
1492#[allow(non_upper_case_globals)]
1494extern "C" fn visit_switch_body(
1495 cursor: CXCursor,
1496 _parent: CXCursor,
1497 client_data: CXClientData,
1498) -> CXChildVisitResult {
1499 #[repr(C)]
1500 struct SwitchData {
1501 condition: Option<Expression>,
1502 cases: Vec<SwitchCase>,
1503 default_case: Option<Vec<Statement>>,
1504 child_index: u32,
1505 }
1506
1507 let switch_data = unsafe { &mut *(client_data as *mut SwitchData) };
1508 let kind = unsafe { clang_getCursorKind(cursor) };
1509
1510 match kind {
1511 CXCursor_CaseStmt => {
1512 if let Some(case) = extract_case_stmt(cursor) {
1514 switch_data.cases.push(case);
1515 }
1516 CXChildVisit_Continue
1517 }
1518 CXCursor_DefaultStmt => {
1519 if let Some(body) = extract_default_stmt(cursor) {
1521 switch_data.default_case = Some(body);
1522 }
1523 CXChildVisit_Continue
1524 }
1525 _ => CXChildVisit_Continue,
1526 }
1527}
1528
1529fn extract_case_stmt(cursor: CXCursor) -> Option<SwitchCase> {
1531 #[repr(C)]
1536 struct CaseData {
1537 value: Option<Expression>,
1538 body: Vec<Statement>,
1539 child_index: u32,
1540 }
1541
1542 let mut case_data = CaseData {
1543 value: None,
1544 body: Vec::new(),
1545 child_index: 0,
1546 };
1547
1548 let data_ptr = &mut case_data as *mut CaseData;
1549
1550 unsafe {
1551 clang_visitChildren(cursor, visit_case_children, data_ptr as CXClientData);
1552 }
1553
1554 Some(SwitchCase {
1555 value: case_data.value,
1556 body: case_data.body,
1557 })
1558}
1559
1560#[allow(non_upper_case_globals)]
1562extern "C" fn visit_case_children(
1563 cursor: CXCursor,
1564 _parent: CXCursor,
1565 client_data: CXClientData,
1566) -> CXChildVisitResult {
1567 #[repr(C)]
1568 struct CaseData {
1569 value: Option<Expression>,
1570 body: Vec<Statement>,
1571 child_index: u32,
1572 }
1573
1574 let case_data = unsafe { &mut *(client_data as *mut CaseData) };
1575 let _kind = unsafe { clang_getCursorKind(cursor) };
1576
1577 match case_data.child_index {
1578 0 => {
1579 if let Some(expr) = try_extract_expression(cursor) {
1581 case_data.value = Some(expr);
1582 }
1583 case_data.child_index += 1;
1584 CXChildVisit_Continue
1585 }
1586 _ => {
1587 if let Some(stmt) = extract_statement(cursor) {
1590 case_data.body.push(stmt);
1591 }
1592 CXChildVisit_Recurse
1594 }
1595 }
1596}
1597
1598fn extract_default_stmt(cursor: CXCursor) -> Option<Vec<Statement>> {
1600 let mut body: Vec<Statement> = Vec::new();
1602 let body_ptr = &mut body as *mut Vec<Statement>;
1603
1604 unsafe {
1605 clang_visitChildren(cursor, visit_default_children, body_ptr as CXClientData);
1606 }
1607
1608 Some(body)
1609}
1610
1611#[allow(non_upper_case_globals)]
1613extern "C" fn visit_default_children(
1614 cursor: CXCursor,
1615 _parent: CXCursor,
1616 client_data: CXClientData,
1617) -> CXChildVisitResult {
1618 let body = unsafe { &mut *(client_data as *mut Vec<Statement>) };
1619
1620 if let Some(stmt) = extract_statement(cursor) {
1622 body.push(stmt);
1623 }
1624
1625 CXChildVisit_Continue
1626}
1627
1628#[allow(non_upper_case_globals)]
1630fn extract_statement(cursor: CXCursor) -> Option<Statement> {
1631 let kind = unsafe { clang_getCursorKind(cursor) };
1632
1633 match kind {
1634 CXCursor_ReturnStmt => extract_return_stmt(cursor),
1635 CXCursor_VarDecl => extract_var_decl(cursor),
1636 CXCursor_IfStmt => extract_if_stmt(cursor),
1637 CXCursor_ForStmt => extract_for_stmt(cursor),
1638 CXCursor_WhileStmt => extract_while_stmt(cursor),
1639 CXCursor_BreakStmt => Some(Statement::Break),
1640 CXCursor_ContinueStmt => Some(Statement::Continue),
1641 CXCursor_UnaryOperator => extract_inc_dec_stmt(cursor),
1642 CXCursor_BinaryOperator => extract_assignment_stmt(cursor),
1643 CXCursor_CallExpr => {
1644 if let Some(Expression::FunctionCall {
1646 function,
1647 arguments,
1648 }) = extract_function_call(cursor)
1649 {
1650 return Some(Statement::FunctionCall {
1651 function,
1652 arguments,
1653 });
1654 }
1655 None
1656 }
1657 _ => None,
1658 }
1659}
1660
1661#[allow(non_upper_case_globals)]
1667extern "C" fn visit_expression(
1668 cursor: CXCursor,
1669 _parent: CXCursor,
1670 client_data: CXClientData,
1671) -> CXChildVisitResult {
1672 let expr_opt = unsafe { &mut *(client_data as *mut Option<Expression>) };
1674
1675 let kind = unsafe { clang_getCursorKind(cursor) };
1677
1678 match kind {
1679 CXCursor_IntegerLiteral => {
1680 if let Some(expr) = extract_int_literal(cursor) {
1682 *expr_opt = Some(expr);
1683 }
1684 CXChildVisit_Continue
1685 }
1686 CXCursor_StringLiteral => {
1687 if let Some(expr) = extract_string_literal(cursor) {
1689 *expr_opt = Some(expr);
1690 }
1691 CXChildVisit_Continue
1692 }
1693 CXCursor_DeclRefExpr => {
1694 if let Some(expr) = extract_variable_ref(cursor) {
1696 *expr_opt = Some(expr);
1697 }
1698 CXChildVisit_Continue
1699 }
1700 CXCursor_BinaryOperator => {
1701 if let Some(expr) = extract_binary_op(cursor) {
1703 *expr_opt = Some(expr);
1704 }
1705 CXChildVisit_Continue
1706 }
1707 CXCursor_CallExpr => {
1708 if let Some(expr) = extract_function_call(cursor) {
1710 *expr_opt = Some(expr);
1711 }
1712 CXChildVisit_Continue
1713 }
1714 CXCursor_UnaryOperator => {
1715 if let Some(expr) = extract_unary_op(cursor) {
1717 *expr_opt = Some(expr);
1718 }
1719 CXChildVisit_Continue
1720 }
1721 CXCursor_ArraySubscriptExpr => {
1722 if let Some(expr) = extract_array_index(cursor) {
1724 *expr_opt = Some(expr);
1725 }
1726 CXChildVisit_Continue
1727 }
1728 CXCursor_MemberRefExpr => {
1729 if let Some(expr) = extract_field_access(cursor) {
1731 *expr_opt = Some(expr);
1732 }
1733 CXChildVisit_Continue
1734 }
1735 CXCursor_UnexposedExpr => {
1736 CXChildVisit_Recurse
1739 }
1740 CXCursor_ParenExpr => {
1741 CXChildVisit_Recurse
1743 }
1744 136 => {
1745 if let Some(expr) = extract_sizeof(cursor) {
1747 *expr_opt = Some(expr);
1748 CXChildVisit_Continue
1749 } else {
1750 CXChildVisit_Recurse
1752 }
1753 }
1754 _ => CXChildVisit_Recurse,
1755 }
1756}
1757
1758fn extract_int_literal(cursor: CXCursor) -> Option<Expression> {
1760 let extent = unsafe { clang_getCursorExtent(cursor) };
1762
1763 let tu = unsafe {
1765 let loc = clang_getCursorLocation(cursor);
1766 let mut file = ptr::null_mut();
1767 let mut line = 0;
1768 let mut column = 0;
1769 let mut offset = 0;
1770 clang_getFileLocation(loc, &mut file, &mut line, &mut column, &mut offset);
1771
1772 clang_Cursor_getTranslationUnit(cursor)
1775 };
1776
1777 if tu.is_null() {
1778 return Some(Expression::IntLiteral(0));
1779 }
1780
1781 let mut tokens = ptr::null_mut();
1783 let mut num_tokens = 0;
1784
1785 unsafe {
1786 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1787 }
1788
1789 let mut value = 0;
1790
1791 if num_tokens > 0 {
1792 unsafe {
1794 let token_cxstring = clang_getTokenSpelling(tu, *tokens);
1795 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1796 if let Ok(token_str) = c_str.to_str() {
1797 value = token_str.parse().unwrap_or(0);
1798 }
1799 clang_disposeString(token_cxstring);
1800
1801 clang_disposeTokens(tu, tokens, num_tokens);
1803 }
1804 }
1805
1806 Some(Expression::IntLiteral(value))
1807}
1808
1809fn extract_string_literal(cursor: CXCursor) -> Option<Expression> {
1811 let extent = unsafe { clang_getCursorExtent(cursor) };
1813
1814 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1816
1817 if tu.is_null() {
1818 return Some(Expression::StringLiteral(String::new()));
1819 }
1820
1821 let mut tokens = ptr::null_mut();
1823 let mut num_tokens = 0;
1824
1825 unsafe {
1826 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1827 }
1828
1829 let mut value = String::new();
1830
1831 if num_tokens > 0 {
1832 unsafe {
1834 let token_cxstring = clang_getTokenSpelling(tu, *tokens);
1835 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1836 if let Ok(token_str) = c_str.to_str() {
1837 value = token_str.trim_matches('"').to_string();
1839 }
1840 clang_disposeString(token_cxstring);
1841
1842 clang_disposeTokens(tu, tokens, num_tokens);
1844 }
1845 }
1846
1847 Some(Expression::StringLiteral(value))
1848}
1849
1850fn extract_variable_ref(cursor: CXCursor) -> Option<Expression> {
1852 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
1854 let name = unsafe {
1855 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
1856 let var_name = c_str.to_string_lossy().into_owned();
1857 clang_disposeString(name_cxstring);
1858 var_name
1859 };
1860
1861 Some(Expression::Variable(name))
1862}
1863
1864fn extract_binary_op(cursor: CXCursor) -> Option<Expression> {
1866 let op = extract_binary_operator(cursor)?;
1868
1869 let mut operands: Vec<Expression> = Vec::new();
1871 let operands_ptr = &mut operands as *mut Vec<Expression>;
1872
1873 unsafe {
1874 clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
1875 }
1876
1877 if operands.len() != 2 {
1879 return None;
1880 }
1881
1882 Some(Expression::BinaryOp {
1883 op,
1884 left: Box::new(operands[0].clone()),
1885 right: Box::new(operands[1].clone()),
1886 })
1887}
1888
1889#[allow(non_upper_case_globals)]
1891extern "C" fn visit_binary_operand(
1892 cursor: CXCursor,
1893 _parent: CXCursor,
1894 client_data: CXClientData,
1895) -> CXChildVisitResult {
1896 let operands = unsafe { &mut *(client_data as *mut Vec<Expression>) };
1897 let kind = unsafe { clang_getCursorKind(cursor) };
1898
1899 match kind {
1900 CXCursor_IntegerLiteral => {
1901 if let Some(expr) = extract_int_literal(cursor) {
1902 operands.push(expr);
1903 }
1904 CXChildVisit_Continue
1905 }
1906 CXCursor_StringLiteral => {
1907 if let Some(expr) = extract_string_literal(cursor) {
1908 operands.push(expr);
1909 }
1910 CXChildVisit_Continue
1911 }
1912 CXCursor_DeclRefExpr => {
1913 if let Some(expr) = extract_variable_ref(cursor) {
1914 operands.push(expr);
1915 }
1916 CXChildVisit_Continue
1917 }
1918 CXCursor_BinaryOperator => {
1919 if let Some(expr) = extract_binary_op(cursor) {
1921 operands.push(expr);
1922 }
1923 CXChildVisit_Continue
1924 }
1925 CXCursor_UnaryOperator => {
1926 if let Some(expr) = extract_unary_op(cursor) {
1928 operands.push(expr);
1929 }
1930 CXChildVisit_Continue
1931 }
1932 CXCursor_ArraySubscriptExpr => {
1933 if let Some(expr) = extract_array_index(cursor) {
1935 operands.push(expr);
1936 }
1937 CXChildVisit_Continue
1938 }
1939 CXCursor_MemberRefExpr => {
1940 if let Some(expr) = extract_field_access(cursor) {
1942 operands.push(expr);
1943 }
1944 CXChildVisit_Continue
1945 }
1946 CXCursor_UnexposedExpr | CXCursor_ParenExpr => {
1947 if let Some(expr) = extract_sizeof(cursor) {
1949 operands.push(expr);
1950 CXChildVisit_Continue
1951 } else {
1952 CXChildVisit_Recurse
1953 }
1954 }
1955 136 => {
1956 if let Some(expr) = extract_sizeof(cursor) {
1958 operands.push(expr);
1959 CXChildVisit_Continue
1960 } else {
1961 CXChildVisit_Recurse
1962 }
1963 }
1964 CXCursor_CallExpr => {
1965 if let Some(expr) = extract_function_call(cursor) {
1967 operands.push(expr);
1968 }
1969 CXChildVisit_Continue
1970 }
1971 _ => CXChildVisit_Recurse,
1972 }
1973}
1974
1975#[allow(non_upper_case_globals)]
1977fn extract_binary_operator(cursor: CXCursor) -> Option<BinaryOperator> {
1978 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1980 if tu.is_null() {
1981 return None;
1982 }
1983
1984 let extent = unsafe { clang_getCursorExtent(cursor) };
1986
1987 let mut tokens = ptr::null_mut();
1989 let mut num_tokens = 0;
1990
1991 unsafe {
1992 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1993 }
1994
1995 let mut operator = None;
1996
1997 let mut candidates: Vec<(usize, BinaryOperator)> = Vec::new();
2004 let mut found_first_operand = false;
2005
2006 for i in 0..num_tokens {
2007 unsafe {
2008 let token = *tokens.add(i as usize);
2009 let token_kind = clang_getTokenKind(token);
2010
2011 if token_kind == CXToken_Identifier || token_kind == CXToken_Literal {
2013 found_first_operand = true;
2014 }
2015
2016 if token_kind == CXToken_Punctuation && found_first_operand {
2018 let token_cxstring = clang_getTokenSpelling(tu, token);
2019 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2020 if let Ok(token_str) = c_str.to_str() {
2021 let op = match token_str {
2022 "+" => Some(BinaryOperator::Add),
2023 "-" => Some(BinaryOperator::Subtract),
2024 "*" => Some(BinaryOperator::Multiply),
2025 "/" => Some(BinaryOperator::Divide),
2026 "%" => Some(BinaryOperator::Modulo),
2027 "==" => Some(BinaryOperator::Equal),
2028 "!=" => Some(BinaryOperator::NotEqual),
2029 "<" => Some(BinaryOperator::LessThan),
2030 ">" => Some(BinaryOperator::GreaterThan),
2031 "<=" => Some(BinaryOperator::LessEqual),
2032 ">=" => Some(BinaryOperator::GreaterEqual),
2033 "&&" => Some(BinaryOperator::LogicalAnd),
2034 "||" => Some(BinaryOperator::LogicalOr),
2035 _ => None,
2036 };
2037 if let Some(op) = op {
2038 candidates.push((i as usize, op));
2039 }
2040 }
2041 clang_disposeString(token_cxstring);
2042 }
2043 }
2044 }
2045
2046 if !candidates.is_empty() {
2049 for (_, op) in &candidates {
2052 if matches!(op, BinaryOperator::LogicalOr) {
2053 operator = Some(*op);
2054 break;
2055 }
2056 }
2057 if operator.is_none() {
2059 for (_, op) in &candidates {
2060 if matches!(op, BinaryOperator::LogicalAnd) {
2061 operator = Some(*op);
2062 break;
2063 }
2064 }
2065 }
2066 if operator.is_none() {
2069 for (_, op) in &candidates {
2071 if matches!(
2072 op,
2073 BinaryOperator::Equal
2074 | BinaryOperator::NotEqual
2075 | BinaryOperator::LessThan
2076 | BinaryOperator::GreaterThan
2077 | BinaryOperator::LessEqual
2078 | BinaryOperator::GreaterEqual
2079 ) {
2080 operator = Some(*op);
2081 break;
2082 }
2083 }
2084 }
2085 if operator.is_none() {
2087 for (_, op) in &candidates {
2088 if matches!(op, BinaryOperator::Add | BinaryOperator::Subtract) {
2089 operator = Some(*op);
2090 break;
2091 }
2092 }
2093 }
2094 if operator.is_none() {
2096 operator = Some(candidates[0].1);
2097 }
2098 }
2099
2100 unsafe {
2101 clang_disposeTokens(tu, tokens, num_tokens);
2102 }
2103
2104 operator
2105}
2106
2107fn extract_function_call(cursor: CXCursor) -> Option<Expression> {
2109 let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
2111 let function = unsafe {
2112 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
2113 let name = c_str.to_string_lossy().into_owned();
2114 clang_disposeString(name_cxstring);
2115 name
2116 };
2117
2118 #[repr(C)]
2121 struct ArgData {
2122 arguments: Vec<Expression>,
2123 skip_first_declref: bool,
2124 }
2125
2126 let mut arg_data = ArgData {
2127 arguments: Vec::new(),
2128 skip_first_declref: true, };
2130 let args_ptr = &mut arg_data as *mut ArgData;
2131
2132 unsafe {
2133 clang_visitChildren(cursor, visit_call_argument, args_ptr as CXClientData);
2134 }
2135
2136 Some(Expression::FunctionCall {
2137 function,
2138 arguments: arg_data.arguments,
2139 })
2140}
2141
2142#[allow(non_upper_case_globals)]
2148extern "C" fn visit_call_argument(
2149 cursor: CXCursor,
2150 _parent: CXCursor,
2151 client_data: CXClientData,
2152) -> CXChildVisitResult {
2153 #[repr(C)]
2154 struct ArgData {
2155 arguments: Vec<Expression>,
2156 skip_first_declref: bool,
2157 }
2158
2159 let arg_data = unsafe { &mut *(client_data as *mut ArgData) };
2161
2162 let kind = unsafe { clang_getCursorKind(cursor) };
2164
2165 match kind {
2166 CXCursor_IntegerLiteral => {
2167 if let Some(expr) = extract_int_literal(cursor) {
2168 arg_data.arguments.push(expr);
2169 }
2170 CXChildVisit_Continue
2171 }
2172 CXCursor_StringLiteral => {
2173 if let Some(expr) = extract_string_literal(cursor) {
2174 arg_data.arguments.push(expr);
2175 }
2176 CXChildVisit_Continue
2177 }
2178 CXCursor_DeclRefExpr => {
2179 if arg_data.skip_first_declref {
2182 arg_data.skip_first_declref = false;
2183 CXChildVisit_Continue
2184 } else {
2185 if let Some(expr) = extract_variable_ref(cursor) {
2186 arg_data.arguments.push(expr);
2187 }
2188 CXChildVisit_Continue
2189 }
2190 }
2191 CXCursor_BinaryOperator => {
2192 if let Some(expr) = extract_binary_op(cursor) {
2194 arg_data.arguments.push(expr);
2195 }
2196 CXChildVisit_Continue
2197 }
2198 CXCursor_CallExpr => {
2199 if let Some(expr) = extract_function_call(cursor) {
2201 arg_data.arguments.push(expr);
2202 }
2203 CXChildVisit_Continue
2204 }
2205 CXCursor_UnaryOperator => {
2206 if let Some(expr) = extract_unary_op(cursor) {
2208 arg_data.arguments.push(expr);
2209 }
2210 CXChildVisit_Continue
2211 }
2212 CXCursor_ArraySubscriptExpr => {
2213 if let Some(expr) = extract_array_index(cursor) {
2215 arg_data.arguments.push(expr);
2216 }
2217 CXChildVisit_Continue
2218 }
2219 CXCursor_MemberRefExpr => {
2220 if let Some(expr) = extract_field_access(cursor) {
2222 arg_data.arguments.push(expr);
2223 }
2224 CXChildVisit_Continue
2225 }
2226 CXCursor_UnexposedExpr | CXCursor_ParenExpr => {
2227 if let Some(expr) = extract_sizeof(cursor) {
2229 arg_data.arguments.push(expr);
2230 CXChildVisit_Continue
2231 } else {
2232 CXChildVisit_Recurse
2233 }
2234 }
2235 136 => {
2236 if let Some(expr) = extract_sizeof(cursor) {
2238 arg_data.arguments.push(expr);
2239 CXChildVisit_Continue
2240 } else {
2241 CXChildVisit_Recurse
2242 }
2243 }
2244 _ => CXChildVisit_Continue, }
2246}
2247
2248fn extract_unary_op(cursor: CXCursor) -> Option<Expression> {
2250 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2252 if tu.is_null() {
2253 return None;
2254 }
2255
2256 let extent = unsafe { clang_getCursorExtent(cursor) };
2258
2259 let mut tokens = ptr::null_mut();
2261 let mut num_tokens = 0;
2262
2263 unsafe {
2264 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2265 }
2266
2267 let mut operator: Option<UnaryOperator> = None;
2268 let mut is_dereference = false;
2269 let mut is_increment = false;
2270 let mut is_decrement = false;
2271 let mut operator_position = 0;
2272
2273 for i in 0..num_tokens {
2275 unsafe {
2276 let token = *tokens.add(i as usize);
2277 let token_kind = clang_getTokenKind(token);
2278
2279 if token_kind == CXToken_Punctuation {
2280 let token_cxstring = clang_getTokenSpelling(tu, token);
2281 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2282 if let Ok(token_str) = c_str.to_str() {
2283 match token_str {
2284 "*" => {
2285 is_dereference = true;
2286 clang_disposeString(token_cxstring);
2287 break;
2288 }
2289 "-" => {
2290 operator = Some(UnaryOperator::Minus);
2291 clang_disposeString(token_cxstring);
2292 break;
2293 }
2294 "!" => {
2295 operator = Some(UnaryOperator::LogicalNot);
2296 clang_disposeString(token_cxstring);
2297 break;
2298 }
2299 "~" => {
2300 operator = Some(UnaryOperator::BitwiseNot);
2301 clang_disposeString(token_cxstring);
2302 break;
2303 }
2304 "&" => {
2305 operator = Some(UnaryOperator::AddressOf);
2306 clang_disposeString(token_cxstring);
2307 break;
2308 }
2309 "++" => {
2310 is_increment = true;
2311 operator_position = i;
2312 clang_disposeString(token_cxstring);
2313 break;
2314 }
2315 "--" => {
2316 is_decrement = true;
2317 operator_position = i;
2318 clang_disposeString(token_cxstring);
2319 break;
2320 }
2321 _ => {}
2322 }
2323 }
2324 clang_disposeString(token_cxstring);
2325 }
2326 }
2327 }
2328
2329 unsafe {
2330 clang_disposeTokens(tu, tokens, num_tokens);
2331 }
2332
2333 let mut operand: Option<Expression> = None;
2335 let operand_ptr = &mut operand as *mut Option<Expression>;
2336
2337 unsafe {
2338 clang_visitChildren(cursor, visit_expression, operand_ptr as CXClientData);
2339 }
2340
2341 let operand_expr = operand?;
2342
2343 if is_dereference {
2345 return Some(Expression::Dereference(Box::new(operand_expr)));
2346 }
2347
2348 if is_increment {
2350 let is_pre = operator_position == 0;
2352 if is_pre {
2353 return Some(Expression::PreIncrement {
2354 operand: Box::new(operand_expr),
2355 });
2356 } else {
2357 return Some(Expression::PostIncrement {
2358 operand: Box::new(operand_expr),
2359 });
2360 }
2361 }
2362
2363 if is_decrement {
2364 let is_pre = operator_position == 0;
2366 if is_pre {
2367 return Some(Expression::PreDecrement {
2368 operand: Box::new(operand_expr),
2369 });
2370 } else {
2371 return Some(Expression::PostDecrement {
2372 operand: Box::new(operand_expr),
2373 });
2374 }
2375 }
2376
2377 if let Some(op) = operator {
2379 return Some(Expression::UnaryOp {
2380 op,
2381 operand: Box::new(operand_expr),
2382 });
2383 }
2384
2385 None
2386}
2387
2388fn extract_array_index(cursor: CXCursor) -> Option<Expression> {
2390 let mut operands: Vec<Expression> = Vec::new();
2392 let operands_ptr = &mut operands as *mut Vec<Expression>;
2393
2394 unsafe {
2395 clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
2396 }
2397
2398 if operands.len() != 2 {
2400 return None;
2401 }
2402
2403 Some(Expression::ArrayIndex {
2404 array: Box::new(operands[0].clone()),
2405 index: Box::new(operands[1].clone()),
2406 })
2407}
2408
2409fn extract_field_access(cursor: CXCursor) -> Option<Expression> {
2411 let field_name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
2413 let field = unsafe {
2414 let c_str = CStr::from_ptr(clang_getCString(field_name_cxstring));
2415 let name = c_str.to_string_lossy().into_owned();
2416 clang_disposeString(field_name_cxstring);
2417 name
2418 };
2419
2420 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2422 if tu.is_null() {
2423 return None;
2424 }
2425
2426 let extent = unsafe { clang_getCursorExtent(cursor) };
2427 let mut tokens = ptr::null_mut();
2428 let mut num_tokens = 0;
2429
2430 unsafe {
2431 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2432 }
2433
2434 let mut is_arrow = false;
2435
2436 for i in 0..num_tokens {
2441 unsafe {
2442 let token = *tokens.add(i as usize);
2443 let token_kind = clang_getTokenKind(token);
2444
2445 if token_kind == CXToken_Punctuation {
2446 let token_cxstring = clang_getTokenSpelling(tu, token);
2447 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2448 if let Ok(token_str) = c_str.to_str() {
2449 if token_str == "->" {
2450 is_arrow = true;
2451 } else if token_str == "." {
2453 is_arrow = false;
2454 }
2456 }
2457 clang_disposeString(token_cxstring);
2458 }
2459 }
2460 }
2461
2462 unsafe {
2463 clang_disposeTokens(tu, tokens, num_tokens);
2464 }
2465
2466 let mut object_expr: Option<Expression> = None;
2468 let expr_ptr = &mut object_expr as *mut Option<Expression>;
2469
2470 unsafe {
2471 clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
2472 }
2473
2474 let object = object_expr?;
2475
2476 if is_arrow {
2477 Some(Expression::PointerFieldAccess {
2478 pointer: Box::new(object),
2479 field,
2480 })
2481 } else {
2482 Some(Expression::FieldAccess {
2483 object: Box::new(object),
2484 field,
2485 })
2486 }
2487}
2488
2489fn extract_sizeof(cursor: CXCursor) -> Option<Expression> {
2491 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2493 if tu.is_null() {
2494 return None;
2495 }
2496
2497 let extent = unsafe { clang_getCursorExtent(cursor) };
2499
2500 let mut tokens = ptr::null_mut();
2502 let mut num_tokens = 0;
2503
2504 unsafe {
2505 clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2506 }
2507
2508 let mut is_sizeof = false;
2509 let mut type_name = String::new();
2510
2511 for i in 0..num_tokens {
2513 unsafe {
2514 let token = *tokens.add(i as usize);
2515 let token_kind = clang_getTokenKind(token);
2516 let token_cxstring = clang_getTokenSpelling(tu, token);
2517 let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2518
2519 if let Ok(token_str) = c_str.to_str() {
2520 if token_str == "sizeof" {
2521 is_sizeof = true;
2522 } else if is_sizeof
2523 && (token_kind == CXToken_Identifier || token_kind == CXToken_Keyword)
2524 && token_str != "("
2525 && token_str != ")"
2526 {
2527 if !type_name.is_empty() {
2529 type_name.push(' ');
2530 }
2531 type_name.push_str(token_str);
2532 }
2533 }
2534
2535 clang_disposeString(token_cxstring);
2536 }
2537 }
2538
2539 unsafe {
2540 clang_disposeTokens(tu, tokens, num_tokens);
2541 }
2542
2543 if is_sizeof && !type_name.is_empty() {
2544 Some(Expression::Sizeof { type_name })
2545 } else {
2546 None
2547 }
2548}
2549
2550#[allow(non_upper_case_globals)]
2552fn extract_cast(cursor: CXCursor) -> Option<Expression> {
2557 let target_cx_type = unsafe { clang_getCursorType(cursor) };
2559 let target_type = convert_type(target_cx_type)?;
2560
2561 let mut inner_expr: Option<Expression> = None;
2563 let inner_ptr = &mut inner_expr as *mut Option<Expression>;
2564
2565 unsafe {
2566 clang_visitChildren(cursor, visit_cast_inner, inner_ptr as CXClientData);
2567 }
2568
2569 inner_expr.map(|expr| Expression::Cast {
2570 target_type,
2571 expr: Box::new(expr),
2572 })
2573}
2574
2575#[allow(non_upper_case_globals)]
2577extern "C" fn visit_cast_inner(
2578 cursor: CXCursor,
2579 _parent: CXCursor,
2580 client_data: CXClientData,
2581) -> CXChildVisitResult {
2582 let inner_expr = unsafe { &mut *(client_data as *mut Option<Expression>) };
2583 let kind = unsafe { clang_getCursorKind(cursor) };
2584
2585 if let Some(expr) = try_extract_expression(cursor) {
2587 *inner_expr = Some(expr);
2588 return CXChildVisit_Break; }
2590
2591 match kind {
2593 CXCursor_UnexposedExpr | CXCursor_ParenExpr => CXChildVisit_Recurse,
2594 _ => CXChildVisit_Continue,
2595 }
2596}
2597
2598fn extract_compound_literal(cursor: CXCursor) -> Option<Expression> {
2603 let literal_cx_type = unsafe { clang_getCursorType(cursor) };
2605 let literal_type = convert_type(literal_cx_type)?;
2606
2607 let mut initializers: Vec<Expression> = Vec::new();
2609 let initializers_ptr = &mut initializers as *mut Vec<Expression>;
2610
2611 unsafe {
2612 clang_visitChildren(
2613 cursor,
2614 visit_compound_literal_initializers,
2615 initializers_ptr as CXClientData,
2616 );
2617 }
2618
2619 Some(Expression::CompoundLiteral {
2620 literal_type,
2621 initializers,
2622 })
2623}
2624
2625#[allow(non_upper_case_globals)]
2627extern "C" fn visit_compound_literal_initializers(
2628 cursor: CXCursor,
2629 _parent: CXCursor,
2630 client_data: CXClientData,
2631) -> CXChildVisitResult {
2632 let initializers = unsafe { &mut *(client_data as *mut Vec<Expression>) };
2633 let kind = unsafe { clang_getCursorKind(cursor) };
2634
2635 if kind == 119 {
2638 return CXChildVisit_Recurse;
2640 }
2641
2642 if let Some(expr) = try_extract_expression(cursor) {
2644 initializers.push(expr);
2645 return CXChildVisit_Continue;
2646 }
2647
2648 match kind {
2650 CXCursor_UnexposedExpr | CXCursor_ParenExpr => CXChildVisit_Recurse,
2651 _ => CXChildVisit_Continue,
2652 }
2653}
2654
2655#[allow(non_upper_case_globals)]
2656fn convert_type(cx_type: CXType) -> Option<Type> {
2657 match cx_type.kind {
2659 CXType_Void => Some(Type::Void),
2660 CXType_Int => Some(Type::Int),
2661 CXType_UInt => Some(Type::Int), CXType_UChar => Some(Type::Char), CXType_UShort => Some(Type::Int), CXType_ULong => Some(Type::Int), CXType_Short => Some(Type::Int), CXType_Long => Some(Type::Int), CXType_LongLong => Some(Type::Int), CXType_ULongLong => Some(Type::Int), CXType_Float => Some(Type::Float),
2670 CXType_Double => Some(Type::Double),
2671 CXType_Char_S | CXType_Char_U => Some(Type::Char),
2672 CXType_Pointer => {
2673 let pointee = unsafe { clang_getPointeeType(cx_type) };
2675
2676 if pointee.kind == CXType_FunctionProto || pointee.kind == CXType_FunctionNoProto {
2678 let return_cx_type = unsafe { clang_getResultType(pointee) };
2681 let return_type = convert_type(return_cx_type)?;
2682
2683 let num_args = unsafe { clang_getNumArgTypes(pointee) };
2685 let mut param_types = Vec::new();
2686
2687 for i in 0..num_args {
2688 let arg_type = unsafe { clang_getArgType(pointee, i as u32) };
2689 if let Some(param_type) = convert_type(arg_type) {
2690 param_types.push(param_type);
2691 }
2692 }
2693
2694 return Some(Type::FunctionPointer {
2695 param_types,
2696 return_type: Box::new(return_type),
2697 });
2698 }
2699
2700 convert_type(pointee).map(|t| Type::Pointer(Box::new(t)))
2702 }
2703 CXType_FunctionProto | CXType_FunctionNoProto => {
2704 let return_cx_type = unsafe { clang_getResultType(cx_type) };
2708 let return_type = convert_type(return_cx_type)?;
2709
2710 let num_args = unsafe { clang_getNumArgTypes(cx_type) };
2712 let mut param_types = Vec::new();
2713
2714 for i in 0..num_args {
2715 let arg_type = unsafe { clang_getArgType(cx_type, i as u32) };
2716 if let Some(param_type) = convert_type(arg_type) {
2717 param_types.push(param_type);
2718 }
2719 }
2720
2721 Some(Type::FunctionPointer {
2722 param_types,
2723 return_type: Box::new(return_type),
2724 })
2725 }
2726 CXType_Record => {
2727 let decl = unsafe { clang_getTypeDeclaration(cx_type) };
2729 let name_cxstring = unsafe { clang_getCursorSpelling(decl) };
2730 let name = unsafe {
2731 let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
2732 let struct_name = c_str.to_string_lossy().into_owned();
2733 clang_disposeString(name_cxstring);
2734 struct_name
2735 };
2736 Some(Type::Struct(name))
2737 }
2738 CXType_Elaborated => {
2739 let canonical = unsafe { clang_getCanonicalType(cx_type) };
2742 convert_type(canonical)
2743 }
2744 CXType_Typedef => {
2745 let canonical = unsafe { clang_getCanonicalType(cx_type) };
2748 convert_type(canonical)
2749 }
2750 CXType_ConstantArray => {
2751 let element_cx_type = unsafe { clang_getArrayElementType(cx_type) };
2753 let element_type = convert_type(element_cx_type)?;
2754
2755 let array_size = unsafe { clang_getArraySize(cx_type) };
2757 let size = if array_size >= 0 {
2758 Some(array_size)
2759 } else {
2760 None
2761 };
2762
2763 Some(Type::Array {
2764 element_type: Box::new(element_type),
2765 size,
2766 })
2767 }
2768 _ => None,
2769 }
2770}
2771
2772#[derive(Debug, Clone, PartialEq)]
2774pub struct SwitchCase {
2775 pub value: Option<Expression>,
2777 pub body: Vec<Statement>,
2779}
2780
2781#[derive(Debug, Clone, PartialEq)]
2783pub enum Statement {
2784 VariableDeclaration {
2786 name: String,
2788 var_type: Type,
2790 initializer: Option<Expression>,
2792 },
2793 Return(Option<Expression>),
2795 Assignment {
2797 target: String,
2799 value: Expression,
2801 },
2802 If {
2804 condition: Expression,
2806 then_block: Vec<Statement>,
2808 else_block: Option<Vec<Statement>>,
2810 },
2811 For {
2813 init: Option<Box<Statement>>,
2815 condition: Option<Expression>,
2817 increment: Option<Box<Statement>>,
2819 body: Vec<Statement>,
2821 },
2822 While {
2824 condition: Expression,
2826 body: Vec<Statement>,
2828 },
2829 DerefAssignment {
2831 target: Expression,
2833 value: Expression,
2835 },
2836 ArrayIndexAssignment {
2838 array: Box<Expression>,
2840 index: Box<Expression>,
2842 value: Expression,
2844 },
2845 FieldAssignment {
2847 object: Expression,
2849 field: String,
2851 value: Expression,
2853 },
2854 Break,
2856 Continue,
2858 Switch {
2860 condition: Expression,
2862 cases: Vec<SwitchCase>,
2864 default_case: Option<Vec<Statement>>,
2866 },
2867 PostIncrement {
2869 target: String,
2871 },
2872 PreIncrement {
2874 target: String,
2876 },
2877 PostDecrement {
2879 target: String,
2881 },
2882 PreDecrement {
2884 target: String,
2886 },
2887 CompoundAssignment {
2889 target: String,
2891 op: BinaryOperator,
2893 value: Expression,
2895 },
2896 FunctionCall {
2898 function: String,
2900 arguments: Vec<Expression>,
2902 },
2903}
2904
2905impl Statement {
2906 pub fn is_string_function_call(&self) -> bool {
2908 match self {
2909 Statement::FunctionCall { function, .. } => {
2910 matches!(function.as_str(), "strlen" | "strcmp" | "strcpy" | "strdup")
2911 }
2912 _ => false,
2913 }
2914 }
2915
2916 pub fn is_function_call(&self) -> bool {
2918 matches!(self, Statement::FunctionCall { .. })
2919 }
2920
2921 pub fn as_function_call(&self) -> Option<&Expression> {
2930 None
2931 }
2932}
2933
2934#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2936pub enum UnaryOperator {
2937 Minus,
2939 LogicalNot,
2941 BitwiseNot,
2943 AddressOf,
2945}
2946
2947#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2949pub enum BinaryOperator {
2950 Add,
2952 Subtract,
2954 Multiply,
2956 Divide,
2958 Modulo,
2960 Equal,
2962 NotEqual,
2964 LessThan,
2966 GreaterThan,
2968 LessEqual,
2970 GreaterEqual,
2972 LogicalAnd,
2974 LogicalOr,
2976}
2977
2978#[derive(Debug, Clone, PartialEq)]
2980pub enum Expression {
2981 IntLiteral(i32),
2983 StringLiteral(String),
2985 Variable(String),
2987 BinaryOp {
2989 op: BinaryOperator,
2991 left: Box<Expression>,
2993 right: Box<Expression>,
2995 },
2996 FunctionCall {
2998 function: String,
3000 arguments: Vec<Expression>,
3002 },
3003 Dereference(Box<Expression>),
3005 UnaryOp {
3007 op: UnaryOperator,
3009 operand: Box<Expression>,
3011 },
3012 ArrayIndex {
3014 array: Box<Expression>,
3016 index: Box<Expression>,
3018 },
3019 FieldAccess {
3021 object: Box<Expression>,
3023 field: String,
3025 },
3026 PointerFieldAccess {
3028 pointer: Box<Expression>,
3030 field: String,
3032 },
3033 PostIncrement {
3035 operand: Box<Expression>,
3037 },
3038 PreIncrement {
3040 operand: Box<Expression>,
3042 },
3043 PostDecrement {
3045 operand: Box<Expression>,
3047 },
3048 PreDecrement {
3050 operand: Box<Expression>,
3052 },
3053 Sizeof {
3055 type_name: String,
3057 },
3058 Cast {
3071 target_type: Type,
3073 expr: Box<Expression>,
3075 },
3076 CompoundLiteral {
3089 literal_type: Type,
3091 initializers: Vec<Expression>,
3093 },
3094}
3095
3096impl Expression {
3097 pub fn is_string_function_call(&self) -> bool {
3099 match self {
3100 Expression::FunctionCall { function, .. } => {
3101 matches!(function.as_str(), "strlen" | "strcmp" | "strcpy" | "strdup")
3102 }
3103 _ => false,
3104 }
3105 }
3106
3107 pub fn string_function_name(&self) -> Option<&str> {
3109 match self {
3110 Expression::FunctionCall { function, .. } if self.is_string_function_call() => {
3111 Some(function.as_str())
3112 }
3113 _ => None,
3114 }
3115 }
3116
3117 pub fn has_string_literal_argument(&self) -> bool {
3119 match self {
3120 Expression::FunctionCall { arguments, .. } => arguments
3121 .iter()
3122 .any(|arg| matches!(arg, Expression::StringLiteral(_))),
3123 _ => false,
3124 }
3125 }
3126}
3127
3128#[derive(Debug, Clone, PartialEq)]
3130pub struct Typedef {
3131 pub name: String,
3133 pub underlying_type: Type,
3135}
3136
3137impl Typedef {
3138 pub fn new(name: String, underlying_type: Type) -> Self {
3140 Self {
3141 name,
3142 underlying_type,
3143 }
3144 }
3145
3146 pub fn name(&self) -> &str {
3148 &self.name
3149 }
3150
3151 pub fn underlying_type(&self) -> &str {
3153 match &self.underlying_type {
3155 Type::Void => "void",
3156 Type::Int => "int",
3157 Type::Float => "float",
3158 Type::Double => "double",
3159 Type::Char => "char",
3160 Type::Pointer(inner) => match **inner {
3161 Type::Char => "char*",
3162 Type::Int => "int*",
3163 Type::Float => "float*",
3164 Type::Double => "double*",
3165 Type::Void => "void*",
3166 _ => "pointer",
3167 },
3168 Type::Struct(name) => name,
3169 Type::FunctionPointer { .. } => "function pointer",
3170 Type::Array { .. } => "array",
3171 }
3172 }
3173
3174 pub fn is_pointer(&self) -> bool {
3176 matches!(self.underlying_type, Type::Pointer(_))
3177 }
3178
3179 pub fn is_struct(&self) -> bool {
3181 matches!(self.underlying_type, Type::Struct(_))
3182 }
3183
3184 pub fn is_function_pointer(&self) -> bool {
3186 matches!(self.underlying_type, Type::FunctionPointer { .. })
3187 }
3188
3189 pub fn is_array(&self) -> bool {
3191 false
3193 }
3194}
3195
3196#[derive(Debug, Clone, PartialEq)]
3198pub struct StructField {
3199 pub name: String,
3201 pub field_type: Type,
3203}
3204
3205impl StructField {
3206 pub fn new(name: String, field_type: Type) -> Self {
3208 Self { name, field_type }
3209 }
3210
3211 pub fn name(&self) -> &str {
3213 &self.name
3214 }
3215
3216 pub fn is_function_pointer(&self) -> bool {
3218 matches!(self.field_type, Type::FunctionPointer { .. })
3219 }
3220}
3221
3222#[derive(Debug, Clone, PartialEq)]
3224pub struct Struct {
3225 pub name: String,
3227 pub fields: Vec<StructField>,
3229}
3230
3231impl Struct {
3232 pub fn new(name: String, fields: Vec<StructField>) -> Self {
3234 Self { name, fields }
3235 }
3236
3237 pub fn name(&self) -> &str {
3239 &self.name
3240 }
3241
3242 pub fn fields(&self) -> &[StructField] {
3244 &self.fields
3245 }
3246}
3247
3248#[derive(Debug, Clone, PartialEq)]
3250pub struct Variable {
3251 name: String,
3253 var_type: Type,
3255 initializer: Option<Expression>,
3257 is_static: bool,
3259 is_extern: bool,
3261 is_const: bool,
3263}
3264
3265impl Variable {
3266 pub fn new(name: String, var_type: Type) -> Self {
3268 Self {
3269 name,
3270 var_type,
3271 initializer: None,
3272 is_static: false,
3273 is_extern: false,
3274 is_const: false,
3275 }
3276 }
3277
3278 pub fn new_with_initializer(name: String, var_type: Type, initializer: Expression) -> Self {
3280 Self {
3281 name,
3282 var_type,
3283 initializer: Some(initializer),
3284 is_static: false,
3285 is_extern: false,
3286 is_const: false,
3287 }
3288 }
3289
3290 pub fn new_with_storage_class(
3292 name: String,
3293 var_type: Type,
3294 initializer: Option<Expression>,
3295 is_static: bool,
3296 is_extern: bool,
3297 is_const: bool,
3298 ) -> Self {
3299 Self {
3300 name,
3301 var_type,
3302 initializer,
3303 is_static,
3304 is_extern,
3305 is_const,
3306 }
3307 }
3308
3309 pub fn name(&self) -> &str {
3311 &self.name
3312 }
3313
3314 pub fn var_type(&self) -> &Type {
3316 &self.var_type
3317 }
3318
3319 pub fn is_function_pointer(&self) -> bool {
3321 matches!(self.var_type, Type::FunctionPointer { .. })
3322 }
3323
3324 pub fn function_pointer_param_count(&self) -> usize {
3326 match &self.var_type {
3327 Type::FunctionPointer { param_types, .. } => param_types.len(),
3328 _ => 0,
3329 }
3330 }
3331
3332 pub fn function_pointer_has_void_return(&self) -> bool {
3334 match &self.var_type {
3335 Type::FunctionPointer { return_type, .. } => matches!(**return_type, Type::Void),
3336 _ => false,
3337 }
3338 }
3339
3340 pub fn is_string_literal(&self) -> bool {
3352 let is_char_ptr =
3354 matches!(self.var_type, Type::Pointer(ref inner) if **inner == Type::Char);
3355
3356 if let Some(initializer) = &self.initializer {
3358 is_char_ptr && matches!(initializer, Expression::StringLiteral(_))
3359 } else {
3360 false
3361 }
3362 }
3363
3364 pub fn is_string_buffer(&self) -> bool {
3374 let is_char_ptr =
3376 matches!(self.var_type, Type::Pointer(ref inner) if **inner == Type::Char);
3377
3378 if let Some(Expression::FunctionCall { function, .. }) = &self.initializer {
3380 is_char_ptr && (function == "malloc" || function == "calloc")
3381 } else {
3382 false
3383 }
3384 }
3385
3386 pub fn initializer(&self) -> Option<&Expression> {
3390 self.initializer.as_ref()
3391 }
3392
3393 pub fn is_static(&self) -> bool {
3395 self.is_static
3396 }
3397
3398 pub fn is_extern(&self) -> bool {
3400 self.is_extern
3401 }
3402
3403 pub fn is_const(&self) -> bool {
3405 self.is_const
3406 }
3407}
3408
3409#[derive(Debug, Clone, PartialEq)]
3411pub struct Ast {
3412 functions: Vec<Function>,
3413 typedefs: Vec<Typedef>,
3414 structs: Vec<Struct>,
3415 macros: Vec<MacroDefinition>,
3416 variables: Vec<Variable>,
3417}
3418
3419#[derive(Debug, Clone, PartialEq)]
3449pub struct MacroDefinition {
3450 pub name: String,
3452 pub parameters: Vec<String>,
3454 pub body: String,
3456}
3457
3458impl MacroDefinition {
3459 pub fn new_object_like(name: String, body: String) -> Self {
3461 Self {
3462 name,
3463 parameters: vec![],
3464 body,
3465 }
3466 }
3467
3468 pub fn new_function_like(name: String, parameters: Vec<String>, body: String) -> Self {
3470 Self {
3471 name,
3472 parameters,
3473 body,
3474 }
3475 }
3476
3477 pub fn name(&self) -> &str {
3479 &self.name
3480 }
3481
3482 pub fn parameters(&self) -> &[String] {
3484 &self.parameters
3485 }
3486
3487 pub fn body(&self) -> &str {
3489 &self.body
3490 }
3491
3492 pub fn is_function_like(&self) -> bool {
3494 !self.parameters.is_empty()
3495 }
3496
3497 pub fn is_object_like(&self) -> bool {
3499 self.parameters.is_empty()
3500 }
3501}
3502
3503impl Ast {
3504 pub fn new() -> Self {
3506 Self {
3507 functions: Vec::new(),
3508 typedefs: Vec::new(),
3509 structs: Vec::new(),
3510 macros: Vec::new(),
3511 variables: Vec::new(),
3512 }
3513 }
3514
3515 pub fn functions(&self) -> &[Function] {
3517 &self.functions
3518 }
3519
3520 pub fn add_function(&mut self, function: Function) {
3522 self.functions.push(function);
3523 }
3524
3525 pub fn typedefs(&self) -> &[Typedef] {
3527 &self.typedefs
3528 }
3529
3530 pub fn add_typedef(&mut self, typedef: Typedef) {
3532 self.typedefs.push(typedef);
3533 }
3534
3535 pub fn structs(&self) -> &[Struct] {
3537 &self.structs
3538 }
3539
3540 pub fn add_struct(&mut self, struct_def: Struct) {
3542 self.structs.push(struct_def);
3543 }
3544
3545 pub fn macros(&self) -> &[MacroDefinition] {
3547 &self.macros
3548 }
3549
3550 pub fn add_macro(&mut self, macro_def: MacroDefinition) {
3552 self.macros.push(macro_def);
3553 }
3554
3555 pub fn variables(&self) -> &[Variable] {
3557 &self.variables
3558 }
3559
3560 pub fn add_variable(&mut self, variable: Variable) {
3562 self.variables.push(variable);
3563 }
3564}
3565
3566impl Default for Ast {
3567 fn default() -> Self {
3568 Self::new()
3569 }
3570}
3571
3572#[derive(Debug, Clone, PartialEq)]
3574pub struct Function {
3575 pub name: String,
3577 pub return_type: Type,
3579 pub parameters: Vec<Parameter>,
3581 pub body: Vec<Statement>,
3583}
3584
3585impl Function {
3586 pub fn new(name: String, return_type: Type, parameters: Vec<Parameter>) -> Self {
3588 Self {
3589 name,
3590 return_type,
3591 parameters,
3592 body: Vec::new(),
3593 }
3594 }
3595
3596 pub fn new_with_body(
3598 name: String,
3599 return_type: Type,
3600 parameters: Vec<Parameter>,
3601 body: Vec<Statement>,
3602 ) -> Self {
3603 Self {
3604 name,
3605 return_type,
3606 parameters,
3607 body,
3608 }
3609 }
3610}
3611
3612#[derive(Debug, Clone, PartialEq)]
3614pub enum Type {
3615 Void,
3617 Int,
3619 Float,
3621 Double,
3623 Char,
3625 Pointer(Box<Type>),
3627 Struct(String),
3629 FunctionPointer {
3631 param_types: Vec<Type>,
3633 return_type: Box<Type>,
3635 },
3636 Array {
3639 element_type: Box<Type>,
3641 size: Option<i64>,
3643 },
3644}
3645
3646#[derive(Debug, Clone, PartialEq)]
3648pub struct Parameter {
3649 pub name: String,
3651 pub param_type: Type,
3653}
3654
3655impl Parameter {
3656 pub fn new(name: String, param_type: Type) -> Self {
3658 Self { name, param_type }
3659 }
3660
3661 pub fn is_function_pointer(&self) -> bool {
3663 matches!(self.param_type, Type::FunctionPointer { .. })
3664 }
3665
3666 pub fn is_const_char_pointer(&self) -> bool {
3674 matches!(self.param_type, Type::Pointer(ref inner) if matches!(**inner, Type::Char))
3675 }
3676}
3677
3678#[cfg(test)]
3679#[path = "parser_tests.rs"]
3680mod parser_tests;
3681
3682#[cfg(test)]
3683#[path = "pointer_arithmetic_tests.rs"]
3684mod pointer_arithmetic_tests;
3685
3686#[cfg(test)]
3687#[path = "break_continue_tests.rs"]
3688mod break_continue_tests;