Skip to content

Commit c8c2bdb

Browse files
committed
clang::Type::template_args return Option<TypeTemplateArgIterator>
1 parent 724aa06 commit c8c2bdb

File tree

3 files changed

+48
-26
lines changed

3 files changed

+48
-26
lines changed

src/clang.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -644,25 +644,22 @@ impl Type {
644644
Ok(Layout::new(size, align))
645645
}
646646

647-
/// If this type is a class template specialization, return its number of
647+
/// If this type is a class template specialization, return its
648648
/// template arguments. Otherwise, return None.
649-
pub fn num_template_args(&self) -> Option<u32> {
649+
pub fn template_args(&self) -> Option<TypeTemplateArgIterator> {
650650
let n = unsafe { clang_Type_getNumTemplateArguments(self.x) };
651651
if n >= 0 {
652-
Some(n as u32)
652+
Some(TypeTemplateArgIterator {
653+
x: self.x,
654+
length: n as u32,
655+
index: 0
656+
})
653657
} else {
654658
debug_assert_eq!(n, -1);
655659
None
656660
}
657661
}
658662

659-
/// Get the type of the `i`th template argument for this template
660-
/// specialization.
661-
pub fn template_arg_type(&self, i: u32) -> Type {
662-
let n = i as c_int;
663-
Type { x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, n) } }
664-
}
665-
666663
/// Given that this type is a pointer type, return the type that it points
667664
/// to.
668665
pub fn pointee_type(&self) -> Type {
@@ -747,6 +744,33 @@ impl Type {
747744
}
748745
}
749746

747+
/// An iterator for a type's template arguments.
748+
pub struct TypeTemplateArgIterator {
749+
x: CXType,
750+
length: u32,
751+
index: u32
752+
}
753+
754+
impl Iterator for TypeTemplateArgIterator {
755+
type Item = Type;
756+
fn next(&mut self) -> Option<Type> {
757+
if self.index < self.length {
758+
let idx = self.index as c_int;
759+
self.index += 1;
760+
Some(Type { x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) } })
761+
} else {
762+
None
763+
}
764+
}
765+
}
766+
767+
impl ExactSizeIterator for TypeTemplateArgIterator {
768+
fn len(&self) -> usize {
769+
assert!(self.index <= self.length);
770+
(self.length - self.index) as usize
771+
}
772+
}
773+
750774
/// A `SourceLocation` is a file, line, column, and byte offset location for
751775
/// some source text.
752776
pub struct SourceLocation {

src/ir/comp.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -489,26 +489,24 @@ impl CompInfo {
489489

490490
let mut ci = CompInfo::new(kind);
491491
ci.is_anonymous = cursor.is_anonymous();
492-
ci.template_args = match ty.num_template_args() {
492+
ci.template_args = match ty.template_args() {
493493
// In forward declarations and not specializations, etc, they are in
494494
// the ast, we'll meet them in CXCursor_TemplateTypeParameter
495495
None => vec![],
496-
Some(len) => {
497-
let mut list = Vec::with_capacity(len as usize);
498-
for i in 0..len {
499-
let arg_type = ty.template_arg_type(i);
500-
if arg_type.kind() != CXType_Invalid {
501-
let type_id =
502-
Item::from_ty_or_ref(arg_type, None, None, ctx);
503-
504-
list.push(type_id);
505-
} else {
506-
ci.has_non_type_template_params = true;
507-
warn!("warning: Template parameter is not a type");
508-
}
496+
Some(arg_types) => {
497+
let num_arg_types = arg_types.len();
498+
499+
let args = arg_types
500+
.filter(|t| t.kind() != CXType_Invalid)
501+
.map(|t| Item::from_ty_or_ref(t, None, None, ctx))
502+
.collect::<Vec<_>>();
503+
504+
if args.len() != num_arg_types {
505+
ci.has_non_type_template_params = true;
506+
warn!("warning: Template parameter is not a type");
509507
}
510508

511-
list
509+
args
512510
}
513511
};
514512

src/ir/ty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ impl Type {
506506
TypeKind::Function(signature)
507507
// Same here, with template specialisations we can safely assume
508508
// this is a Comp(..)
509-
} else if ty.num_template_args().unwrap_or(0) > 0 {
509+
} else if ty.template_args().map_or(false, |x| x.len() > 0) {
510510
debug!("Template specialization: {:?}", ty);
511511
let complex =
512512
CompInfo::from_ty(potential_id, ty, location, ctx)

0 commit comments

Comments
 (0)