]> granicus.if.org Git - clang/commitdiff
[AST] Traverse templates in LexicallyOrderedRecursiveASTVisitor
authorJohannes Altmanninger <aclopte@gmail.com>
Wed, 6 Sep 2017 13:11:13 +0000 (13:11 +0000)
committerJohannes Altmanninger <aclopte@gmail.com>
Wed, 6 Sep 2017 13:11:13 +0000 (13:11 +0000)
Summary:
We need to specialize this because RecursiveASTVisitor visits template
template parameters after the templated declaration, unlike the order in
which they appear in the source code.

Reviewers: arphaman

Reviewed By: arphaman

Subscribers: klimek, cfe-commits

Differential Revision: https://reviews.llvm.org/D36998

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@312631 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
include/clang/AST/RecursiveASTVisitor.h
unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp

index 7d2029de0213d875d2ba7f6cbb2134916d91a48b..538e072385397548a7c8d8706beb425a91f98931 100644 (file)
@@ -111,6 +111,8 @@ public:
     return true;
   }
 
+  bool shouldTraverseTemplateArgumentsBeforeDecl() const { return true; }
+
 private:
   bool TraverseAdditionalLexicallyNestedDeclarations() {
     // FIXME: Ideally the gathered declarations and the declarations in the
index fbb30673174e942a3b8e54582f5d1031de59b47c..f628c340327c085bb32676cc173739729a4029dc 100644 (file)
@@ -535,6 +535,7 @@ private:
 
   bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue);
   bool PostVisitStmt(Stmt *S);
+  bool shouldTraverseTemplateArgumentsBeforeDecl() const { return false; }
 };
 
 template <typename Derived>
@@ -1688,8 +1689,13 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
 // template declarations.
 #define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND)                                   \
   DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, {                              \
-    TRY_TO(TraverseDecl(D->getTemplatedDecl()));                               \
-    TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));   \
+    if (getDerived().shouldTraverseTemplateArgumentsBeforeDecl()) {            \
+      TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \
+      TRY_TO(TraverseDecl(D->getTemplatedDecl()));                             \
+    } else {                                                                   \
+      TRY_TO(TraverseDecl(D->getTemplatedDecl()));                             \
+      TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \
+    }                                                                          \
                                                                                \
     /* By default, we do not traverse the instantiations of                    \
        class templates since they do not appear in the user code. The          \
index 72aa6042af12fab421128ef7bd8d8a23375888ff..2f2c5d6ee18894884a578f740e90b8d63c9ef278 100644 (file)
@@ -21,8 +21,9 @@ class LexicallyOrderedDeclVisitor
     : public LexicallyOrderedRecursiveASTVisitor<LexicallyOrderedDeclVisitor> {
 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 @@ public:
 
 private:
   DummyMatchVisitor &Matcher;
+  bool EmitIndices;
+  unsigned Index = 0;
   llvm::SmallVector<Decl *, 8> TraversalStack;
 };
 
 class DummyMatchVisitor : public ExpectedLocationVisitor<DummyMatchVisitor> {
+  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 @@ bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) {
       OS << ND->getNameAsString();
     else
       OS << "???";
-    if (isa<DeclContext>(D))
+    if (isa<DeclContext>(D) or isa<TemplateDecl>(D))
       OS << "/";
   }
+  if (EmitIndices)
+    OS << "@" << Index++;
   Matcher.match(OS.str(), D);
   return true;
 }
@@ -138,4 +146,18 @@ MACRO_F(2)
   EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
 }
 
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitTemplateDecl) {
+  StringRef Source = R"(
+template <class T> T f();
+template <class U, class = void> class Class {};
+)";
+  DummyMatchVisitor Visitor(/*EmitIndices=*/true);
+  Visitor.ExpectMatch("/f/T@1", 2, 11);
+  Visitor.ExpectMatch("/f/f/@2", 2, 20);
+  Visitor.ExpectMatch("/Class/U@4", 3, 11);
+  Visitor.ExpectMatch("/Class/@5", 3, 20);
+  Visitor.ExpectMatch("/Class/Class/@6", 3, 34);
+  EXPECT_TRUE(Visitor.runOver(Source));
+}
+
 } // end anonymous namespace