[cfe-commits] PATCH: add an option to RecursiveASTVisitor to visit implicit declarations

James Dennett jdennett at googlers.com
Mon Jun 4 16:37:22 PDT 2012


Sometimes an AST visitor can be most straightforward if it can assume that
all decls that are referred to have been visited.  The current code doesn't
visit such nodes.  With the attached patch they are visited if an AST
visitor asks for it; this should have no effect for existing visitors
(unless they coincidentally happen to have a member
called shouldVisitImplicitDeclarations).

Any/all comments are welcome.

-- James
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120604/2933eb4e/attachment.html>
-------------- next part --------------
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h	(revision 157950)
+++ include/clang/AST/RecursiveASTVisitor.h	(working copy)
@@ -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,11 @@ bool RecursiveASTVisitor<Derived>::Trave
   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).
+  // The following code optionally traverses them.
+
+  if (!getDerived().shouldVisitImplicitDeclarations() && D->isImplicit())
     return true;
 
   switch (D->getKind()) {
@@ -1697,7 +1702,9 @@ bool RecursiveASTVisitor<Derived>::Trave
   // 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.
Index: unittests/Tooling/RecursiveASTVisitorTest.cpp
===================================================================
--- unittests/Tooling/RecursiveASTVisitorTest.cpp	(revision 157950)
+++ unittests/Tooling/RecursiveASTVisitorTest.cpp	(working copy)
@@ -448,4 +448,31 @@ TEST(RecursiveASTVisitor, VisitsClassTem
     "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


More information about the cfe-commits mailing list