// 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);
}
virtual ASTContext &getASTContext() const = 0;
- virtual bool isMatchingInImplicitTemplateInstantiation() const = 0;
+ virtual bool IsMatchingInTemplateInstantiationNotSpelledInSource() const = 0;
protected:
virtual bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
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);
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:
if (Finder->getASTContext().getParentMapContext().getTraversalKind() ==
TK_IgnoreUnlessSpelledInSource &&
- Finder->isMatchingInImplicitTemplateInstantiation())
+ Finder->IsMatchingInTemplateInstantiationNotSpelledInSource())
return false;
auto N =
if (Finder->getASTContext().getParentMapContext().getTraversalKind() ==
TK_IgnoreUnlessSpelledInSource &&
- Finder->isMatchingInImplicitTemplateInstantiation())
+ Finder->IsMatchingInTemplateInstantiationNotSpelledInSource())
return false;
auto N =
(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(
| |-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");
}
{
| |-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");
}
}
(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"),
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>
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(