Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -2454,7 +2454,8 @@ /// function. e.g. various subtypes of clang::Type and various expressions. /// /// Usable as: Matcher, Matcher, -/// Matcher, Matcher, Matcher, +/// Matcher, Matcher, Matcher, +/// Matcher, /// Matcher, Matcher, Matcher, /// Matcher, Matcher, Matcher, /// Matcher, Matcher, Index: include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- include/clang/ASTMatchers/ASTMatchersInternal.h +++ include/clang/ASTMatchers/ASTMatchersInternal.h @@ -744,16 +744,29 @@ if (Node.isNull()) return false; - if (auto *TD = Node->getAsTagDecl()) - return matchesDecl(TD, Finder, Builder); - else if (auto *TT = Node->getAs()) - return matchesDecl(TT->getDecl(), Finder, Builder); // Do not use getAs instead of the direct dyn_cast. // Calling getAs will return the canonical type, but that type does not // store a TemplateTypeParmDecl. We *need* the uncanonical type, if it is // available, and using dyn_cast ensures that. - else if (auto *TTP = dyn_cast(Node.getTypePtr())) + if (auto *TTP = dyn_cast(Node.getTypePtr())) return matchesDecl(TTP->getDecl(), Finder, Builder); + + // Try if any of desugaring results match + // (these are not mutually exclusive). + if (auto *TST = Node->getAs()) { + if (matchesSpecialized(*TST, Finder, Builder)) + return true; + } + if (auto *TT = Node->getAs()) { + if (matchesDecl(TT->getDecl(), Finder, Builder)) + return true; + } + + // Try non-desugarable types. + if (auto *TD = Node->getAsTagDecl()) + return matchesDecl(TD, Finder, Builder); + else if (auto *ET = Node->getAs()) + return matchesSpecialized(*ET, Finder, Builder); else if (auto *OCIT = Node->getAs()) return matchesDecl(OCIT->getDecl(), Finder, Builder); else if (auto *UUT = Node->getAs()) @@ -760,9 +773,18 @@ return matchesDecl(UUT->getDecl(), Finder, Builder); else if (auto *ICNT = Node->getAs()) return matchesDecl(ICNT->getDecl(), Finder, Builder); + return false; } + /// \brief Gets the QualType from ElaboratedType + /// and returns whether the inner matches on it. + bool matchesSpecialized(const ElaboratedType &Node, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return matchesSpecialized(Node.getNamedType(), Finder, Builder); + } + /// \brief Gets the TemplateDecl from a TemplateSpecializationType /// and returns whether the inner matches on it. bool matchesSpecialized(const TemplateSpecializationType &Node, @@ -1007,10 +1029,10 @@ TypeLoc, QualType> AdaptativeDefaultToTypes; /// \brief All types that are supported by HasDeclarationMatcher above. -typedef TypeList HasDeclarationSupportedTypes; /// \brief Converts a \c Matcher to a matcher of desired type \c To by Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -2106,5 +2106,56 @@ functionDecl(hasName("bar")))))); } +TEST(HasDeclaration, ElaboratedTypeAndTemplateSpecializationType) { + std::string input = + "namespace Namespace {\n" + "template\n" + "class Template {\n" + " public:\n" + " void Method() {}\n" + "};\n" + "} // namespace Namespace\n" + "template \n" + "void Function(Namespace::Template param) {\n" + " param.Method();\n" + "};\n"; + + // Matcher for ::Namespace::Template template decl. + auto param_type_decl_matcher = classTemplateDecl( + hasName("Template"), + hasParent(namespaceDecl(hasName("Namespace"))), + has(templateTypeParmDecl(hasName("T")))); + + // hasDeclaration / qualType-flavour. + EXPECT_TRUE(matches(input, parmVarDecl( + hasName("param"), + hasType(qualType(hasDeclaration(decl(param_type_decl_matcher))))))); + + // hasDeclaration / elaboratedType-flavour. + EXPECT_TRUE(matches(input, parmVarDecl( + hasName("param"), + hasType(elaboratedType(hasDeclaration(decl(param_type_decl_matcher))))))); +} + +TEST(HasDeclaration, TypedefTypeAndTemplateSpecializationTypeAreBothHere) { + std::string input = + "template\n" + "class Foo {};\n" + "using Bar = Foo;\n" + "Bar variable;\n"; + + // hasDeclaration should match typedefNameDecl. + EXPECT_TRUE(matches(input, varDecl( + hasName("variable"), + hasType(qualType(hasDeclaration(decl( + typeAliasDecl(hasName("Bar"))))))))); + + // hasDeclaration should match templateSpecializationType + EXPECT_TRUE(matches(input, varDecl( + hasName("variable"), + hasType(qualType(hasDeclaration(decl( + classTemplateSpecializationDecl()))))))); +} + } // namespace ast_matchers } // namespace clang