@@ -136,11 +136,11 @@ impl Cursor {
136
136
// `clang_Cursor_getNumTemplateArguments` is totally unreliable.
137
137
// Therefore, try former first, and only fallback to the latter if we
138
138
// have to.
139
- self . cur_type ( ) . num_template_args ( )
139
+ self . cur_type ( )
140
+ . num_template_args ( )
140
141
. or_else ( || {
141
- let n: c_int = unsafe {
142
- clang_Cursor_getNumTemplateArguments ( self . x )
143
- } ;
142
+ let n: c_int =
143
+ unsafe { clang_Cursor_getNumTemplateArguments ( self . x ) } ;
144
144
145
145
if n >= 0 {
146
146
Some ( n as u32 )
@@ -360,6 +360,41 @@ impl Cursor {
360
360
}
361
361
}
362
362
363
+ /// Collect all of this cursor's children into a vec and return them.
364
+ pub fn collect_children ( & self ) -> Vec < Cursor > {
365
+ let mut children = vec ! [ ] ;
366
+ self . visit ( |c| {
367
+ children. push ( c) ;
368
+ CXChildVisit_Continue
369
+ } ) ;
370
+ children
371
+ }
372
+
373
+ /// Does this cursor have any children?
374
+ pub fn has_children ( & self ) -> bool {
375
+ let mut has_children = false ;
376
+ self . visit ( |_| {
377
+ has_children = true ;
378
+ CXChildVisit_Break
379
+ } ) ;
380
+ has_children
381
+ }
382
+
383
+ /// Does this cursor have at least `n` children?
384
+ pub fn has_at_least_num_children ( & self , n : usize ) -> bool {
385
+ assert ! ( n > 0 ) ;
386
+ let mut num_left = n;
387
+ self . visit ( |_| {
388
+ num_left -= 1 ;
389
+ if num_left == 0 {
390
+ CXChildVisit_Break
391
+ } else {
392
+ CXChildVisit_Continue
393
+ }
394
+ } ) ;
395
+ num_left == 0
396
+ }
397
+
363
398
/// Returns whether the given location contains a cursor with the given
364
399
/// kind in the first level of nesting underneath (doesn't look
365
400
/// recursively).
@@ -581,7 +616,7 @@ impl Hash for Cursor {
581
616
}
582
617
583
618
/// The type of a node in clang's AST.
584
- #[ derive( Clone ) ]
619
+ #[ derive( Clone , Copy ) ]
585
620
pub struct Type {
586
621
x : CXType ,
587
622
}
@@ -657,6 +692,31 @@ impl Type {
657
692
}
658
693
}
659
694
695
+ /// Get the canonical declaration of this type, if it is available.
696
+ pub fn canonical_declaration ( & self ,
697
+ location : Option < & Cursor > )
698
+ -> Option < CanonicalTypeDeclaration > {
699
+ let mut declaration = self . declaration ( ) ;
700
+ if !declaration. is_valid ( ) {
701
+ if let Some ( location) = location {
702
+ let mut location = * location;
703
+ if let Some ( referenced) = location. referenced ( ) {
704
+ location = referenced;
705
+ }
706
+ if location. is_template_like ( ) {
707
+ declaration = location;
708
+ }
709
+ }
710
+ }
711
+
712
+ let canonical = declaration. canonical ( ) ;
713
+ if canonical. is_valid ( ) && canonical. kind ( ) != CXCursor_NoDeclFound {
714
+ Some ( CanonicalTypeDeclaration ( * self , canonical) )
715
+ } else {
716
+ None
717
+ }
718
+ }
719
+
660
720
/// Get a raw display name for this type.
661
721
pub fn spelling ( & self ) -> String {
662
722
unsafe { cxstring_into_string ( clang_getTypeSpelling ( self . x ) ) }
@@ -731,10 +791,12 @@ impl Type {
731
791
/// If this type is a class template specialization, return its
732
792
/// template arguments. Otherwise, return None.
733
793
pub fn template_args ( & self ) -> Option < TypeTemplateArgIterator > {
734
- self . num_template_args ( ) . map ( |n| TypeTemplateArgIterator {
735
- x : self . x ,
736
- length : n,
737
- index : 0 ,
794
+ self . num_template_args ( ) . map ( |n| {
795
+ TypeTemplateArgIterator {
796
+ x : self . x ,
797
+ length : n,
798
+ index : 0 ,
799
+ }
738
800
} )
739
801
}
740
802
@@ -836,9 +898,8 @@ impl Type {
836
898
// Yep, the spelling of this containing type-parameter is extremely
837
899
// nasty... But can happen in <type_traits>. Unfortunately I couldn't
838
900
// reduce it enough :(
839
- self . template_args ( ) . map_or ( false , |args| {
840
- args. len ( ) > 0
841
- } ) && match self . declaration ( ) . kind ( ) {
901
+ self . template_args ( ) . map_or ( false , |args| args. len ( ) > 0 ) &&
902
+ match self . declaration ( ) . kind ( ) {
842
903
CXCursor_ClassTemplatePartialSpecialization |
843
904
CXCursor_TypeAliasTemplateDecl |
844
905
CXCursor_TemplateTemplateParameter => false ,
@@ -847,6 +908,26 @@ impl Type {
847
908
}
848
909
}
849
910
911
+ /// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its
912
+ /// cursor is the canonical declaration for its type. If you have a
913
+ /// `CanonicalTypeDeclaration` instance, you know for sure that the type and
914
+ /// cursor match up in a canonical declaration relationship, and it simply
915
+ /// cannot be otherwise.
916
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
917
+ pub struct CanonicalTypeDeclaration ( Type , Cursor ) ;
918
+
919
+ impl CanonicalTypeDeclaration {
920
+ /// Get the type.
921
+ pub fn ty ( & self ) -> & Type {
922
+ & self . 0
923
+ }
924
+
925
+ /// Get the type's canonical declaration cursor.
926
+ pub fn cursor ( & self ) -> & Cursor {
927
+ & self . 1
928
+ }
929
+ }
930
+
850
931
/// An iterator for a type's template arguments.
851
932
pub struct TypeTemplateArgIterator {
852
933
x : CXType ,
@@ -1389,7 +1470,10 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
1389
1470
type_to_str( ty. kind( ) ) ) ) ;
1390
1471
}
1391
1472
if let Some ( ty) = c. ret_type ( ) {
1392
- print_indent ( depth, format ! ( " {}ret-type = {}" , prefix, type_to_str( ty. kind( ) ) ) ) ;
1473
+ print_indent ( depth,
1474
+ format ! ( " {}ret-type = {}" ,
1475
+ prefix,
1476
+ type_to_str( ty. kind( ) ) ) ) ;
1393
1477
}
1394
1478
1395
1479
if let Some ( refd) = c. referenced ( ) {
@@ -1398,7 +1482,9 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
1398
1482
print_cursor ( depth,
1399
1483
String :: from ( prefix) + "referenced." ,
1400
1484
& refd) ;
1401
- print_cursor ( depth, String :: from ( prefix) + "referenced." , & refd) ;
1485
+ print_cursor ( depth,
1486
+ String :: from ( prefix) + "referenced." ,
1487
+ & refd) ;
1402
1488
}
1403
1489
}
1404
1490
@@ -1408,7 +1494,9 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
1408
1494
print_cursor ( depth,
1409
1495
String :: from ( prefix) + "canonical." ,
1410
1496
& canonical) ;
1411
- print_cursor ( depth, String :: from ( prefix) + "canonical." , & canonical) ;
1497
+ print_cursor ( depth,
1498
+ String :: from ( prefix) + "canonical." ,
1499
+ & canonical) ;
1412
1500
}
1413
1501
1414
1502
if let Some ( specialized) = c. specialized ( ) {
@@ -1417,7 +1505,9 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
1417
1505
print_cursor ( depth,
1418
1506
String :: from ( prefix) + "specialized." ,
1419
1507
& specialized) ;
1420
- print_cursor ( depth, String :: from ( prefix) + "specialized." , & specialized) ;
1508
+ print_cursor ( depth,
1509
+ String :: from ( prefix) + "specialized." ,
1510
+ & specialized) ;
1421
1511
}
1422
1512
}
1423
1513
}
0 commit comments