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
This commit is contained in:
Stephen Kelly 2020-11-02 23:56:32 +00:00
parent 90f0e87653
commit 7efe07a12b
6 changed files with 237 additions and 32 deletions

View File

@ -101,6 +101,8 @@ public:
// 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);
}

View File

@ -1060,7 +1060,7 @@ public:
virtual ASTContext &getASTContext() const = 0;
virtual bool isMatchingInImplicitTemplateInstantiation() const = 0;
virtual bool IsMatchingInTemplateInstantiationNotSpelledInSource() const = 0;
protected:
virtual bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,

View File

@ -500,6 +500,17 @@ public:
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 @@ public:
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:

View File

@ -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 =

View File

@ -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");
}
}

View File

@ -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(