diff options
-rw-r--r-- | include/clang/AST/RecursiveASTVisitor.h | 15 | ||||
-rw-r--r-- | unittests/Tooling/RecursiveASTVisitorTest.cpp | 27 |
2 files changed, 37 insertions, 5 deletions
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 72f24a09a5..b1db07af17 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -148,6 +148,10 @@ public: /// TypeLocs. bool shouldWalkTypesOfTypeLocs() const { return true; } + /// \brief Return whether this visitor should recurse into implicit + /// declarations, e.g., implicit constructors and destructors. + bool shouldVisitImplicitDeclarations() const { return false; } + /// \brief Return whether \param S should be traversed using data recursion /// to avoid a stack overflow with extreme cases. bool shouldUseDataRecursionFor(Stmt *S) const { @@ -601,10 +605,9 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) { if (!D) return true; - // As a syntax visitor, we want to ignore declarations for - // implicitly-defined declarations (ones not typed explicitly by the - // user). - if (D->isImplicit()) + // As a syntax visitor, by default we want to ignore declarations for + // implicit declarations (ones not typed explicitly by the user). + if (!getDerived().shouldVisitImplicitDeclarations() && D->isImplicit()) return true; switch (D->getKind()) { @@ -1697,7 +1700,9 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) { // FunctionNoProtoType or FunctionProtoType, or a typedef. This // also covers the return type and the function parameters, // including exception specifications. - TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + if (clang::TypeSourceInfo *TSI = D->getTypeSourceInfo()) { + TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); + } if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { // Constructor initializers. diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp index 9ad825f8cf..52b3987bc8 100644 --- a/unittests/Tooling/RecursiveASTVisitorTest.cpp +++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp @@ -448,4 +448,31 @@ TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) { "template<template <typename> class T> class Y {};\n")); } +// A visitor that visits implicit declarations and matches constructors. +class ImplicitCtorVisitor + : public ExpectedLocationVisitor<ImplicitCtorVisitor> { +public: + bool shouldVisitImplicitDeclarations() const { return true; } + + bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) { + if (Ctor->isImplicit()) { // Was not written in source code + if (const CXXRecordDecl* Class = Ctor->getParent()) { + Match(Class->getName(), Ctor->getLocation()); + } + } + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) { + ImplicitCtorVisitor Visitor; + Visitor.ExpectMatch("Simple", 2, 8); + // Note: Clang lazily instantiates implicit declarations, so we need + // to use them in order to force them to appear in the AST. + EXPECT_TRUE(Visitor.runOver( + "struct WithCtor { WithCtor(); }; \n" + "struct Simple { Simple(); WithCtor w; }; \n" + "int main() { Simple s; Simple t(s); }\n")); +} + } // end namespace clang |