[clang] 7efe07a - Traverse-ignore explicit template instantiations

Stephen Kelly via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 6 07:27:11 PST 2020


Author: Stephen Kelly
Date: 2020-11-06T15:25:59Z
New Revision: 7efe07a12b6967bc358678adf75dffd238a00250

URL: https://github.com/llvm/llvm-project/commit/7efe07a12b6967bc358678adf75dffd238a00250
DIFF: https://github.com/llvm/llvm-project/commit/7efe07a12b6967bc358678adf75dffd238a00250.diff

LOG: Traverse-ignore explicit template instantiations

Continue to dump and match on explicit template specializations, but
omit explicit instantiation declarations and definitions.

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

Added: 
    

Modified: 
    clang/include/clang/AST/ASTNodeTraverser.h
    clang/include/clang/ASTMatchers/ASTMatchersInternal.h
    clang/lib/ASTMatchers/ASTMatchFinder.cpp
    clang/lib/ASTMatchers/ASTMatchersInternal.cpp
    clang/unittests/AST/ASTTraverserTest.cpp
    clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index 1141f514d795..c3c06bf37f3d 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -101,6 +101,8 @@ class ASTNodeTraverser
 
       // Decls within functions are visited by the body.
       if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) {
+        if (isa<ClassTemplateSpecializationDecl>(*D) && Traversal != TK_AsIs)
+          return;
         if (const auto *DC = dyn_cast<DeclContext>(D))
           dumpDeclContext(DC);
       }

diff  --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index 1f5951877f24..bd8174110910 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1060,7 +1060,7 @@ class ASTMatchFinder {
 
   virtual ASTContext &getASTContext() const = 0;
 
-  virtual bool isMatchingInImplicitTemplateInstantiation() const = 0;
+  virtual bool IsMatchingInTemplateInstantiationNotSpelledInSource() const = 0;
 
 protected:
   virtual bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,

diff  --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
index 2fa1a3f71eb5..67de0e14d18c 100644
--- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -500,6 +500,17 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
                           const DynTypedMatcher &Matcher,
                           BoundNodesTreeBuilder *Builder, int MaxDepth,
                           TraversalKind Traversal, BindKind Bind) {
+    bool ScopedTraversal = TraversingTemplateInstantiationNotSpelledInSource;
+
+    if (const auto *CTSD = Node.get<ClassTemplateSpecializationDecl>()) {
+      int SK = CTSD->getSpecializationKind();
+      if (SK == TSK_ExplicitInstantiationDeclaration ||
+          SK == TSK_ExplicitInstantiationDefinition)
+        ScopedTraversal = true;
+    }
+
+    TemplateInstantiationNotSpelledInSourceScope RAII(this, ScopedTraversal);
+
     MatchChildASTVisitor Visitor(
       &Matcher, this, Builder, MaxDepth, Traversal, Bind);
     return Visitor.findMatch(Node);
@@ -584,38 +595,38 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
   bool shouldVisitTemplateInstantiations() const { return true; }
   bool shouldVisitImplicitCode() const { return true; }
 
-  bool isMatchingInImplicitTemplateInstantiation() const override {
-    return TraversingImplicitTemplateInstantiation;
+  bool IsMatchingInTemplateInstantiationNotSpelledInSource() const override {
+    return TraversingTemplateInstantiationNotSpelledInSource;
   }
 
   bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {
-    ImplicitTemplateInstantiationScope RAII(this, true);
+    TemplateInstantiationNotSpelledInSourceScope RAII(this, true);
     return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
         D);
   }
 
   bool TraverseTemplateInstantiations(VarTemplateDecl *D) {
-    ImplicitTemplateInstantiationScope RAII(this, true);
+    TemplateInstantiationNotSpelledInSourceScope RAII(this, true);
     return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
         D);
   }
 
   bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {
-    ImplicitTemplateInstantiationScope RAII(this, true);
+    TemplateInstantiationNotSpelledInSourceScope RAII(this, true);
     return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
         D);
   }
 
 private:
