Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -482,6 +482,13 @@ private: // These are helper methods used by more than one Traverse* method. bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); + + // Traverses template parameter lists of either a DeclaratorDecl or TagDecl. + template ::value || + std::is_base_of::value>::type> + bool TraverseDeclTemplateParameterLists(T *D); + #define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \ bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D); DEF_TRAVERSE_TMPL_INST(Class) @@ -1532,6 +1539,16 @@ } template +template +bool RecursiveASTVisitor::TraverseDeclTemplateParameterLists(T *D) { + for (unsigned i = 0; i < D->getNumTemplateParameterLists(); i++) { + TemplateParameterList *TPL = D->getTemplateParameterList(i); + TraverseTemplateParameterListHelper(TPL); + } + return true; +} + +template bool RecursiveASTVisitor::TraverseTemplateInstantiations( ClassTemplateDecl *D) { for (auto *SD : D->specializations()) { @@ -1692,6 +1709,8 @@ }) DEF_TRAVERSE_DECL(EnumDecl, { + TRY_TO(TraverseDeclTemplateParameterLists(D)); + if (D->getTypeForDecl()) TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); @@ -1706,6 +1725,7 @@ // We shouldn't traverse D->getTypeForDecl(); it's a result of // declaring the type, not something that was written in the source. + TRY_TO(TraverseDeclTemplateParameterLists(D)); TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); return true; } @@ -1800,6 +1820,7 @@ template bool RecursiveASTVisitor::TraverseDeclaratorHelper(DeclaratorDecl *D) { + TRY_TO(TraverseDeclTemplateParameterLists(D)); TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); if (D->getTypeSourceInfo()) TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); @@ -1846,6 +1867,7 @@ template bool RecursiveASTVisitor::TraverseFunctionHelper(FunctionDecl *D) { + TRY_TO(TraverseDeclTemplateParameterLists(D)); TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -1720,6 +1720,68 @@ "}\n", declRefExpr(to(decl(hasAncestor(decl())))))); } + +AST_MATCHER_P(QualType, + hasUnderlyingType, + internal::Matcher, + InnerMatcher) { + const Type* type = Node.getTypePtrOrNull(); + return type && InnerMatcher.matches(*type, Finder, Builder); +} + +TEST(HasAncestor, TemplateTypeParmDeclUnderCXXMethodDecl) { + EXPECT_TRUE(matches( + "template\n" + "class Class {\n" + " void method();\n" + "};\n" + "template\n" + "void Class::method() {}\n", + qualType(hasUnderlyingType(templateTypeParmType(hasDeclaration(decl( + hasAncestor(decl())))))))); +} + +TEST(HasAncestor, TemplateTypeParmDeclUnderVarDecl) { + EXPECT_TRUE(matches( + "template\n" + "class Class {\n" + " static T pi;\n" + "};\n" + "template\n" + "U Class::pi = U(3.1415926535897932385);\n", + qualType(hasUnderlyingType(templateTypeParmType(hasDeclaration(decl( + hasAncestor(decl())))))))); +} + +TEST(HasAncestor, TemplateTypeParmDeclUnderEnumDecl) { + EXPECT_TRUE(matches( + "template\n" + "struct Struct {\n" + " enum class Enum : T;\n" + "};\n" + "template\n" + "enum class Struct::Enum : U {\n" + " e1,\n" + " e2\n" + "};\n", + qualType(hasUnderlyingType(templateTypeParmType(hasDeclaration(decl( + hasAncestor(decl())))))))); +} + +TEST(HasAncestor, TemplateTypeParmDeclUnderStructDecl) { + EXPECT_TRUE(matches( + "template\n" + "class Class {\n" + " struct Struct;\n" + "};\n" + "template\n" + "struct Class::Struct {\n" + " U field;\n" + "};\n", + qualType(hasUnderlyingType(templateTypeParmType(hasDeclaration(decl( + hasAncestor(decl())))))))); +} + TEST(HasAncestor, NonParmDependentTemplateParmVarDeclRefExpr) { EXPECT_TRUE(matches("struct PartitionAllocator {\n" " template\n"