forked from OSchip/llvm-project
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:
parent
90f0e87653
commit
7efe07a12b
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue