[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