diff --git a/iwyu.cc b/iwyu.cc index c9dc3e3..436604a 100644 --- a/iwyu.cc +++ b/iwyu.cc @@ -2682,8 +2682,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor { // void fn(const S& 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() { diff --git a/iwyu_ast_util.cc b/iwyu_ast_util.cc index 047f3fc..189958a 100644 --- a/iwyu_ast_util.cc +++ b/iwyu_ast_util.cc @@ -547,12 +547,35 @@ class TypeEnumerator : public RecursiveASTVisitor { } // --- 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()) { + for (const TemplateArgument& arg : template_spec->template_arguments()) + TraverseTemplateArgument(arg); + } + } + set seen_types_; }; diff --git a/tests/cxx/template_args.cc b/tests/cxx/template_args.cc index f46177d..1b30551 100644 --- a/tests/cxx/template_args.cc +++ b/tests/cxx/template_args.cc @@ -80,6 +80,10 @@ void PointerClassArguments() { template struct Outer { T t; }; template struct Inner { T t; }; +struct StaticTemplateFieldStruct { + // IWYU: IndirectClass needs a declaration + static Inner tpl; +}; void NestedTemplateArguments() { // IWYU: IndirectClass needs a declaration @@ -94,6 +98,23 @@ void NestedTemplateArguments() { // IWYU: IndirectClass needs a declaration Outer >* 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 osi; + // Member referencing also requires template instantiation and nested member + // full-type-use reporting. + // IWYU: IndirectClass is...*indirect.h + (void)osi.t; + + Outer osip; + (void)osip.t; + + Outer* opsi; + // IWYU: IndirectClass is...*indirect.h + (void)opsi->t; } // ---------------------------------------------------------------