Skip to content

Commit 9c8b593

Browse files
author
bors-servo
authored
Auto merge of #472 - fitzgen:cursor-num-template-args, r=emilio
Make Cursor::num_template_args slightly more reliable This improves the situation slightly, but even `clang_Type_getNumTemplateArgs` doesn't work for most templates... r? @emilio
2 parents f4b1309 + 2723539 commit 9c8b593

File tree

1 file changed

+40
-17
lines changed

1 file changed

+40
-17
lines changed

src/clang.rs

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -122,20 +122,37 @@ impl Cursor {
122122
}
123123

124124
/// Return the number of template arguments used by this cursor's referent,
125-
/// if the referent is either a template specialization or
126-
/// declaration. Returns -1 otherwise.
125+
/// if the referent is either a template specialization or declaration.
126+
/// Returns `None` otherwise.
127127
///
128128
/// NOTE: This may not return `Some` for some non-fully specialized
129129
/// templates, see #193 and #194.
130130
pub fn num_template_args(&self) -> Option<u32> {
131-
let n: c_int = unsafe { clang_Cursor_getNumTemplateArguments(self.x) };
131+
// XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while
132+
// `clang_Cursor_getNumTemplateArguments` is totally unreliable.
133+
// Therefore, try former first, and only fallback to the latter if we
134+
// have to.
135+
self.cur_type().num_template_args()
136+
.or_else(|| {
137+
let n: c_int = unsafe {
138+
clang_Cursor_getNumTemplateArguments(self.x)
139+
};
132140

133-
if n >= 0 {
134-
Some(n as u32)
135-
} else {
136-
debug_assert_eq!(n, -1);
137-
None
138-
}
141+
if n >= 0 {
142+
Some(n as u32)
143+
} else {
144+
debug_assert_eq!(n, -1);
145+
None
146+
}
147+
})
148+
.or_else(|| {
149+
let canonical = self.canonical();
150+
if canonical != *self {
151+
canonical.num_template_args()
152+
} else {
153+
None
154+
}
155+
})
139156
}
140157

141158
/// Get a cursor pointing to this referent's containing translation unit.
@@ -672,22 +689,28 @@ impl Type {
672689
Ok(Layout::new(size, align))
673690
}
674691

675-
/// If this type is a class template specialization, return its
676-
/// template arguments. Otherwise, return None.
677-
pub fn template_args(&self) -> Option<TypeTemplateArgIterator> {
692+
/// Get the number of template arguments this type has, or `None` if it is
693+
/// not some kind of template.
694+
pub fn num_template_args(&self) -> Option<u32> {
678695
let n = unsafe { clang_Type_getNumTemplateArguments(self.x) };
679696
if n >= 0 {
680-
Some(TypeTemplateArgIterator {
681-
x: self.x,
682-
length: n as u32,
683-
index: 0,
684-
})
697+
Some(n as u32)
685698
} else {
686699
debug_assert_eq!(n, -1);
687700
None
688701
}
689702
}
690703

704+
/// If this type is a class template specialization, return its
705+
/// template arguments. Otherwise, return None.
706+
pub fn template_args(&self) -> Option<TypeTemplateArgIterator> {
707+
self.num_template_args().map(|n| TypeTemplateArgIterator {
708+
x: self.x,
709+
length: n,
710+
index: 0,
711+
})
712+
}
713+
691714
/// Given that this type is a pointer type, return the type that it points
692715
/// to.
693716
pub fn pointee_type(&self) -> Option<Type> {

0 commit comments

Comments
 (0)