diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -1167,6 +1167,8 @@ } else if (const auto *FD = dyn_cast(DeclNode)) { if (FD->isDefaulted()) ScopedChildren = true; + if (FD->isTemplateInstantiation()) + ScopedTraversal = true; } ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -2201,10 +2201,18 @@ TemplStruct() {} ~TemplStruct() {} + void outOfLine(T); + private: T m_t; }; +template +void TemplStruct::outOfLine(T) +{ + +} + template T timesTwo(T input) { @@ -2278,6 +2286,7 @@ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MTempl))); // TODO: If we could match on explicit instantiations of function templates, // this would be EXPECT_TRUE. + // See Sema::ActOnExplicitInstantiation, EXPECT_FALSE( matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MTempl))); } @@ -2324,6 +2333,14 @@ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); } + { + // Instantiated, out-of-line methods are not matchable + auto M = + cxxMethodDecl(hasName("outOfLine"), isDefinition(), + hasParameter(0, parmVarDecl(hasType(asString("float"))))); + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); + EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); + } { // Explicit specialization is written in source and it matches: auto M = classTemplateSpecializationDecl(