-  bool TraversingImplicitTemplateInstantiation = false;
+  bool TraversingTemplateInstantiationNotSpelledInSource = false;
 
-  struct ImplicitTemplateInstantiationScope {
-    ImplicitTemplateInstantiationScope(MatchASTVisitor *V, bool B)
-        : MV(V), MB(V->TraversingImplicitTemplateInstantiation) {
-      V->TraversingImplicitTemplateInstantiation = B;
+  struct TemplateInstantiationNotSpelledInSourceScope {
+    TemplateInstantiationNotSpelledInSourceScope(MatchASTVisitor *V, bool B)
+        : MV(V), MB(V->TraversingTemplateInstantiationNotSpelledInSource) {
+      V->TraversingTemplateInstantiationNotSpelledInSource = B;
     }
-    ~ImplicitTemplateInstantiationScope() {
-      MV->TraversingImplicitTemplateInstantiation = MB;
+    ~TemplateInstantiationNotSpelledInSourceScope() {
+      MV->TraversingTemplateInstantiationNotSpelledInSource = MB;
     }
 
   private:

diff  --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index c319213d28ab..2e14ef28ecdb 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -286,7 +286,7 @@ bool DynTypedMatcher::matches(const DynTypedNode &DynNode,
 
   if (Finder->getASTContext().getParentMapContext().getTraversalKind() ==
           TK_IgnoreUnlessSpelledInSource &&
-      Finder->isMatchingInImplicitTemplateInstantiation())
+      Finder->IsMatchingInTemplateInstantiationNotSpelledInSource())
     return false;
 
   auto N =
@@ -311,7 +311,7 @@ bool DynTypedMatcher::matchesNoKindCheck(const DynTypedNode &DynNode,
 
   if (Finder->getASTContext().getParentMapContext().getTraversalKind() ==
           TK_IgnoreUnlessSpelledInSource &&
-      Finder->isMatchingInImplicitTemplateInstantiation())
+      Finder->IsMatchingInTemplateInstantiationNotSpelledInSource())
     return false;
 
   auto N =

diff  --git a/clang/unittests/AST/ASTTraverserTest.cpp b/clang/unittests/AST/ASTTraverserTest.cpp
index 6423b4d4cd4d..727a1ffa8395 100644
--- a/clang/unittests/AST/ASTTraverserTest.cpp
+++ b/clang/unittests/AST/ASTTraverserTest.cpp
@@ -1075,6 +1075,26 @@ void instantiate()
   (void)timesTwo<int>(2);
   (void)timesTwo<double>(2);
 }
+
+template class TemplStruct<float>;
+
+extern template class TemplStruct<long>;
+
+template<> class TemplStruct<bool> {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+  void foo() {}
+private:
+  bool m_t;
+};
+
+// Explicit instantiation of template functions do not appear in the AST
+template float timesTwo(float);
+
+template<> bool timesTwo<bool>(bool) {
+  return true;
+}
 )cpp");
   {
     auto BN = ast_matchers::match(
@@ -1121,18 +1141,48 @@ ClassTemplateDecl 'TemplStruct'
 | |-FieldDecl 'm_t'
 | `-CXXConstructorDecl 'TemplStruct'
 |   `-ParmVarDecl ''
+|-ClassTemplateSpecializationDecl 'TemplStruct'
+| |-TemplateArgument type double
+| | `-BuiltinType
+| |-CXXRecordDecl 'TemplStruct'
+| |-CXXConstructorDecl 'TemplStruct'
+| | `-CompoundStmt
+| |-CXXDestructorDecl '~TemplStruct'
+| | `-CompoundStmt
+| |-AccessSpecDecl
+| |-FieldDecl 'm_t'
+| `-CXXConstructorDecl 'TemplStruct'
+|   `-ParmVarDecl ''
+|-ClassTemplateSpecializationDecl 'TemplStruct'
+| |-TemplateArgument type float
+| | `-BuiltinType
+| |-CXXRecordDecl 'TemplStruct'
+| |-CXXConstructorDecl 'TemplStruct'
+| | `-CompoundStmt
+| |-CXXDestructorDecl '~TemplStruct'
+| | `-CompoundStmt
+| |-AccessSpecDecl
+| `-FieldDecl 'm_t'
+|-ClassTemplateSpecializationDecl 'TemplStruct'
+| |-TemplateArgument type long
+| | `-BuiltinType
+| |-CXXRecordDecl 'TemplStruct'
+| |-CXXConstructorDecl 'TemplStruct'
+| |-CXXDestructorDecl '~TemplStruct'
+| |-AccessSpecDecl
+| `-FieldDecl 'm_t'
 `-ClassTemplateSpecializationDecl 'TemplStruct'
-  |-TemplateArgument type double
+  |-TemplateArgument type _Bool
   | `-BuiltinType
   |-CXXRecordDecl 'TemplStruct'
   |-CXXConstructorDecl 'TemplStruct'
   | `-CompoundStmt
   |-CXXDestructorDecl '~TemplStruct'
   | `-CompoundStmt
+  |-CXXMethodDecl 'foo'
+  | `-CompoundStmt
   |-AccessSpecDecl
-  |-FieldDecl 'm_t'
-  `-CXXConstructorDecl 'TemplStruct'
-    `-ParmVarDecl ''
+  `-FieldDecl 'm_t'
 )cpp");
   }
   {
@@ -1176,17 +1226,72 @@ FunctionTemplateDecl 'timesTwo'
 |       |-ImplicitCastExpr
 |       | `-DeclRefExpr 'input'
 |       `-IntegerLiteral
+|-FunctionDecl 'timesTwo'
+| |-TemplateArgument type double
+| | `-BuiltinType
+| |-ParmVarDecl 'input'
+| `-CompoundStmt
+|   `-ReturnStmt
+|     `-BinaryOperator
+|       |-ImplicitCastExpr
+|       | `-DeclRefExpr 'input'
+|       `-ImplicitCastExpr
+|         `-IntegerLiteral
+|-FunctionDecl 'timesTwo'
+| |-TemplateArgument type float
+| | `-BuiltinType
+| |-ParmVarDecl 'input'
+| `-CompoundStmt
+|   `-ReturnStmt
+|     `-BinaryOperator
+|       |-ImplicitCastExpr
+|       | `-DeclRefExpr 'input'
+|       `-ImplicitCastExpr
+|         `-IntegerLiteral
+|-FunctionDecl 'timesTwo'
+| |-TemplateArgument type _Bool
+| | `-BuiltinType
+| |-ParmVarDecl ''
+| `-CompoundStmt
+|   `-ReturnStmt
+|     `-CXXBoolLiteralExpr
 `-FunctionDecl 'timesTwo'
-  |-TemplateArgument type double
+  |-TemplateArgument type _Bool
   | `-BuiltinType
-  |-ParmVarDecl 'input'
-  `-CompoundStmt
-    `-ReturnStmt
-      `-BinaryOperator
-        |-ImplicitCastExpr
-        | `-DeclRefExpr 'input'
-        `-ImplicitCastExpr
-          `-IntegerLiteral
+  `-ParmVarDecl 'input'
+)cpp");
+  }
+  {
+    auto BN = ast_matchers::match(
+        classTemplateSpecializationDecl(
+            hasName("TemplStruct"),
+            hasTemplateArgument(
+                0, templateArgument(refersToType(asString("float")))),
+            hasParent(translationUnitDecl()))
+            .bind("rec"),
+        AST->getASTContext());
+    EXPECT_EQ(BN.size(), 1u);
+
+    EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
+                            BN[0].getNodeAs<Decl>("rec")),
+              R"cpp(
+ClassTemplateSpecializationDecl 'TemplStruct'
+`-TemplateArgument type float
+  `-BuiltinType
+)cpp");
+
+    EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
+              R"cpp(
+ClassTemplateSpecializationDecl 'TemplStruct'
+|-TemplateArgument type float
+| `-BuiltinType
+|-CXXRecordDecl 'TemplStruct'
+|-CXXConstructorDecl 'TemplStruct'
+| `-CompoundStmt
+|-CXXDestructorDecl '~TemplStruct'
+| `-CompoundStmt
+|-AccessSpecDecl
+`-FieldDecl 'm_t'
 )cpp");
   }
 }

