Handle sugared template specs in template args

Non-sugared template specialization type template arguments are already
analyzed due to 'TraverseType' call inside
'InstantiatedTemplateVisitor::TraverseSubstTemplateTypeParmTypeHelper'
and subsequent 'TraverseTemplateSpecializationTypeHelper' call.
Components of sugared template specialization types are added into
resugar_map, otherwise their template arguments would not be reported.
Test case has been extended.
This commit is contained in:
Bolshakov 2022-09-18 21:45:33 +03:00 committed by Kim Gräsman
parent 06f7c21cbc
commit c3bcb661f6
3 changed files with 51 additions and 2 deletions

View File

@ -2682,8 +2682,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
// void fn(const S<Class>& s) { // Forward declarations are sufficient here.
// (void)s.t; // Full 'Class' type is needed due to template instantiation.
// }
void ReportTplSpecComponentTypes(const TemplateSpecializationType*) {
}
void ReportTplSpecComponentTypes(const TemplateSpecializationType*) = delete;
// Do not add any variables here! If you do, they will not be shared
// between the normal iwyu ast visitor and the
@ -3236,6 +3235,12 @@ class InstantiatedTemplateVisitor
return Base::VisitCXXConstructExpr(expr);
}
// --- Handler declared in IwyuBaseASTVisitor.
void ReportTplSpecComponentTypes(const TemplateSpecializationType* type) {
TraverseDataAndTypeMembersOfClassHelper(type);
}
private:
// Clears the state of the visitor.
void Clear() {

View File

@ -547,12 +547,35 @@ class TypeEnumerator : public RecursiveASTVisitor<TypeEnumerator> {
}
// --- Methods on RecursiveASTVisitor
bool TraverseType(QualType type) {
TraverseArgumentsOfSugaredTemplates(type);
return Base::TraverseType(type);
}
bool TraverseTypeLoc(TypeLoc type_loc) {
TraverseArgumentsOfSugaredTemplates(type_loc.getType());
return Base::TraverseTypeLoc(type_loc);
}
bool VisitType(Type* type) {
seen_types_.insert(type);
return true;
}
private:
// Clang doesn't traverse underlying type for most of the sugar types.
// If a TemplateSpecializationType occurs in a sugaring chain, traverse its
// arguments explicitly, otherwise they aren't put into resugar_map.
void TraverseArgumentsOfSugaredTemplates(QualType type) {
if (type.isNull())
return;
if (const auto* template_spec = type->getAs<TemplateSpecializationType>()) {
for (const TemplateArgument& arg : template_spec->template_arguments())
TraverseTemplateArgument(arg);
}
}
set<const Type*> seen_types_;
};

View File

@ -80,6 +80,10 @@ void PointerClassArguments() {
template<typename T> struct Outer { T t; };
template<typename T> struct Inner { T t; };
struct StaticTemplateFieldStruct {
// IWYU: IndirectClass needs a declaration
static Inner<IndirectClass> tpl;
};
void NestedTemplateArguments() {
// IWYU: IndirectClass needs a declaration
@ -94,6 +98,23 @@ void NestedTemplateArguments() {
// IWYU: IndirectClass needs a declaration
Outer<Inner<IndirectClass> >* opi;
(void)opi;
// Test that use of template specialization type template argument is not
// hidden by any sugar in the AST.
// IWYU: IndirectClass is...*indirect.h
Outer<decltype(StaticTemplateFieldStruct::tpl)> osi;
// Member referencing also requires template instantiation and nested member
// full-type-use reporting.
// IWYU: IndirectClass is...*indirect.h
(void)osi.t;
Outer<decltype(StaticTemplateFieldStruct::tpl)*> osip;
(void)osip.t;
Outer<decltype(StaticTemplateFieldStruct::tpl)>* opsi;
// IWYU: IndirectClass is...*indirect.h
(void)opsi->t;
}
// ---------------------------------------------------------------