1#![allow(non_upper_case_globals, dead_code)]
5#![deny(clippy::missing_docs_in_private_items)]
6
7use crate::ir::context::BindgenContext;
8use clang_sys::*;
9use std::cmp;
10
11use std::ffi::{CStr, CString};
12use std::fmt;
13use std::fs::OpenOptions;
14use std::hash::Hash;
15use std::hash::Hasher;
16use std::os::raw::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ulonglong};
17use std::sync::OnceLock;
18use std::{mem, ptr, slice};
19
20pub(crate) struct Attribute {
25 name: &'static [u8],
26 kind: Option<CXCursorKind>,
27 token_kind: CXTokenKind,
28}
29
30impl Attribute {
31 pub(crate) const MUST_USE: Self = Self {
33 name: b"warn_unused_result",
34 kind: Some(440),
36 token_kind: CXToken_Identifier,
37 };
38
39 pub(crate) const NO_RETURN: Self = Self {
41 name: b"_Noreturn",
42 kind: None,
43 token_kind: CXToken_Keyword,
44 };
45
46 pub(crate) const NO_RETURN_CPP: Self = Self {
48 name: b"noreturn",
49 kind: None,
50 token_kind: CXToken_Identifier,
51 };
52}
53
54#[derive(Copy, Clone)]
58pub(crate) struct Cursor {
59 x: CXCursor,
60}
61
62impl fmt::Debug for Cursor {
63 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
64 write!(
65 fmt,
66 "Cursor({} kind: {}, loc: {}, usr: {:?})",
67 self.spelling(),
68 kind_to_str(self.kind()),
69 self.location(),
70 self.usr()
71 )
72 }
73}
74
75impl Cursor {
76 pub(crate) fn usr(&self) -> Option<String> {
81 let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) };
82 if s.is_empty() {
83 None
84 } else {
85 Some(s)
86 }
87 }
88
89 pub(crate) fn is_declaration(&self) -> bool {
91 unsafe { clang_isDeclaration(self.kind()) != 0 }
92 }
93
94 pub(crate) fn is_anonymous(&self) -> bool {
96 unsafe { clang_Cursor_isAnonymous(self.x) != 0 }
97 }
98
99 pub(crate) fn spelling(&self) -> String {
101 unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) }
102 }
103
104 pub(crate) fn display_name(&self) -> String {
109 unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) }
110 }
111
112 pub(crate) fn mangling(&self) -> String {
114 unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) }
115 }
116
117 pub(crate) fn cxx_manglings(&self) -> Result<Vec<String>, ()> {
120 use clang_sys::*;
121 unsafe {
122 let manglings = clang_Cursor_getCXXManglings(self.x);
123 if manglings.is_null() {
124 return Err(());
125 }
126 let count = (*manglings).Count as usize;
127
128 let mut result = Vec::with_capacity(count);
129 for i in 0..count {
130 let string_ptr = (*manglings).Strings.add(i);
131 result.push(cxstring_to_string_leaky(*string_ptr));
132 }
133 clang_disposeStringSet(manglings);
134 Ok(result)
135 }
136 }
137
138 pub(crate) fn is_builtin(&self) -> bool {
140 let (file, _, _, _) = self.location().location();
141 file.name().is_none()
142 }
143
144 pub(crate) fn lexical_parent(&self) -> Cursor {
162 unsafe {
163 Cursor {
164 x: clang_getCursorLexicalParent(self.x),
165 }
166 }
167 }
168
169 pub(crate) fn fallible_semantic_parent(&self) -> Option<Cursor> {
174 let sp = unsafe {
175 Cursor {
176 x: clang_getCursorSemanticParent(self.x),
177 }
178 };
179 if sp == *self || !sp.is_valid() {
180 return None;
181 }
182 Some(sp)
183 }
184
185 pub(crate) fn semantic_parent(&self) -> Cursor {
190 self.fallible_semantic_parent().unwrap()
191 }
192
193 pub(crate) fn num_template_args(&self) -> Option<u32> {
200 self.cur_type()
205 .num_template_args()
206 .or_else(|| {
207 let n: c_int =
208 unsafe { clang_Cursor_getNumTemplateArguments(self.x) };
209
210 if n >= 0 {
211 Some(n as u32)
212 } else {
213 debug_assert_eq!(n, -1);
214 None
215 }
216 })
217 .or_else(|| {
218 let canonical = self.canonical();
219 if canonical == *self {
220 None
221 } else {
222 canonical.num_template_args()
223 }
224 })
225 }
226
227 pub(crate) fn translation_unit(&self) -> Cursor {
234 assert!(self.is_valid());
235 unsafe {
236 let tu = clang_Cursor_getTranslationUnit(self.x);
237 let cursor = Cursor {
238 x: clang_getTranslationUnitCursor(tu),
239 };
240 assert!(cursor.is_valid());
241 cursor
242 }
243 }
244
245 pub(crate) fn is_toplevel(&self) -> bool {
247 let mut semantic_parent = self.fallible_semantic_parent();
248
249 while semantic_parent.is_some() &&
250 (semantic_parent.unwrap().kind() == CXCursor_Namespace ||
251 semantic_parent.unwrap().kind() ==
252 CXCursor_NamespaceAlias ||
253 semantic_parent.unwrap().kind() == CXCursor_NamespaceRef)
254 {
255 semantic_parent =
256 semantic_parent.unwrap().fallible_semantic_parent();
257 }
258
259 let tu = self.translation_unit();
260 semantic_parent == tu.fallible_semantic_parent()
262 }
263
264 pub(crate) fn is_template_like(&self) -> bool {
268 matches!(
269 self.kind(),
270 CXCursor_ClassTemplate |
271 CXCursor_ClassTemplatePartialSpecialization |
272 CXCursor_TypeAliasTemplateDecl
273 )
274 }
275
276 pub(crate) fn is_macro_function_like(&self) -> bool {
278 unsafe { clang_Cursor_isMacroFunctionLike(self.x) != 0 }
279 }
280
281 pub(crate) fn kind(&self) -> CXCursorKind {
283 self.x.kind
284 }
285
286 pub(crate) fn is_definition(&self) -> bool {
288 unsafe { clang_isCursorDefinition(self.x) != 0 }
289 }
290
291 pub(crate) fn is_template_specialization(&self) -> bool {
293 self.specialized().is_some()
294 }
295
296 pub(crate) fn is_fully_specialized_template(&self) -> bool {
299 self.is_template_specialization() &&
300 self.kind() != CXCursor_ClassTemplatePartialSpecialization &&
301 self.num_template_args().unwrap_or(0) > 0
302 }
303
304 pub(crate) fn is_in_non_fully_specialized_template(&self) -> bool {
307 if self.is_toplevel() {
308 return false;
309 }
310
311 let parent = self.semantic_parent();
312 if parent.is_fully_specialized_template() {
313 return false;
314 }
315
316 if !parent.is_template_like() {
317 return parent.is_in_non_fully_specialized_template();
318 }
319
320 true
321 }
322
323 pub(crate) fn is_template_parameter(&self) -> bool {
325 matches!(
326 self.kind(),
327 CXCursor_TemplateTemplateParameter |
328 CXCursor_TemplateTypeParameter |
329 CXCursor_NonTypeTemplateParameter
330 )
331 }
332
333 pub(crate) fn is_dependent_on_template_parameter(&self) -> bool {
335 fn visitor(
336 found_template_parameter: &mut bool,
337 cur: Cursor,
338 ) -> CXChildVisitResult {
339 if cur.is_template_parameter() {
341 *found_template_parameter = true;
342 return CXChildVisit_Break;
343 }
344
345 if let Some(referenced) = cur.referenced() {
347 if referenced.is_template_parameter() {
348 *found_template_parameter = true;
349 return CXChildVisit_Break;
350 }
351
352 referenced
353 .visit(|next| visitor(found_template_parameter, next));
354 if *found_template_parameter {
355 return CXChildVisit_Break;
356 }
357 }
358
359 CXChildVisit_Recurse
361 }
362
363 if self.is_template_parameter() {
364 return true;
365 }
366
367 let mut found_template_parameter = false;
368 self.visit(|next| visitor(&mut found_template_parameter, next));
369
370 found_template_parameter
371 }
372
373 pub(crate) fn is_valid(&self) -> bool {
375 unsafe { clang_isInvalid(self.kind()) == 0 }
376 }
377
378 pub(crate) fn location(&self) -> SourceLocation {
380 unsafe {
381 SourceLocation {
382 x: clang_getCursorLocation(self.x),
383 }
384 }
385 }
386
387 pub(crate) fn extent(&self) -> CXSourceRange {
389 unsafe { clang_getCursorExtent(self.x) }
390 }
391
392 pub(crate) fn raw_comment(&self) -> Option<String> {
394 let s = unsafe {
395 cxstring_into_string(clang_Cursor_getRawCommentText(self.x))
396 };
397 if s.is_empty() {
398 None
399 } else {
400 Some(s)
401 }
402 }
403
404 pub(crate) fn comment(&self) -> Comment {
406 unsafe {
407 Comment {
408 x: clang_Cursor_getParsedComment(self.x),
409 }
410 }
411 }
412
413 pub(crate) fn cur_type(&self) -> Type {
415 unsafe {
416 Type {
417 x: clang_getCursorType(self.x),
418 }
419 }
420 }
421
422 pub(crate) fn definition(&self) -> Option<Cursor> {
426 unsafe {
427 let ret = Cursor {
428 x: clang_getCursorDefinition(self.x),
429 };
430
431 if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound {
432 Some(ret)
433 } else {
434 None
435 }
436 }
437 }
438
439 pub(crate) fn referenced(&self) -> Option<Cursor> {
442 unsafe {
443 let ret = Cursor {
444 x: clang_getCursorReferenced(self.x),
445 };
446
447 if ret.is_valid() {
448 Some(ret)
449 } else {
450 None
451 }
452 }
453 }
454
455 pub(crate) fn canonical(&self) -> Cursor {
461 unsafe {
462 Cursor {
463 x: clang_getCanonicalCursor(self.x),
464 }
465 }
466 }
467
468 pub(crate) fn specialized(&self) -> Option<Cursor> {
472 unsafe {
473 let ret = Cursor {
474 x: clang_getSpecializedCursorTemplate(self.x),
475 };
476 if ret.is_valid() {
477 Some(ret)
478 } else {
479 None
480 }
481 }
482 }
483
484 pub(crate) fn template_kind(&self) -> CXCursorKind {
487 unsafe { clang_getTemplateCursorKind(self.x) }
488 }
489
490 pub(crate) fn visit<Visitor>(&self, mut visitor: Visitor)
494 where
495 Visitor: FnMut(Cursor) -> CXChildVisitResult,
496 {
497 let data = ptr::addr_of_mut!(visitor);
498 unsafe {
499 clang_visitChildren(self.x, visit_children::<Visitor>, data.cast());
500 }
501 }
502
503 pub(crate) fn visit_sorted<Visitor>(
507 &self,
508 ctx: &mut BindgenContext,
509 mut visitor: Visitor,
510 ) where
511 Visitor: FnMut(&mut BindgenContext, Cursor),
512 {
513 const SOURCE_ORDER_ENABLED: bool = false;
517 if !SOURCE_ORDER_ENABLED {
518 return self.visit(|c| {
519 visitor(ctx, c);
520 CXChildVisit_Continue
521 });
522 }
523
524 let mut children = self.collect_children();
525 for child in &children {
526 if child.kind() == CXCursor_InclusionDirective {
527 if let Some(included_file) = child.get_included_file_name() {
528 let location = child.location();
529 let (source_file, _, _, offset) = location.location();
530
531 if let Some(source_file) = source_file.name() {
532 ctx.add_include(source_file, included_file, offset);
533 }
534 }
535 }
536 }
537 children
538 .sort_by(|child1, child2| child1.cmp_by_source_order(child2, ctx));
539 for child in children {
540 visitor(ctx, child);
541 }
542 }
543
544 fn cmp_by_source_order(
551 &self,
552 other: &Self,
553 ctx: &BindgenContext,
554 ) -> cmp::Ordering {
555 let (file, _, _, offset) = self.location().location();
556 let (other_file, _, _, other_offset) = other.location().location();
557
558 let (file, other_file) = match (file.name(), other_file.name()) {
559 (Some(file), Some(other_file)) => (file, other_file),
560 (Some(_), None) => return cmp::Ordering::Greater,
562 (None, Some(_)) => return cmp::Ordering::Less,
563 (None, None) => return cmp::Ordering::Equal,
564 };
565
566 if file == other_file {
567 return offset.cmp(&other_offset);
569 }
570
571 let include_location = ctx.included_file_location(&file);
572 let other_include_location = ctx.included_file_location(&other_file);
573 match (include_location, other_include_location) {
574 (Some((file2, offset2)), _) if file2 == other_file => {
575 offset2.cmp(&other_offset)
576 }
577 (Some(_), None) => cmp::Ordering::Greater,
578 (_, Some((other_file2, other_offset2))) if file == other_file2 => {
579 offset.cmp(&other_offset2)
580 }
581 (None, Some(_)) => cmp::Ordering::Less,
582 (Some((file2, offset2)), Some((other_file2, other_offset2))) => {
583 if file2 == other_file2 {
584 offset2.cmp(&other_offset2)
585 } else {
586 cmp::Ordering::Equal
587 }
588 }
589 (None, None) => cmp::Ordering::Equal,
590 }
591 }
592
593 pub(crate) fn collect_children(&self) -> Vec<Cursor> {
595 let mut children = vec![];
596 self.visit(|c| {
597 children.push(c);
598 CXChildVisit_Continue
599 });
600 children
601 }
602
603 pub(crate) fn has_children(&self) -> bool {
605 let mut has_children = false;
606 self.visit(|_| {
607 has_children = true;
608 CXChildVisit_Break
609 });
610 has_children
611 }
612
613 pub(crate) fn has_at_least_num_children(&self, n: usize) -> bool {
615 assert!(n > 0);
616 let mut num_left = n;
617 self.visit(|_| {
618 num_left -= 1;
619 if num_left == 0 {
620 CXChildVisit_Break
621 } else {
622 CXChildVisit_Continue
623 }
624 });
625 num_left == 0
626 }
627
628 pub(crate) fn contains_cursor(&self, kind: CXCursorKind) -> bool {
632 let mut found = false;
633
634 self.visit(|c| {
635 if c.kind() == kind {
636 found = true;
637 CXChildVisit_Break
638 } else {
639 CXChildVisit_Continue
640 }
641 });
642
643 found
644 }
645
646 pub(crate) fn is_inlined_function(&self) -> bool {
648 unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 }
649 }
650
651 pub(crate) fn is_defaulted_function(&self) -> bool {
653 unsafe { clang_CXXMethod_isDefaulted(self.x) != 0 }
654 }
655
656 pub(crate) fn is_deleted_function(&self) -> bool {
658 self.is_inlined_function() &&
668 self.definition().is_none() &&
669 !self.is_defaulted_function()
670 }
671
672 pub(crate) fn is_bit_field(&self) -> bool {
674 unsafe { clang_Cursor_isBitField(self.x) != 0 }
675 }
676
677 pub(crate) fn bit_width_expr(&self) -> Option<Cursor> {
680 if !self.is_bit_field() {
681 return None;
682 }
683
684 let mut result = None;
685 self.visit(|cur| {
686 if cur.kind() == CXCursor_TypeRef {
689 return CXChildVisit_Continue;
690 }
691
692 result = Some(cur);
694
695 CXChildVisit_Break
696 });
697
698 result
699 }
700
701 pub(crate) fn bit_width(&self) -> Option<u32> {
704 if self.bit_width_expr()?.is_dependent_on_template_parameter() {
708 return None;
709 }
710
711 unsafe {
712 let w = clang_getFieldDeclBitWidth(self.x);
713 if w == -1 {
714 None
715 } else {
716 Some(w as u32)
717 }
718 }
719 }
720
721 pub(crate) fn enum_type(&self) -> Option<Type> {
724 unsafe {
725 let t = Type {
726 x: clang_getEnumDeclIntegerType(self.x),
727 };
728 if t.is_valid() {
729 Some(t)
730 } else {
731 None
732 }
733 }
734 }
735
736 pub(crate) fn enum_val_boolean(&self) -> Option<bool> {
740 unsafe {
741 if self.kind() == CXCursor_EnumConstantDecl {
742 Some(clang_getEnumConstantDeclValue(self.x) != 0)
743 } else {
744 None
745 }
746 }
747 }
748
749 pub(crate) fn enum_val_signed(&self) -> Option<i64> {
753 unsafe {
754 if self.kind() == CXCursor_EnumConstantDecl {
755 #[allow(clippy::unnecessary_cast)]
756 Some(clang_getEnumConstantDeclValue(self.x) as i64)
757 } else {
758 None
759 }
760 }
761 }
762
763 pub(crate) fn enum_val_unsigned(&self) -> Option<u64> {
767 unsafe {
768 if self.kind() == CXCursor_EnumConstantDecl {
769 #[allow(clippy::unnecessary_cast)]
770 Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64)
771 } else {
772 None
773 }
774 }
775 }
776
777 pub(crate) fn has_attrs<const N: usize>(
779 &self,
780 attrs: &[Attribute; N],
781 ) -> [bool; N] {
782 let mut found_attrs = [false; N];
783 let mut found_count = 0;
784
785 self.visit(|cur| {
786 let kind = cur.kind();
787 for (idx, attr) in attrs.iter().enumerate() {
788 let found_attr = &mut found_attrs[idx];
789 if !*found_attr {
790 if attr.kind == Some(kind) ||
792 (kind == CXCursor_UnexposedAttr &&
793 cur.tokens().iter().any(|t| {
794 t.kind == attr.token_kind &&
795 t.spelling() == attr.name
796 }))
797 {
798 *found_attr = true;
799 found_count += 1;
800
801 if found_count == N {
802 return CXChildVisit_Break;
803 }
804 }
805 }
806 }
807
808 CXChildVisit_Continue
809 });
810
811 found_attrs
812 }
813
814 pub(crate) fn typedef_type(&self) -> Option<Type> {
817 let inner = Type {
818 x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) },
819 };
820
821 if inner.is_valid() {
822 Some(inner)
823 } else {
824 None
825 }
826 }
827
828 pub(crate) fn linkage(&self) -> CXLinkageKind {
832 unsafe { clang_getCursorLinkage(self.x) }
833 }
834
835 pub(crate) fn visibility(&self) -> CXVisibilityKind {
837 unsafe { clang_getCursorVisibility(self.x) }
838 }
839
840 pub(crate) fn args(&self) -> Option<Vec<Cursor>> {
846 self.num_args().ok().map(|num| {
850 (0..num)
851 .map(|i| Cursor {
852 x: unsafe { clang_Cursor_getArgument(self.x, i as c_uint) },
853 })
854 .collect()
855 })
856 }
857
858 pub(crate) fn num_args(&self) -> Result<u32, ()> {
864 unsafe {
865 let w = clang_Cursor_getNumArguments(self.x);
866 if w == -1 {
867 Err(())
868 } else {
869 Ok(w as u32)
870 }
871 }
872 }
873
874 pub(crate) fn access_specifier(&self) -> CX_CXXAccessSpecifier {
876 unsafe { clang_getCXXAccessSpecifier(self.x) }
877 }
878
879 pub(crate) fn public_accessible(&self) -> bool {
884 let access = self.access_specifier();
885 access == CX_CXXPublic || access == CX_CXXInvalidAccessSpecifier
886 }
887
888 pub(crate) fn is_mutable_field(&self) -> bool {
891 unsafe { clang_CXXField_isMutable(self.x) != 0 }
892 }
893
894 pub(crate) fn offset_of_field(&self) -> Result<usize, LayoutError> {
896 let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) };
897
898 if offset < 0 {
899 Err(LayoutError::from(offset as i32))
900 } else {
901 Ok(offset as usize)
902 }
903 }
904
905 pub(crate) fn method_is_static(&self) -> bool {
907 unsafe { clang_CXXMethod_isStatic(self.x) != 0 }
908 }
909
910 pub(crate) fn method_is_const(&self) -> bool {
912 unsafe { clang_CXXMethod_isConst(self.x) != 0 }
913 }
914
915 pub(crate) fn method_is_virtual(&self) -> bool {
917 unsafe { clang_CXXMethod_isVirtual(self.x) != 0 }
918 }
919
920 pub(crate) fn method_is_pure_virtual(&self) -> bool {
922 unsafe { clang_CXXMethod_isPureVirtual(self.x) != 0 }
923 }
924
925 pub(crate) fn is_virtual_base(&self) -> bool {
927 unsafe { clang_isVirtualBase(self.x) != 0 }
928 }
929
930 pub(crate) fn evaluate(&self) -> Option<EvalResult> {
932 EvalResult::new(*self)
933 }
934
935 pub(crate) fn ret_type(&self) -> Option<Type> {
937 let rt = Type {
938 x: unsafe { clang_getCursorResultType(self.x) },
939 };
940 if rt.is_valid() {
941 Some(rt)
942 } else {
943 None
944 }
945 }
946
947 pub(crate) fn tokens(&self) -> RawTokens<'_> {
949 RawTokens::new(self)
950 }
951
952 pub(crate) fn cexpr_tokens(self) -> Vec<cexpr::token::Token> {
954 self.tokens()
955 .iter()
956 .filter_map(|token| token.as_cexpr_token())
957 .collect()
958 }
959
960 pub(crate) fn get_included_file_name(&self) -> Option<String> {
964 let file = unsafe { clang_getIncludedFile(self.x) };
965 if file.is_null() {
966 None
967 } else {
968 Some(unsafe { cxstring_into_string(clang_getFileName(file)) })
969 }
970 }
971
972 pub(crate) fn is_inline_namespace(&self) -> bool {
974 unsafe { clang_Cursor_isInlineNamespace(self.x) != 0 }
975 }
976}
977
978pub(crate) struct RawTokens<'a> {
980 cursor: &'a Cursor,
981 tu: CXTranslationUnit,
982 tokens: *mut CXToken,
983 token_count: c_uint,
984}
985
986impl<'a> RawTokens<'a> {
987 fn new(cursor: &'a Cursor) -> Self {
988 let mut tokens = ptr::null_mut();
989 let mut token_count = 0;
990 let range = cursor.extent();
991 let tu = unsafe { clang_Cursor_getTranslationUnit(cursor.x) };
992 unsafe { clang_tokenize(tu, range, &mut tokens, &mut token_count) };
993 Self {
994 cursor,
995 tu,
996 tokens,
997 token_count,
998 }
999 }
1000
1001 fn as_slice(&self) -> &[CXToken] {
1002 if self.tokens.is_null() {
1003 return &[];
1004 }
1005 unsafe { slice::from_raw_parts(self.tokens, self.token_count as usize) }
1006 }
1007
1008 pub(crate) fn iter(&self) -> ClangTokenIterator<'_> {
1010 ClangTokenIterator {
1011 tu: self.tu,
1012 raw: self.as_slice().iter(),
1013 }
1014 }
1015}
1016
1017impl Drop for RawTokens<'_> {
1018 fn drop(&mut self) {
1019 if !self.tokens.is_null() {
1020 unsafe {
1021 clang_disposeTokens(
1022 self.tu,
1023 self.tokens,
1024 self.token_count as c_uint,
1025 );
1026 }
1027 }
1028 }
1029}
1030
1031#[derive(Debug)]
1035pub(crate) struct ClangToken {
1036 spelling: CXString,
1037 pub(crate) extent: CXSourceRange,
1040 pub(crate) kind: CXTokenKind,
1043}
1044
1045impl ClangToken {
1046 pub(crate) fn spelling(&self) -> &[u8] {
1048 let c_str = unsafe { CStr::from_ptr(clang_getCString(self.spelling)) };
1049 c_str.to_bytes()
1050 }
1051
1052 pub(crate) fn as_cexpr_token(&self) -> Option<cexpr::token::Token> {
1054 use cexpr::token;
1055
1056 let kind = match self.kind {
1057 CXToken_Punctuation => token::Kind::Punctuation,
1058 CXToken_Literal => token::Kind::Literal,
1059 CXToken_Identifier => token::Kind::Identifier,
1060 CXToken_Keyword => token::Kind::Keyword,
1061 CXToken_Comment => return None,
1064 _ => {
1065 warn!("Found unexpected token kind: {self:?}");
1066 return None;
1067 }
1068 };
1069
1070 Some(token::Token {
1071 kind,
1072 raw: self.spelling().to_vec().into_boxed_slice(),
1073 })
1074 }
1075}
1076
1077impl Drop for ClangToken {
1078 fn drop(&mut self) {
1079 unsafe { clang_disposeString(self.spelling) }
1080 }
1081}
1082
1083pub(crate) struct ClangTokenIterator<'a> {
1085 tu: CXTranslationUnit,
1086 raw: slice::Iter<'a, CXToken>,
1087}
1088
1089impl Iterator for ClangTokenIterator<'_> {
1090 type Item = ClangToken;
1091
1092 fn next(&mut self) -> Option<Self::Item> {
1093 let raw = self.raw.next()?;
1094 unsafe {
1095 let kind = clang_getTokenKind(*raw);
1096 let spelling = clang_getTokenSpelling(self.tu, *raw);
1097 let extent = clang_getTokenExtent(self.tu, *raw);
1098 Some(ClangToken {
1099 spelling,
1100 extent,
1101 kind,
1102 })
1103 }
1104 }
1105}
1106
1107pub(crate) fn is_valid_identifier(name: &str) -> bool {
1110 let mut chars = name.chars();
1111 let first_valid =
1112 chars.next().is_some_and(|c| c.is_alphabetic() || c == '_');
1113
1114 first_valid && chars.all(|c| c.is_alphanumeric() || c == '_')
1115}
1116
1117extern "C" fn visit_children<Visitor>(
1118 cur: CXCursor,
1119 _parent: CXCursor,
1120 data: CXClientData,
1121) -> CXChildVisitResult
1122where
1123 Visitor: FnMut(Cursor) -> CXChildVisitResult,
1124{
1125 let func: &mut Visitor = unsafe { &mut *data.cast::<Visitor>() };
1126 let child = Cursor { x: cur };
1127
1128 (*func)(child)
1129}
1130
1131impl PartialEq for Cursor {
1132 fn eq(&self, other: &Cursor) -> bool {
1133 unsafe { clang_equalCursors(self.x, other.x) == 1 }
1134 }
1135}
1136
1137impl Eq for Cursor {}
1138
1139impl Hash for Cursor {
1140 fn hash<H: Hasher>(&self, state: &mut H) {
1141 unsafe { clang_hashCursor(self.x) }.hash(state);
1142 }
1143}
1144
1145#[derive(Clone, Copy)]
1147pub(crate) struct Type {
1148 x: CXType,
1149}
1150
1151impl PartialEq for Type {
1152 fn eq(&self, other: &Self) -> bool {
1153 unsafe { clang_equalTypes(self.x, other.x) != 0 }
1154 }
1155}
1156
1157impl Eq for Type {}
1158
1159impl fmt::Debug for Type {
1160 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1161 write!(
1162 fmt,
1163 "Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})",
1164 self.spelling(),
1165 type_to_str(self.kind()),
1166 self.call_conv(),
1167 self.declaration(),
1168 self.declaration().canonical()
1169 )
1170 }
1171}
1172
1173#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1175pub(crate) enum LayoutError {
1176 Invalid,
1178 Incomplete,
1180 Dependent,
1182 NotConstantSize,
1184 InvalidFieldName,
1187 Unknown,
1189}
1190
1191impl ::std::convert::From<i32> for LayoutError {
1192 fn from(val: i32) -> Self {
1193 use self::LayoutError::*;
1194
1195 match val {
1196 CXTypeLayoutError_Invalid => Invalid,
1197 CXTypeLayoutError_Incomplete => Incomplete,
1198 CXTypeLayoutError_Dependent => Dependent,
1199 CXTypeLayoutError_NotConstantSize => NotConstantSize,
1200 CXTypeLayoutError_InvalidFieldName => InvalidFieldName,
1201 _ => Unknown,
1202 }
1203 }
1204}
1205
1206impl Type {
1207 pub(crate) fn kind(&self) -> CXTypeKind {
1209 self.x.kind
1210 }
1211
1212 pub(crate) fn declaration(&self) -> Cursor {
1214 unsafe {
1215 Cursor {
1216 x: clang_getTypeDeclaration(self.x),
1217 }
1218 }
1219 }
1220
1221 pub(crate) fn canonical_declaration(
1223 &self,
1224 location: Option<&Cursor>,
1225 ) -> Option<CanonicalTypeDeclaration> {
1226 let mut declaration = self.declaration();
1227 if !declaration.is_valid() {
1228 if let Some(location) = location {
1229 let mut location = *location;
1230 if let Some(referenced) = location.referenced() {
1231 location = referenced;
1232 }
1233 if location.is_template_like() {
1234 declaration = location;
1235 }
1236 }
1237 }
1238
1239 let canonical = declaration.canonical();
1240 if canonical.is_valid() && canonical.kind() != CXCursor_NoDeclFound {
1241 Some(CanonicalTypeDeclaration(*self, canonical))
1242 } else {
1243 None
1244 }
1245 }
1246
1247 pub(crate) fn spelling(&self) -> String {
1249 let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) };
1250 if s.split("::").all(is_valid_identifier) {
1253 if let Some(s) = s.split("::").last() {
1254 return s.to_owned();
1255 }
1256 }
1257
1258 s
1259 }
1260
1261 pub(crate) fn is_const(&self) -> bool {
1263 unsafe { clang_isConstQualifiedType(self.x) != 0 }
1264 }
1265
1266 #[inline]
1267 fn is_non_deductible_auto_type(&self) -> bool {
1268 debug_assert_eq!(self.kind(), CXType_Auto);
1269 self.canonical_type() == *self
1270 }
1271
1272 #[inline]
1273 fn clang_size_of(&self, ctx: &BindgenContext) -> c_longlong {
1274 match self.kind() {
1275 CXType_RValueReference | CXType_LValueReference => {
1277 ctx.target_pointer_size() as c_longlong
1278 }
1279 CXType_Auto if self.is_non_deductible_auto_type() => -6,
1281 _ => unsafe { clang_Type_getSizeOf(self.x) },
1282 }
1283 }
1284
1285 #[inline]
1286 fn clang_align_of(&self, ctx: &BindgenContext) -> c_longlong {
1287 match self.kind() {
1288 CXType_RValueReference | CXType_LValueReference => {
1290 ctx.target_pointer_size() as c_longlong
1291 }
1292 CXType_Auto if self.is_non_deductible_auto_type() => -6,
1294 _ => unsafe { clang_Type_getAlignOf(self.x) },
1295 }
1296 }
1297
1298 pub(crate) fn size(&self, ctx: &BindgenContext) -> usize {
1301 let val = self.clang_size_of(ctx);
1302 if val < 0 {
1303 0
1304 } else {
1305 val as usize
1306 }
1307 }
1308
1309 pub(crate) fn fallible_size(
1311 &self,
1312 ctx: &BindgenContext,
1313 ) -> Result<usize, LayoutError> {
1314 let val = self.clang_size_of(ctx);
1315 if val < 0 {
1316 Err(LayoutError::from(val as i32))
1317 } else {
1318 Ok(val as usize)
1319 }
1320 }
1321
1322 pub(crate) fn align(&self, ctx: &BindgenContext) -> usize {
1325 let val = self.clang_align_of(ctx);
1326 if val < 0 {
1327 0
1328 } else {
1329 val as usize
1330 }
1331 }
1332
1333 pub(crate) fn fallible_align(
1335 &self,
1336 ctx: &BindgenContext,
1337 ) -> Result<usize, LayoutError> {
1338 let val = self.clang_align_of(ctx);
1339 if val < 0 {
1340 Err(LayoutError::from(val as i32))
1341 } else {
1342 Ok(val as usize)
1343 }
1344 }
1345
1346 pub(crate) fn fallible_layout(
1349 &self,
1350 ctx: &BindgenContext,
1351 ) -> Result<crate::ir::layout::Layout, LayoutError> {
1352 use crate::ir::layout::Layout;
1353 let size = self.fallible_size(ctx)?;
1354 let align = self.fallible_align(ctx)?;
1355 Ok(Layout::new(size, align))
1356 }
1357
1358 pub(crate) fn num_template_args(&self) -> Option<u32> {
1361 let n = unsafe { clang_Type_getNumTemplateArguments(self.x) };
1362 if n >= 0 {
1363 Some(n as u32)
1364 } else {
1365 debug_assert_eq!(n, -1);
1366 None
1367 }
1368 }
1369
1370 pub(crate) fn template_args(&self) -> Option<TypeTemplateArgIterator> {
1373 self.num_template_args().map(|n| TypeTemplateArgIterator {
1374 x: self.x,
1375 length: n,
1376 index: 0,
1377 })
1378 }
1379
1380 pub(crate) fn args(&self) -> Option<Vec<Type>> {
1384 self.num_args().ok().map(|num| {
1385 (0..num)
1386 .map(|i| Type {
1387 x: unsafe { clang_getArgType(self.x, i as c_uint) },
1388 })
1389 .collect()
1390 })
1391 }
1392
1393 pub(crate) fn num_args(&self) -> Result<u32, ()> {
1397 unsafe {
1398 let w = clang_getNumArgTypes(self.x);
1399 if w == -1 {
1400 Err(())
1401 } else {
1402 Ok(w as u32)
1403 }
1404 }
1405 }
1406
1407 pub(crate) fn pointee_type(&self) -> Option<Type> {
1410 match self.kind() {
1411 CXType_Pointer |
1412 CXType_RValueReference |
1413 CXType_LValueReference |
1414 CXType_MemberPointer |
1415 CXType_BlockPointer |
1416 CXType_ObjCObjectPointer => {
1417 let ret = Type {
1418 x: unsafe { clang_getPointeeType(self.x) },
1419 };
1420 debug_assert!(ret.is_valid());
1421 Some(ret)
1422 }
1423 _ => None,
1424 }
1425 }
1426
1427 pub(crate) fn elem_type(&self) -> Option<Type> {
1430 let current_type = Type {
1431 x: unsafe { clang_getElementType(self.x) },
1432 };
1433 if current_type.is_valid() {
1434 Some(current_type)
1435 } else {
1436 None
1437 }
1438 }
1439
1440 pub(crate) fn num_elements(&self) -> Option<usize> {
1443 let num_elements_returned = unsafe { clang_getNumElements(self.x) };
1444 if num_elements_returned == -1 {
1445 None
1446 } else {
1447 Some(num_elements_returned as usize)
1448 }
1449 }
1450
1451 pub(crate) fn canonical_type(&self) -> Type {
1454 unsafe {
1455 Type {
1456 x: clang_getCanonicalType(self.x),
1457 }
1458 }
1459 }
1460
1461 pub(crate) fn is_variadic(&self) -> bool {
1463 unsafe { clang_isFunctionTypeVariadic(self.x) != 0 }
1464 }
1465
1466 pub(crate) fn ret_type(&self) -> Option<Type> {
1469 let rt = Type {
1470 x: unsafe { clang_getResultType(self.x) },
1471 };
1472 if rt.is_valid() {
1473 Some(rt)
1474 } else {
1475 None
1476 }
1477 }
1478
1479 pub(crate) fn call_conv(&self) -> CXCallingConv {
1482 unsafe { clang_getFunctionTypeCallingConv(self.x) }
1483 }
1484
1485 pub(crate) fn named(&self) -> Type {
1488 unsafe {
1489 Type {
1490 x: clang_Type_getNamedType(self.x),
1491 }
1492 }
1493 }
1494
1495 pub(crate) fn atomic_value_type(&self) -> Type {
1497 unsafe {
1498 Type {
1499 x: clang_Type_getValueType(self.x),
1500 }
1501 }
1502 }
1503
1504 pub(crate) fn is_valid(&self) -> bool {
1506 self.kind() != CXType_Invalid
1507 }
1508
1509 pub(crate) fn is_valid_and_exposed(&self) -> bool {
1511 self.is_valid() && self.kind() != CXType_Unexposed
1512 }
1513
1514 pub(crate) fn is_fully_instantiated_template(&self) -> bool {
1516 self.template_args().is_some_and(|args| args.len() > 0) &&
1520 !matches!(
1521 self.declaration().kind(),
1522 CXCursor_ClassTemplatePartialSpecialization |
1523 CXCursor_TypeAliasTemplateDecl |
1524 CXCursor_TemplateTemplateParameter
1525 )
1526 }
1527
1528 pub(crate) fn is_associated_type(&self) -> bool {
1538 fn hacky_parse_associated_type<S: AsRef<str>>(spelling: S) -> bool {
1540 static ASSOC_TYPE_RE: OnceLock<regex::Regex> = OnceLock::new();
1541 ASSOC_TYPE_RE
1542 .get_or_init(|| {
1543 regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+")
1544 .unwrap()
1545 })
1546 .is_match(spelling.as_ref())
1547 }
1548
1549 self.kind() == CXType_Unexposed &&
1550 (hacky_parse_associated_type(self.spelling()) ||
1551 hacky_parse_associated_type(
1552 self.canonical_type().spelling(),
1553 ))
1554 }
1555}
1556
1557#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1563pub(crate) struct CanonicalTypeDeclaration(Type, Cursor);
1564
1565impl CanonicalTypeDeclaration {
1566 pub(crate) fn ty(&self) -> &Type {
1568 &self.0
1569 }
1570
1571 pub(crate) fn cursor(&self) -> &Cursor {
1573 &self.1
1574 }
1575}
1576
1577pub(crate) struct TypeTemplateArgIterator {
1579 x: CXType,
1580 length: u32,
1581 index: u32,
1582}
1583
1584impl Iterator for TypeTemplateArgIterator {
1585 type Item = Type;
1586 fn next(&mut self) -> Option<Type> {
1587 if self.index < self.length {
1588 let idx = self.index as c_uint;
1589 self.index += 1;
1590 Some(Type {
1591 x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) },
1592 })
1593 } else {
1594 None
1595 }
1596 }
1597}
1598
1599impl ExactSizeIterator for TypeTemplateArgIterator {
1600 fn len(&self) -> usize {
1601 assert!(self.index <= self.length);
1602 (self.length - self.index) as usize
1603 }
1604}
1605
1606pub(crate) struct SourceLocation {
1609 x: CXSourceLocation,
1610}
1611
1612impl SourceLocation {
1613 pub(crate) fn location(&self) -> (File, usize, usize, usize) {
1616 unsafe {
1617 let mut file = mem::zeroed();
1618 let mut line = 0;
1619 let mut col = 0;
1620 let mut off = 0;
1621 clang_getFileLocation(
1622 self.x, &mut file, &mut line, &mut col, &mut off,
1623 );
1624 (File { x: file }, line as usize, col as usize, off as usize)
1625 }
1626 }
1627}
1628
1629impl fmt::Display for SourceLocation {
1630 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1631 let (file, line, col, _) = self.location();
1632 if let Some(name) = file.name() {
1633 write!(f, "{name}:{line}:{col}")
1634 } else {
1635 "builtin definitions".fmt(f)
1636 }
1637 }
1638}
1639
1640impl fmt::Debug for SourceLocation {
1641 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1642 write!(f, "{self}")
1643 }
1644}
1645
1646pub(crate) struct Comment {
1650 x: CXComment,
1651}
1652
1653impl Comment {
1654 pub(crate) fn kind(&self) -> CXCommentKind {
1656 unsafe { clang_Comment_getKind(self.x) }
1657 }
1658
1659 pub(crate) fn get_children(&self) -> CommentChildrenIterator {
1661 CommentChildrenIterator {
1662 parent: self.x,
1663 length: unsafe { clang_Comment_getNumChildren(self.x) },
1664 index: 0,
1665 }
1666 }
1667
1668 pub(crate) fn get_tag_name(&self) -> String {
1671 unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) }
1672 }
1673
1674 pub(crate) fn get_tag_attrs(&self) -> CommentAttributesIterator {
1676 CommentAttributesIterator {
1677 x: self.x,
1678 length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) },
1679 index: 0,
1680 }
1681 }
1682}
1683
1684pub(crate) struct CommentChildrenIterator {
1686 parent: CXComment,
1687 length: c_uint,
1688 index: c_uint,
1689}
1690
1691impl Iterator for CommentChildrenIterator {
1692 type Item = Comment;
1693 fn next(&mut self) -> Option<Comment> {
1694 if self.index < self.length {
1695 let idx = self.index;
1696 self.index += 1;
1697 Some(Comment {
1698 x: unsafe { clang_Comment_getChild(self.parent, idx) },
1699 })
1700 } else {
1701 None
1702 }
1703 }
1704}
1705
1706pub(crate) struct CommentAttribute {
1708 pub(crate) name: String,
1710 pub(crate) value: String,
1712}
1713
1714pub(crate) struct CommentAttributesIterator {
1716 x: CXComment,
1717 length: c_uint,
1718 index: c_uint,
1719}
1720
1721impl Iterator for CommentAttributesIterator {
1722 type Item = CommentAttribute;
1723 fn next(&mut self) -> Option<CommentAttribute> {
1724 if self.index < self.length {
1725 let idx = self.index;
1726 self.index += 1;
1727 Some(CommentAttribute {
1728 name: unsafe {
1729 cxstring_into_string(clang_HTMLStartTag_getAttrName(
1730 self.x, idx,
1731 ))
1732 },
1733 value: unsafe {
1734 cxstring_into_string(clang_HTMLStartTag_getAttrValue(
1735 self.x, idx,
1736 ))
1737 },
1738 })
1739 } else {
1740 None
1741 }
1742 }
1743}
1744
1745pub(crate) struct File {
1747 x: CXFile,
1748}
1749
1750impl File {
1751 pub(crate) fn name(&self) -> Option<String> {
1753 if self.x.is_null() {
1754 return None;
1755 }
1756 Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) })
1757 }
1758}
1759
1760fn cxstring_to_string_leaky(s: CXString) -> String {
1761 if s.data.is_null() {
1762 return String::new();
1763 }
1764 let c_str = unsafe { CStr::from_ptr(clang_getCString(s)) };
1765 c_str.to_string_lossy().into_owned()
1766}
1767
1768fn cxstring_into_string(s: CXString) -> String {
1769 let ret = cxstring_to_string_leaky(s);
1770 unsafe { clang_disposeString(s) };
1771 ret
1772}
1773
1774pub(crate) struct Index {
1777 x: CXIndex,
1778}
1779
1780impl Index {
1781 pub(crate) fn new(pch: bool, diag: bool) -> Index {
1788 unsafe {
1789 Index {
1790 x: clang_createIndex(c_int::from(pch), c_int::from(diag)),
1791 }
1792 }
1793 }
1794}
1795
1796impl fmt::Debug for Index {
1797 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1798 write!(fmt, "Index {{ }}")
1799 }
1800}
1801
1802impl Drop for Index {
1803 fn drop(&mut self) {
1804 unsafe {
1805 clang_disposeIndex(self.x);
1806 }
1807 }
1808}
1809
1810pub(crate) struct TranslationUnit {
1812 x: CXTranslationUnit,
1813}
1814
1815impl fmt::Debug for TranslationUnit {
1816 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1817 write!(fmt, "TranslationUnit {{ }}")
1818 }
1819}
1820
1821impl TranslationUnit {
1822 pub(crate) fn parse(
1824 ix: &Index,
1825 file: &str,
1826 cmd_args: &[Box<str>],
1827 unsaved: &[UnsavedFile],
1828 opts: CXTranslationUnit_Flags,
1829 ) -> Option<TranslationUnit> {
1830 let fname = CString::new(file).unwrap();
1831 let _c_args: Vec<CString> = cmd_args
1832 .iter()
1833 .map(|s| CString::new(s.as_bytes()).unwrap())
1834 .collect();
1835 let c_args: Vec<*const c_char> =
1836 _c_args.iter().map(|s| s.as_ptr()).collect();
1837 let mut c_unsaved: Vec<CXUnsavedFile> =
1838 unsaved.iter().map(|f| f.x).collect();
1839 let tu = unsafe {
1840 clang_parseTranslationUnit(
1841 ix.x,
1842 fname.as_ptr(),
1843 c_args.as_ptr(),
1844 c_args.len() as c_int,
1845 c_unsaved.as_mut_ptr(),
1846 c_unsaved.len() as c_uint,
1847 opts,
1848 )
1849 };
1850 if tu.is_null() {
1851 None
1852 } else {
1853 Some(TranslationUnit { x: tu })
1854 }
1855 }
1856
1857 pub(crate) fn diags(&self) -> Vec<Diagnostic> {
1860 unsafe {
1861 let num = clang_getNumDiagnostics(self.x) as usize;
1862 let mut diags = vec![];
1863 for i in 0..num {
1864 diags.push(Diagnostic {
1865 x: clang_getDiagnostic(self.x, i as c_uint),
1866 });
1867 }
1868 diags
1869 }
1870 }
1871
1872 pub(crate) fn cursor(&self) -> Cursor {
1874 unsafe {
1875 Cursor {
1876 x: clang_getTranslationUnitCursor(self.x),
1877 }
1878 }
1879 }
1880
1881 pub(crate) fn save(&mut self, file: &str) -> Result<(), CXSaveError> {
1883 let Ok(file) = CString::new(file) else {
1884 return Err(CXSaveError_Unknown);
1885 };
1886 let ret = unsafe {
1887 clang_saveTranslationUnit(
1888 self.x,
1889 file.as_ptr(),
1890 clang_defaultSaveOptions(self.x),
1891 )
1892 };
1893 if ret != 0 {
1894 Err(ret)
1895 } else {
1896 Ok(())
1897 }
1898 }
1899
1900 pub(crate) fn is_null(&self) -> bool {
1902 self.x.is_null()
1903 }
1904}
1905
1906impl Drop for TranslationUnit {
1907 fn drop(&mut self) {
1908 unsafe {
1909 clang_disposeTranslationUnit(self.x);
1910 }
1911 }
1912}
1913
1914pub(crate) struct FallbackTranslationUnit {
1916 file_path: String,
1917 pch_path: String,
1918 idx: Box<Index>,
1919 tu: TranslationUnit,
1920}
1921
1922impl fmt::Debug for FallbackTranslationUnit {
1923 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1924 write!(fmt, "FallbackTranslationUnit {{ }}")
1925 }
1926}
1927
1928impl FallbackTranslationUnit {
1929 pub(crate) fn new(
1931 file: String,
1932 pch_path: String,
1933 c_args: &[Box<str>],
1934 ) -> Option<Self> {
1935 OpenOptions::new()
1937 .write(true)
1938 .create(true)
1939 .truncate(true)
1940 .open(&file)
1941 .ok()?;
1942
1943 let f_index = Box::new(Index::new(true, false));
1944 let f_translation_unit = TranslationUnit::parse(
1945 &f_index,
1946 &file,
1947 c_args,
1948 &[],
1949 CXTranslationUnit_None,
1950 )?;
1951 Some(FallbackTranslationUnit {
1952 file_path: file,
1953 pch_path,
1954 tu: f_translation_unit,
1955 idx: f_index,
1956 })
1957 }
1958
1959 pub(crate) fn translation_unit(&self) -> &TranslationUnit {
1961 &self.tu
1962 }
1963
1964 pub(crate) fn reparse(
1966 &mut self,
1967 unsaved_contents: &str,
1968 ) -> Result<(), CXErrorCode> {
1969 let unsaved = &[UnsavedFile::new(&self.file_path, unsaved_contents)];
1970 let mut c_unsaved: Vec<CXUnsavedFile> =
1971 unsaved.iter().map(|f| f.x).collect();
1972 let ret = unsafe {
1973 clang_reparseTranslationUnit(
1974 self.tu.x,
1975 unsaved.len() as c_uint,
1976 c_unsaved.as_mut_ptr(),
1977 clang_defaultReparseOptions(self.tu.x),
1978 )
1979 };
1980 if ret != 0 {
1981 Err(ret)
1982 } else {
1983 Ok(())
1984 }
1985 }
1986}
1987
1988impl Drop for FallbackTranslationUnit {
1989 fn drop(&mut self) {
1990 let _ = std::fs::remove_file(&self.file_path);
1991 let _ = std::fs::remove_file(&self.pch_path);
1992 }
1993}
1994
1995pub(crate) struct Diagnostic {
1997 x: CXDiagnostic,
1998}
1999
2000impl Diagnostic {
2001 pub(crate) fn format(&self) -> String {
2004 unsafe {
2005 let opts = clang_defaultDiagnosticDisplayOptions();
2006 cxstring_into_string(clang_formatDiagnostic(self.x, opts))
2007 }
2008 }
2009
2010 pub(crate) fn severity(&self) -> CXDiagnosticSeverity {
2012 unsafe { clang_getDiagnosticSeverity(self.x) }
2013 }
2014}
2015
2016impl Drop for Diagnostic {
2017 fn drop(&mut self) {
2019 unsafe {
2020 clang_disposeDiagnostic(self.x);
2021 }
2022 }
2023}
2024
2025pub(crate) struct UnsavedFile {
2027 x: CXUnsavedFile,
2028 pub(crate) name: CString,
2031 contents: CString,
2032}
2033
2034impl UnsavedFile {
2035 pub(crate) fn new(name: &str, contents: &str) -> UnsavedFile {
2037 let name = CString::new(name.as_bytes()).unwrap();
2038 let contents = CString::new(contents.as_bytes()).unwrap();
2039 let x = CXUnsavedFile {
2040 Filename: name.as_ptr(),
2041 Contents: contents.as_ptr(),
2042 Length: contents.as_bytes().len() as c_ulong,
2043 };
2044 UnsavedFile { x, name, contents }
2045 }
2046}
2047
2048impl fmt::Debug for UnsavedFile {
2049 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2050 write!(
2051 fmt,
2052 "UnsavedFile(name: {:?}, contents: {:?})",
2053 self.name, self.contents
2054 )
2055 }
2056}
2057
2058pub(crate) fn kind_to_str(x: CXCursorKind) -> String {
2060 unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) }
2061}
2062
2063pub(crate) fn type_to_str(x: CXTypeKind) -> String {
2065 unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) }
2066}
2067
2068pub(crate) fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
2070 fn print_indent<S: AsRef<str>>(depth: isize, s: S) {
2071 for _ in 0..depth {
2072 print!(" ");
2073 }
2074 println!("{}", s.as_ref());
2075 }
2076
2077 fn print_cursor<S: AsRef<str>>(depth: isize, prefix: S, c: &Cursor) {
2078 let prefix = prefix.as_ref();
2079 print_indent(
2080 depth,
2081 format!(" {prefix}kind = {}", kind_to_str(c.kind())),
2082 );
2083 print_indent(
2084 depth,
2085 format!(" {prefix}spelling = \"{}\"", c.spelling()),
2086 );
2087 print_indent(depth, format!(" {prefix}location = {}", c.location()));
2088 print_indent(
2089 depth,
2090 format!(" {prefix}is-definition? {}", c.is_definition()),
2091 );
2092 print_indent(
2093 depth,
2094 format!(" {prefix}is-declaration? {}", c.is_declaration()),
2095 );
2096 print_indent(
2097 depth,
2098 format!(
2099 " {prefix}is-inlined-function? {}",
2100 c.is_inlined_function()
2101 ),
2102 );
2103
2104 let templ_kind = c.template_kind();
2105 if templ_kind != CXCursor_NoDeclFound {
2106 print_indent(
2107 depth,
2108 format!(" {prefix}template-kind = {}", kind_to_str(templ_kind)),
2109 );
2110 }
2111 if let Some(usr) = c.usr() {
2112 print_indent(depth, format!(" {prefix}usr = \"{usr}\""));
2113 }
2114 if let Ok(num) = c.num_args() {
2115 print_indent(depth, format!(" {prefix}number-of-args = {num}"));
2116 }
2117 if let Some(num) = c.num_template_args() {
2118 print_indent(
2119 depth,
2120 format!(" {prefix}number-of-template-args = {num}"),
2121 );
2122 }
2123
2124 if c.is_bit_field() {
2125 let width = match c.bit_width() {
2126 Some(w) => w.to_string(),
2127 None => "<unevaluable>".to_string(),
2128 };
2129 print_indent(depth, format!(" {prefix}bit-width = {width}"));
2130 }
2131
2132 if let Some(ty) = c.enum_type() {
2133 print_indent(
2134 depth,
2135 format!(" {prefix}enum-type = {}", type_to_str(ty.kind())),
2136 );
2137 }
2138 if let Some(val) = c.enum_val_signed() {
2139 print_indent(depth, format!(" {prefix}enum-val = {val}"));
2140 }
2141 if let Some(ty) = c.typedef_type() {
2142 print_indent(
2143 depth,
2144 format!(" {prefix}typedef-type = {}", type_to_str(ty.kind())),
2145 );
2146 }
2147 if let Some(ty) = c.ret_type() {
2148 print_indent(
2149 depth,
2150 format!(" {prefix}ret-type = {}", type_to_str(ty.kind())),
2151 );
2152 }
2153
2154 if let Some(refd) = c.referenced() {
2155 if refd != *c {
2156 println!();
2157 print_cursor(
2158 depth,
2159 String::from(prefix) + "referenced.",
2160 &refd,
2161 );
2162 }
2163 }
2164
2165 let canonical = c.canonical();
2166 if canonical != *c {
2167 println!();
2168 print_cursor(
2169 depth,
2170 String::from(prefix) + "canonical.",
2171 &canonical,
2172 );
2173 }
2174
2175 if let Some(specialized) = c.specialized() {
2176 if specialized != *c {
2177 println!();
2178 print_cursor(
2179 depth,
2180 String::from(prefix) + "specialized.",
2181 &specialized,
2182 );
2183 }
2184 }
2185
2186 if let Some(parent) = c.fallible_semantic_parent() {
2187 println!();
2188 print_cursor(
2189 depth,
2190 String::from(prefix) + "semantic-parent.",
2191 &parent,
2192 );
2193 }
2194 }
2195
2196 fn print_type<S: AsRef<str>>(depth: isize, prefix: S, ty: &Type) {
2197 let prefix = prefix.as_ref();
2198
2199 let kind = ty.kind();
2200 print_indent(depth, format!(" {prefix}kind = {}", type_to_str(kind)));
2201 if kind == CXType_Invalid {
2202 return;
2203 }
2204
2205 print_indent(depth, format!(" {prefix}cconv = {}", ty.call_conv()));
2206
2207 print_indent(
2208 depth,
2209 format!(" {prefix}spelling = \"{}\"", ty.spelling()),
2210 );
2211 let num_template_args =
2212 unsafe { clang_Type_getNumTemplateArguments(ty.x) };
2213 if num_template_args >= 0 {
2214 print_indent(
2215 depth,
2216 format!(
2217 " {prefix}number-of-template-args = {num_template_args}"
2218 ),
2219 );
2220 }
2221 if let Some(num) = ty.num_elements() {
2222 print_indent(depth, format!(" {prefix}number-of-elements = {num}"));
2223 }
2224 print_indent(
2225 depth,
2226 format!(" {prefix}is-variadic? {}", ty.is_variadic()),
2227 );
2228
2229 let canonical = ty.canonical_type();
2230 if canonical != *ty {
2231 println!();
2232 print_type(depth, String::from(prefix) + "canonical.", &canonical);
2233 }
2234
2235 if let Some(pointee) = ty.pointee_type() {
2236 if pointee != *ty {
2237 println!();
2238 print_type(depth, String::from(prefix) + "pointee.", &pointee);
2239 }
2240 }
2241
2242 if let Some(elem) = ty.elem_type() {
2243 if elem != *ty {
2244 println!();
2245 print_type(depth, String::from(prefix) + "elements.", &elem);
2246 }
2247 }
2248
2249 if let Some(ret) = ty.ret_type() {
2250 if ret != *ty {
2251 println!();
2252 print_type(depth, String::from(prefix) + "return.", &ret);
2253 }
2254 }
2255
2256 let named = ty.named();
2257 if named != *ty && named.is_valid() {
2258 println!();
2259 print_type(depth, String::from(prefix) + "named.", &named);
2260 }
2261 }
2262
2263 print_indent(depth, "(");
2264 print_cursor(depth, "", c);
2265
2266 println!();
2267 let ty = c.cur_type();
2268 print_type(depth, "type.", &ty);
2269
2270 let declaration = ty.declaration();
2271 if declaration != *c && declaration.kind() != CXCursor_NoDeclFound {
2272 println!();
2273 print_cursor(depth, "type.declaration.", &declaration);
2274 }
2275
2276 let mut found_children = false;
2278 c.visit(|s| {
2279 if !found_children {
2280 println!();
2281 found_children = true;
2282 }
2283 ast_dump(&s, depth + 1)
2284 });
2285
2286 print_indent(depth, ")");
2287
2288 CXChildVisit_Continue
2289}
2290
2291pub(crate) fn extract_clang_version() -> String {
2293 unsafe { cxstring_into_string(clang_getClangVersion()) }
2294}
2295
2296#[derive(Debug)]
2298pub(crate) struct EvalResult {
2299 x: CXEvalResult,
2300 ty: Type,
2301}
2302
2303impl EvalResult {
2304 pub(crate) fn new(cursor: Cursor) -> Option<Self> {
2306 {
2310 let mut found_cant_eval = false;
2311 cursor.visit(|c| {
2312 if c.kind() == CXCursor_TypeRef &&
2313 c.cur_type().canonical_type().kind() == CXType_Unexposed
2314 {
2315 found_cant_eval = true;
2316 return CXChildVisit_Break;
2317 }
2318
2319 CXChildVisit_Recurse
2320 });
2321
2322 if found_cant_eval {
2323 return None;
2324 }
2325 }
2326 Some(EvalResult {
2327 x: unsafe { clang_Cursor_Evaluate(cursor.x) },
2328 ty: cursor.cur_type().canonical_type(),
2329 })
2330 }
2331
2332 fn kind(&self) -> CXEvalResultKind {
2333 unsafe { clang_EvalResult_getKind(self.x) }
2334 }
2335
2336 pub(crate) fn as_double(&self) -> Option<f64> {
2338 match self.kind() {
2339 CXEval_Float => {
2340 Some(unsafe { clang_EvalResult_getAsDouble(self.x) })
2341 }
2342 _ => None,
2343 }
2344 }
2345
2346 pub(crate) fn as_int(&self) -> Option<i64> {
2348 if self.kind() != CXEval_Int {
2349 return None;
2350 }
2351
2352 if unsafe { clang_EvalResult_isUnsignedInt(self.x) } != 0 {
2353 let value = unsafe { clang_EvalResult_getAsUnsigned(self.x) };
2354 if value > i64::MAX as c_ulonglong {
2355 return None;
2356 }
2357
2358 return Some(value as i64);
2359 }
2360
2361 let value = unsafe { clang_EvalResult_getAsLongLong(self.x) };
2362 if value > i64::MAX as c_longlong {
2363 return None;
2364 }
2365 if value < i64::MIN as c_longlong {
2366 return None;
2367 }
2368 #[allow(clippy::unnecessary_cast)]
2369 Some(value as i64)
2370 }
2371
2372 pub(crate) fn as_literal_string(&self) -> Option<Vec<u8>> {
2375 if self.kind() != CXEval_StrLiteral {
2376 return None;
2377 }
2378
2379 let char_ty = self.ty.pointee_type().or_else(|| self.ty.elem_type())?;
2380 match char_ty.kind() {
2381 CXType_Char_S | CXType_SChar | CXType_Char_U | CXType_UChar => {
2382 let ret = unsafe {
2383 CStr::from_ptr(clang_EvalResult_getAsStr(self.x))
2384 };
2385 Some(ret.to_bytes().to_vec())
2386 }
2387 CXType_Char16 => None,
2389 CXType_Char32 => None,
2390 CXType_WChar => None,
2391 _ => None,
2392 }
2393 }
2394}
2395
2396impl Drop for EvalResult {
2397 fn drop(&mut self) {
2398 unsafe { clang_EvalResult_dispose(self.x) };
2399 }
2400}
2401#[derive(Debug, Eq, PartialEq, Copy, Clone)]
2404pub(crate) enum ABIKind {
2405 GenericItanium,
2407 Microsoft,
2409}
2410
2411#[derive(Debug)]
2413pub(crate) struct TargetInfo {
2414 pub(crate) triple: String,
2416 pub(crate) pointer_width: usize,
2418 pub(crate) abi: ABIKind,
2420}
2421
2422impl TargetInfo {
2423 pub(crate) fn new(tu: &TranslationUnit) -> Self {
2425 let triple;
2426 let pointer_width;
2427 unsafe {
2428 let ti = clang_getTranslationUnitTargetInfo(tu.x);
2429 triple = cxstring_into_string(clang_TargetInfo_getTriple(ti));
2430 pointer_width = clang_TargetInfo_getPointerWidth(ti);
2431 clang_TargetInfo_dispose(ti);
2432 }
2433 assert!(pointer_width > 0);
2434 assert_eq!(pointer_width % 8, 0);
2435
2436 let abi = if triple.contains("msvc") {
2437 ABIKind::Microsoft
2438 } else {
2439 ABIKind::GenericItanium
2440 };
2441
2442 TargetInfo {
2443 triple,
2444 pointer_width: pointer_width as usize,
2445 abi,
2446 }
2447 }
2448}