diff --git a/iwyu.cc b/iwyu.cc index 7b3e0b8be..013d5619f 100644 --- a/iwyu.cc +++ b/iwyu.cc @@ -230,6 +230,7 @@ using clang::Preprocessor; using clang::QualType; using clang::QualifiedTypeLoc; using clang::RecordDecl; +using clang::RecordType; using clang::RecursiveASTVisitor; using clang::ReferenceType; using clang::Sema; @@ -2602,10 +2603,9 @@ class IwyuBaseAstVisitor : public BaseAstVisitor { dyn_cast(component)) { const NamedDecl* decl = TypeToDeclAsWritten(tpl_spec_type); if (const auto* al_tpl_decl = dyn_cast(decl)) { - const TypeAliasDecl* al_decl = al_tpl_decl->getTemplatedDecl(); - InsertAllInto(GetProvidedTypes(tpl_spec_type->desugar().getTypePtr(), - GetLocation(al_decl)), - &retval); + InsertAllInto( + GetAliasTemplateProvidedTypes(tpl_spec_type, al_tpl_decl), + &retval); continue; } } @@ -2653,6 +2653,16 @@ class IwyuBaseAstVisitor : public BaseAstVisitor { bool SourceOrTargetTypeIsProvided(const ASTNode* construct_expr_node) const = delete; + set GetAliasTemplateProvidedTypes( + const TemplateSpecializationType* type, + const TypeAliasTemplateDecl* al_tpl_decl) const { + const TypeAliasDecl* al_decl = al_tpl_decl->getTemplatedDecl(); + set res = GetProvidedTypes(type->getAliasedType().getTypePtr(), + GetLocation(al_decl)); + RemoveAllFrom(GetCanonicalArgComponents(type), &res); + return res; + } + void ReportTypeUseInternal(SourceLocation used_loc, const Type* type, set blocked_types, DerefKind deref_kind) { @@ -2729,10 +2739,10 @@ class IwyuBaseAstVisitor : public BaseAstVisitor { if (template_spec_type->isTypeAlias()) { const NamedDecl* decl = TypeToDeclAsWritten(template_spec_type); if (const auto* al_tpl_decl = dyn_cast(decl)) { - const TypeAliasDecl* al_decl = al_tpl_decl->getTemplatedDecl(); + InsertAllInto( + GetAliasTemplateProvidedTypes(template_spec_type, al_tpl_decl), + &blocked_types); const Type* type = template_spec_type->getAliasedType().getTypePtr(); - InsertAllInto(GetProvidedTypes(type, GetLocation(al_decl)), - &blocked_types); ReportTypeUseInternal(used_loc, type, blocked_types, deref_kind); } return; @@ -3262,6 +3272,22 @@ class InstantiatedTemplateVisitor return Base::VisitSubstTemplateTypeParmType(type); } + bool VisitRecordType(RecordType* type) { + if (CanIgnoreCurrentASTNode() || CanIgnoreType(type)) + return true; + + // CanForwardDeclareType function relies on the specific placement of + // the type node in the AST. An intermediate SubstTemplateTypeParmType could + // break that logic. However, such cases don't even need to be considered + // here, because they are handled in VisitSubstTemplateTypeParmType. But + // maybe using AncestorIsA, or replacing VisitSubst...Type with + // TraverseSubst...Type and Traverse...TypeLoc would be more reliable. + if (!current_ast_node()->ParentIsA()) + AnalyzeTemplateTypeParmUse(type); + + return Base::VisitRecordType(type); + } + bool VisitTemplateSpecializationType(TemplateSpecializationType* type) { if (CanIgnoreCurrentASTNode()) return true; diff --git a/iwyu_ast_util.cc b/iwyu_ast_util.cc index 8bc27edad..208ecb1f1 100644 --- a/iwyu_ast_util.cc +++ b/iwyu_ast_util.cc @@ -148,6 +148,7 @@ using llvm::errs; using llvm::isa; using llvm::raw_string_ostream; using std::function; +using std::vector; namespace include_what_you_use { @@ -1617,6 +1618,17 @@ bool CanBeOpaqueDeclared(const EnumType* type) { return type->getDecl()->isFixed(); } +vector GetCanonicalArgComponents( + const TemplateSpecializationType* type) { + vector res; + SugaredTypeEnumerator enumerator; + for (const TemplateArgument& arg : type->template_arguments()) { + for (const Type* component : enumerator.Enumerate(arg)) + res.push_back(GetCanonicalType(component)); + } + return res; +} + // --- Utilities for Stmt. bool IsAddressOf(const Expr* expr) { diff --git a/iwyu_ast_util.h b/iwyu_ast_util.h index 046108a96..607c757d5 100644 --- a/iwyu_ast_util.h +++ b/iwyu_ast_util.h @@ -16,6 +16,7 @@ #include // for map #include // for set #include // for string +#include // for vector #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" @@ -858,6 +859,11 @@ TemplateInstantiationData GetTplInstDataForClassNoComponentTypes( // according to the standard. bool CanBeOpaqueDeclared(const clang::EnumType* type); +// Collects template argument type components and returns them desugared. +// The result may contain duplicates. +std::vector GetCanonicalArgComponents( + const clang::TemplateSpecializationType*); + // --- Utilities for Stmt. // Returns true if the given expr is '&'. diff --git a/tests/cxx/typedef_chain_in_template-d5.h b/tests/cxx/typedef_chain_in_template-d5.h index 9b7862749..8ddd5b3c7 100644 --- a/tests/cxx/typedef_chain_in_template-d5.h +++ b/tests/cxx/typedef_chain_in_template-d5.h @@ -28,3 +28,8 @@ struct Tpl { using TplWithNonProvidedAliased1 = Tpl; using TplWithNonProvidedAliased2 = Tpl>; + +class TypedefChainClass; + +template +using NonProvidingAliasByOther = IdentityAlias2; diff --git a/tests/cxx/typedef_chain_in_template-i1.h b/tests/cxx/typedef_chain_in_template-i1.h index ffc196449..0b7fbe5bb 100644 --- a/tests/cxx/typedef_chain_in_template-i1.h +++ b/tests/cxx/typedef_chain_in_template-i1.h @@ -18,4 +18,7 @@ struct TypedefWrapper { typedef value_type& reference; }; +template +using IdentityAlias2 = T; + #endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_TYPEDEF_CHAIN_IN_TEMPLATE_I1_H_ diff --git a/tests/cxx/typedef_chain_in_template.cc b/tests/cxx/typedef_chain_in_template.cc index cae0b9ff2..1f9a948a4 100644 --- a/tests/cxx/typedef_chain_in_template.cc +++ b/tests/cxx/typedef_chain_in_template.cc @@ -74,6 +74,11 @@ void Fn() { (void)sizeof(TplWithNonProvidedAliased1); // IWYU: TypedefChainClass is...*typedef_chain_class.h (void)sizeof(TplWithNonProvidedAliased2); + + // IWYU: TypedefChainClass is...*typedef_chain_class.h + NonProvidingAliasByOther<1> npabo; + // IWYU: TypedefChainClass is...*typedef_chain_class.h + npabo.Method(); } /**** IWYU_SUMMARY @@ -89,6 +94,6 @@ The full include-list for tests/cxx/typedef_chain_in_template.cc: #include "tests/cxx/typedef_chain_in_template-d2.h" // for ContainerAsLibcpp #include "tests/cxx/typedef_chain_in_template-d3.h" // for ContainerShortTypedefChain #include "tests/cxx/typedef_chain_in_template-d4.h" // for ContainerLongTypedefChain -#include "tests/cxx/typedef_chain_in_template-d5.h" // for IdentityAliasComplex, IdentityStructComplex, TplWithNonProvidedAliased1, TplWithNonProvidedAliased2 +#include "tests/cxx/typedef_chain_in_template-d5.h" // for IdentityAliasComplex, IdentityStructComplex, NonProvidingAliasByOther, TplWithNonProvidedAliased1, TplWithNonProvidedAliased2 ***** IWYU_SUMMARY */