bool getDeserialize() const { return Deserialize; }
void SetTraversalKind(TraversalKind TK) { Traversal = TK; }
- TraversalKind GetTraversalKind() const { return Traversal; }
void Visit(const Decl *D) {
getNodeDelegate().AddChild([=] {
Visit(D->getTemplatedDecl());
- if (Traversal == TK_AsIs) {
- for (const auto *Child : D->specializations())
- dumpTemplateDeclSpecialization(Child);
- }
+ for (const auto *Child : D->specializations())
+ dumpTemplateDeclSpecialization(Child);
}
void VisitTypeAliasDecl(const TypeAliasDecl *D) {
bool canIgnoreChildDeclWhileTraversingDeclContext(const Decl *Child);
-#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
- bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D);
- DEF_TRAVERSE_TMPL_INST(Class)
- DEF_TRAVERSE_TMPL_INST(Var)
- DEF_TRAVERSE_TMPL_INST(Function)
-#undef DEF_TRAVERSE_TMPL_INST
-
private:
// These are helper methods used by more than one Traverse* method.
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
template <typename T>
bool TraverseDeclTemplateParameterLists(T *D);
+#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \
+ bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D);
+ DEF_TRAVERSE_TMPL_INST(Class)
+ DEF_TRAVERSE_TMPL_INST(Var)
+ DEF_TRAVERSE_TMPL_INST(Function)
+#undef DEF_TRAVERSE_TMPL_INST
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
unsigned Count);
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
return this->InnerMatcher.matches(DynTypedNode::create(*Node), Finder,
Builder);
}
-
- llvm::Optional<clang::TraversalKind> TraversalKind() const override {
- return this->InnerMatcher.getTraversalKind();
- }
};
private:
virtual ASTContext &getASTContext() const = 0;
- virtual bool isMatchingInImplicitTemplateInstantiation() const = 0;
-
protected:
virtual bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
const DynTypedMatcher &Matcher,
Visit(D->getTemplatedDecl());
- if (GetTraversalKind() == TK_AsIs) {
- for (const auto *Child : D->specializations())
- dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
- !D->isCanonicalDecl());
- }
+ for (const auto *Child : D->specializations())
+ dumpTemplateDeclSpecialization(Child, DumpExplicitInst,
+ !D->isCanonicalDecl());
}
void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
- bool isMatchingInImplicitTemplateInstantiation() const override {
- return TraversingImplicitTemplateInstantiation;
- }
-
- bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {
- ImplicitTemplateInstantiationScope RAII(this, true);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
- D);
- }
-
- bool TraverseTemplateInstantiations(VarTemplateDecl *D) {
- ImplicitTemplateInstantiationScope RAII(this, true);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
- D);
- }
-
- bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {
- ImplicitTemplateInstantiationScope RAII(this, true);
- return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
- D);
- }
-
private:
- bool TraversingImplicitTemplateInstantiation = false;
-
- struct ImplicitTemplateInstantiationScope {
- ImplicitTemplateInstantiationScope(MatchASTVisitor *V, bool B)
- : MV(V), MB(V->TraversingImplicitTemplateInstantiation) {
- V->TraversingImplicitTemplateInstantiation = B;
- }
- ~ImplicitTemplateInstantiationScope() {
- MV->TraversingImplicitTemplateInstantiation = MB;
- }
-
- private:
- MatchASTVisitor *MV;
- bool MB;
- };
-
class TimeBucketRegion {
public:
TimeBucketRegion() : Bucket(nullptr) {}
TraversalKindScope RAII(Finder->getASTContext(),
Implementation->TraversalKind());
- if (Finder->getASTContext().getParentMapContext().getTraversalKind() ==
- TK_IgnoreUnlessSpelledInSource &&
- Finder->isMatchingInImplicitTemplateInstantiation())
- return false;
-
auto N =
Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode);
TraversalKindScope raii(Finder->getASTContext(),
Implementation->TraversalKind());
- if (Finder->getASTContext().getParentMapContext().getTraversalKind() ==
- TK_IgnoreUnlessSpelledInSource &&
- Finder->isMatchingInImplicitTemplateInstantiation())
- return false;
-
auto N =
Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode);
void Visit(const TemplateArgument &A, SourceRange R = {},
const Decl *From = nullptr, const char *Label = nullptr) {
OS << "TemplateArgument";
- switch (A.getKind()) {
- case TemplateArgument::Type: {
- OS << " type " << A.getAsType().getAsString();
- break;
- }
- default:
- break;
- }
}
template <typename... T> void Visit(T...) {}
verifyWithDynNode(TA,
R"cpp(
-TemplateArgument type int
+TemplateArgument
`-BuiltinType
)cpp");
}
}
-TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) {
-
- auto AST = buildASTFromCode(R"cpp(
-template<typename T>
-struct TemplStruct {
- TemplStruct() {}
- ~TemplStruct() {}
-
-private:
- T m_t;
-};
-
-template<typename T>
-T timesTwo(T input)
-{
- return input * 2;
-}
-
-void instantiate()
-{
- TemplStruct<int> ti;
- TemplStruct<double> td;
- (void)timesTwo<int>(2);
- (void)timesTwo<double>(2);
-}
-)cpp");
- {
- auto BN = ast_matchers::match(
- classTemplateDecl(hasName("TemplStruct")).bind("rec"),
- AST->getASTContext());
- EXPECT_EQ(BN.size(), 1u);
-
- EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
- BN[0].getNodeAs<Decl>("rec")),
- R"cpp(
-ClassTemplateDecl 'TemplStruct'
-|-TemplateTypeParmDecl 'T'
-`-CXXRecordDecl 'TemplStruct'
- |-CXXRecordDecl 'TemplStruct'
- |-CXXConstructorDecl 'TemplStruct<T>'
- | `-CompoundStmt
- |-CXXDestructorDecl '~TemplStruct<T>'
- | `-CompoundStmt
- |-AccessSpecDecl
- `-FieldDecl 'm_t'
-)cpp");
-
- EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
- R"cpp(
-ClassTemplateDecl 'TemplStruct'
-|-TemplateTypeParmDecl 'T'
-|-CXXRecordDecl 'TemplStruct'
-| |-CXXRecordDecl 'TemplStruct'
-| |-CXXConstructorDecl 'TemplStruct<T>'
-| | `-CompoundStmt
-| |-CXXDestructorDecl '~TemplStruct<T>'
-| | `-CompoundStmt
-| |-AccessSpecDecl
-| `-FieldDecl 'm_t'
-|-ClassTemplateSpecializationDecl 'TemplStruct'
-| |-TemplateArgument type int
-| | `-BuiltinType
-| |-CXXRecordDecl 'TemplStruct'
-| |-CXXConstructorDecl 'TemplStruct'
-| | `-CompoundStmt
-| |-CXXDestructorDecl '~TemplStruct'
-| | `-CompoundStmt
-| |-AccessSpecDecl
-| |-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 ''
-)cpp");
- }
- {
- auto BN = ast_matchers::match(
- functionTemplateDecl(hasName("timesTwo")).bind("fn"),
- AST->getASTContext());
- EXPECT_EQ(BN.size(), 1u);
-
- EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
- BN[0].getNodeAs<Decl>("fn")),
- R"cpp(
-FunctionTemplateDecl 'timesTwo'
-|-TemplateTypeParmDecl 'T'
-`-FunctionDecl 'timesTwo'
- |-ParmVarDecl 'input'
- `-CompoundStmt
- `-ReturnStmt
- `-BinaryOperator
- |-DeclRefExpr 'input'
- `-IntegerLiteral
-)cpp");
-
- EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),
- R"cpp(
-FunctionTemplateDecl 'timesTwo'
-|-TemplateTypeParmDecl 'T'
-|-FunctionDecl 'timesTwo'
-| |-ParmVarDecl 'input'
-| `-CompoundStmt
-| `-ReturnStmt
-| `-BinaryOperator
-| |-DeclRefExpr 'input'
-| `-IntegerLiteral
-|-FunctionDecl 'timesTwo'
-| |-TemplateArgument type int
-| | `-BuiltinType
-| |-ParmVarDecl 'input'
-| `-CompoundStmt
-| `-ReturnStmt
-| `-BinaryOperator
-| |-ImplicitCastExpr
-| | `-DeclRefExpr 'input'
-| `-IntegerLiteral
-`-FunctionDecl 'timesTwo'
- |-TemplateArgument type double
- | `-BuiltinType
- |-ParmVarDecl 'input'
- `-CompoundStmt
- `-ReturnStmt
- `-BinaryOperator
- |-ImplicitCastExpr
- | `-DeclRefExpr 'input'
- `-ImplicitCastExpr
- `-IntegerLiteral
-)cpp");
- }
-}
-
} // namespace clang
traverse(TK_AsIs,
staticAssertDecl(has(implicitCastExpr(has(
substNonTypeTemplateParmExpr(has(integerLiteral())))))))));
- EXPECT_TRUE(matches(
- Code, traverse(TK_IgnoreUnlessSpelledInSource,
- staticAssertDecl(has(declRefExpr(
- to(nonTypeTemplateParmDecl(hasName("alignment"))),
- hasType(asString("unsigned int"))))))));
- EXPECT_TRUE(matches(Code, traverse(TK_AsIs, staticAssertDecl(hasDescendant(
- integerLiteral())))));
- EXPECT_FALSE(matches(
- Code, traverse(TK_IgnoreUnlessSpelledInSource,
- staticAssertDecl(hasDescendant(integerLiteral())))));
+ EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource,
+ staticAssertDecl(has(integerLiteral())))));
Code = R"cpp(
EXPECT_EQ(ErrorCount, 0);
}
-TEST_F(TransformerTest, TemplateInstantiation) {
-
- std::string NonTemplatesInput = R"cpp(
-struct S {
- int m_i;
-};
-)cpp";
- std::string NonTemplatesExpected = R"cpp(
-struct S {
- safe_int m_i;
-};
-)cpp";
-
- std::string TemplatesInput = R"cpp(
-template<typename T>
-struct TemplStruct {
- TemplStruct() {}
- ~TemplStruct() {}
-
-private:
- T m_t;
-};
-
-void instantiate()
-{
- TemplStruct<int> ti;
-}
-)cpp";
-
- auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField");
-
- // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct':
- testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField),
- changeTo(cat("safe_int ", name("theField")))),
- NonTemplatesInput + TemplatesInput,
- NonTemplatesExpected + TemplatesInput);
-
- // In AsIs mode, template instantiations are modified, which is
- // often not desired:
-
- std::string IncorrectTemplatesExpected = R"cpp(
-template<typename T>
-struct TemplStruct {
- TemplStruct() {}
- ~TemplStruct() {}
-
-private:
- safe_int m_t;
-};
-
-void instantiate()
-{
- TemplStruct<int> ti;
-}
-)cpp";
-
- // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct':
- testRule(makeRule(traverse(TK_AsIs, MatchedField),
- changeTo(cat("safe_int ", name("theField")))),
-
- NonTemplatesInput + TemplatesInput,
- NonTemplatesExpected + IncorrectTemplatesExpected);
-}
-
// Transformation of macro source text when the change encompasses the entirety
// of the expanded text.
TEST_F(TransformerTest, SimpleMacro) {