diff  --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index 13b5011bfe3e..a0d460cce66e 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -2214,6 +2214,23 @@ void instantiate()
   (void)timesTwo<double>(2);
 }
 
+template class TemplStruct<float>;
+
+extern template class TemplStruct<long>;
+
+template<> class TemplStruct<bool> {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+  void boolSpecializationMethodOnly() {}
+private:
+  bool m_t;
+};
+
+template float timesTwo(float);
+template<> bool timesTwo<bool>(bool){
+  return true;
+}
 )cpp";
   {
     auto M = cxxRecordDecl(hasName("TemplStruct"),
@@ -2241,6 +2258,77 @@ void instantiate()
     EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
     EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
   }
+  {
+    // Match on the integer literal in the explicit instantiation:
+    auto MDef =
+        functionDecl(hasName("timesTwo"),
+                     hasParameter(0, parmVarDecl(hasType(asString("float")))),
+                     hasDescendant(integerLiteral(equals(2))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MDef)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MDef)));
+
+    auto MTempl =
+        functionDecl(hasName("timesTwo"),
+                     hasTemplateArgument(0, refersToType(asString("float"))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MTempl)));
+    // TODO: If we could match on explicit instantiations of function templates,
+    // this would be EXPECT_TRUE.
+    EXPECT_FALSE(
+        matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MTempl)));
+  }
+  {
+    auto M = functionDecl(hasName("timesTwo"),
+                          hasParameter(0, parmVarDecl(hasType(booleanType()))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    // Match on the field within the explicit instantiation:
+    auto MRecord = cxxRecordDecl(hasName("TemplStruct"),
+                                 has(fieldDecl(hasType(asString("float")))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MRecord)));
+    EXPECT_FALSE(
+        matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MRecord)));
+
+    // Match on the explicit template instantiation itself:
+    auto MTempl = classTemplateSpecializationDecl(
+        hasName("TemplStruct"),
+        hasTemplateArgument(0,
+                            templateArgument(refersToType(asString("float")))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MTempl)));
+    EXPECT_TRUE(
+        matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MTempl)));
+  }
+  {
+    // The template argument is matchable, but the instantiation is not:
+    auto M = classTemplateSpecializationDecl(
+        hasName("TemplStruct"),
+        hasTemplateArgument(0,
+                            templateArgument(refersToType(asString("float")))),
+        has(cxxConstructorDecl(hasName("TemplStruct"))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
+  {
+    // The template argument is matchable, but the instantiation is not:
+    auto M = classTemplateSpecializationDecl(
+        hasName("TemplStruct"),
+        hasTemplateArgument(0,
+                            templateArgument(refersToType(asString("long")))),
+        has(cxxConstructorDecl(hasName("TemplStruct"))));
+    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(
+        hasName("TemplStruct"),
+        hasTemplateArgument(0, templateArgument(refersToType(booleanType()))),
+        has(cxxConstructorDecl(hasName("TemplStruct"))),
+        has(cxxMethodDecl(hasName("boolSpecializationMethodOnly"))));
+    EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+    EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+  }
 }
 
 template <typename MatcherT>
@@ -3249,10 +3337,9 @@ TEST(MatcherMemoize, HasDiffersFromHasDescendant) {
   EXPECT_TRUE(matches(
     code,
     cxxThrowExpr(hasDescendant(integerLiteral()))));
-  EXPECT_TRUE(notMatches(code, 
-    cxxThrowExpr(allOf(
-      hasDescendant(integerLiteral()),
-      has(integerLiteral())))));
+  EXPECT_TRUE(
+      notMatches(code, cxxThrowExpr(allOf(hasDescendant(integerLiteral()),
+                                          has(integerLiteral())))));
 }
 TEST(HasAncestor, MatchesAllAncestors) {
   EXPECT_TRUE(matches(


        


More information about the cfe-commits mailing list