Index: include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h =================================================================== --- include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h +++ include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h @@ -111,6 +111,21 @@ return true; } +#define DEF_TRAVERSE_TEMPLATE_DECL(TMPLDECLKIND) \ + bool Traverse##TMPLDECLKIND##TemplateDecl(TMPLDECLKIND##TemplateDecl *TD) { \ + if (!BaseType::TraverseTemplateParameterListHelper( \ + TD->getTemplateParameters())) \ + return false; \ + assert(!BaseType::getDerived().shouldVisitTemplateInstantiations() && \ + "It does not make sense for most clients to visit template " \ + "instantiations here."); \ + return BaseType::getDerived().TraverseDecl(TD->getTemplatedDecl()); \ + } + DEF_TRAVERSE_TEMPLATE_DECL(Class) + DEF_TRAVERSE_TEMPLATE_DECL(Var) + DEF_TRAVERSE_TEMPLATE_DECL(Function) +#undef DEF_TRAVERSE_TEMPLATE_DECL + private: bool TraverseAdditionalLexicallyNestedDeclarations() { // FIXME: Ideally the gathered declarations and the declarations in the Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -499,10 +499,10 @@ bool canIgnoreChildDeclWhileTraversingDeclContext(const Decl *Child); -private: // These are helper methods used by more than one Traverse* method. bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); +private: // Traverses template parameter lists of either a DeclaratorDecl or TagDecl. template bool TraverseDeclTemplateParameterLists(T *D); Index: unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp =================================================================== --- unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp +++ unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp @@ -21,8 +21,9 @@ : public LexicallyOrderedRecursiveASTVisitor { public: LexicallyOrderedDeclVisitor(DummyMatchVisitor &Matcher, - const SourceManager &SM) - : LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher) {} + const SourceManager &SM, bool EmitIndices) + : LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher), + EmitIndices(EmitIndices) {} bool TraverseDecl(Decl *D) { TraversalStack.push_back(D); @@ -35,15 +36,20 @@ private: DummyMatchVisitor &Matcher; + bool EmitIndices; + unsigned Index = 0; llvm::SmallVector TraversalStack; }; class DummyMatchVisitor : public ExpectedLocationVisitor { + bool EmitIndices; + public: + DummyMatchVisitor(bool EmitIndices = false) : EmitIndices(EmitIndices) {} bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) { const ASTContext &Context = TU->getASTContext(); const SourceManager &SM = Context.getSourceManager(); - LexicallyOrderedDeclVisitor SubVisitor(*this, SM); + LexicallyOrderedDeclVisitor SubVisitor(*this, SM, EmitIndices); SubVisitor.TraverseDecl(TU); return false; } @@ -64,9 +70,11 @@ OS << ND->getNameAsString(); else OS << "???"; - if (isa(D)) + if (isa(D) or isa(D)) OS << "/"; } + if (EmitIndices) + OS << "@" << Index++; Matcher.match(OS.str(), D); return true; } @@ -138,4 +146,18 @@ EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC)); } +TEST(LexicallyOrderedRecursiveASTVisitor, VisitTemplateDecl) { + StringRef Source = R"( +template T f(); +template class Class {}; +)"; + DummyMatchVisitor Visitor(/*EmitIndices=*/true); + Visitor.ExpectMatch("/f/T@0", 2, 11); + Visitor.ExpectMatch("/f/f/@1", 2, 20); + Visitor.ExpectMatch("/Class/U@2", 3, 11); + Visitor.ExpectMatch("/Class/@3", 3, 20); + Visitor.ExpectMatch("/Class/Class/@4", 3, 34); + EXPECT_TRUE(Visitor.runOver(Source)); +} + } // end anonymous namespace