[cfe-commits] r156339 - /cfe/trunk/tools/libclang/RecursiveASTVisitor.h

Argyrios Kyrtzidis akyrtzi at gmail.com
Mon May 7 16:23:04 PDT 2012


Author: akirtzidis
Date: Mon May  7 18:23:03 2012
New Revision: 156339

URL: http://llvm.org/viewvc/llvm-project?rev=156339&view=rev
Log:
[libclang] Actually commit the changes to make libclang's RecursiveASTVisitor
data-recursive for statements.

Modified:
    cfe/trunk/tools/libclang/RecursiveASTVisitor.h

Modified: cfe/trunk/tools/libclang/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/RecursiveASTVisitor.h?rev=156339&r1=156338&r2=156339&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/RecursiveASTVisitor.h (original)
+++ cfe/trunk/tools/libclang/RecursiveASTVisitor.h Mon May  7 18:23:03 2012
@@ -115,6 +115,9 @@
 /// node are grouped together.  In other words, Visit*() methods for
 /// different nodes are never interleaved.
 ///
+/// Stmts are traversed internally using a data queue to avoid a stack overflow
+/// with hugely nested ASTs.
+///
 /// Clients of this visitor should subclass the visitor (providing
 /// themselves as the template argument, using the curiously recurring
 /// template pattern) and override any of the Traverse*, WalkUpFrom*,
@@ -149,13 +152,6 @@
   /// TypeLocs.
   bool shouldWalkTypesOfTypeLocs() const { return true; }
 
-  /// \brief Return whether \param S should be traversed using data recursion
-  /// to avoid a stack overflow with extreme cases.
-  bool shouldUseDataRecursionFor(Stmt *S) const {
-    return isa<BinaryOperator>(S) || isa<UnaryOperator>(S) ||
-           isa<CaseStmt>(S) || isa<CXXOperatorCallExpr>(S);
-  }
-
   /// \brief Recursively visit a statement or expression, by
   /// dispatching to Traverse*() based on the argument's dynamic type.
   ///
@@ -268,7 +264,8 @@
 #define OPERATOR(NAME)                                           \
   bool TraverseUnary##NAME(UnaryOperator *S) {                  \
     TRY_TO(WalkUpFromUnary##NAME(S));                           \
-    TRY_TO(TraverseStmt(S->getSubExpr()));                      \
+    StmtQueueAction StmtQueue(*this);                           \
+    StmtQueue.queue(S->getSubExpr());                           \
     return true;                                                \
   }                                                             \
   bool WalkUpFromUnary##NAME(UnaryOperator *S) {                \
@@ -287,8 +284,9 @@
 #define GENERAL_BINOP_FALLBACK(NAME, BINOP_TYPE)                \
   bool TraverseBin##NAME(BINOP_TYPE *S) {                       \
     TRY_TO(WalkUpFromBin##NAME(S));                             \
-    TRY_TO(TraverseStmt(S->getLHS()));                          \
-    TRY_TO(TraverseStmt(S->getRHS()));                          \
+    StmtQueueAction StmtQueue(*this);                           \
+    StmtQueue.queue(S->getLHS());                               \
+    StmtQueue.queue(S->getRHS());                               \
     return true;                                                \
   }                                                             \
   bool WalkUpFromBin##NAME(BINOP_TYPE *S) {                     \
@@ -394,8 +392,8 @@
 private:
   // These are helper methods used by more than one Traverse* method.
   bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
-  bool TraverseClassInstantiations(ClassTemplateDecl* D, Decl *Pattern);
-  bool TraverseFunctionInstantiations(FunctionTemplateDecl* D) ;
+  bool TraverseClassInstantiations(ClassTemplateDecl *D);
+  bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ;
   bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
                                           unsigned Count);
   bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
@@ -406,100 +404,39 @@
   bool TraverseFunctionHelper(FunctionDecl *D);
   bool TraverseVarHelper(VarDecl *D);
 
-  bool Walk(Stmt *S);
+  typedef SmallVector<Stmt *, 16> StmtsTy;
+  typedef SmallVector<StmtsTy *, 4> QueuesTy;
+  
+  QueuesTy Queues;
 
-  struct EnqueueJob {
-    Stmt *S;
-    Stmt::child_iterator StmtIt;
-
-    EnqueueJob(Stmt *S) : S(S), StmtIt() {
-      if (Expr *E = dyn_cast_or_null<Expr>(S))
-        S = E->IgnoreParens();
+  class NewQueueRAII {
+    RecursiveASTVisitor &RAV;
+  public:
+    NewQueueRAII(StmtsTy &queue, RecursiveASTVisitor &RAV) : RAV(RAV) {
+      RAV.Queues.push_back(&queue);
     }
-  };
-  bool dataTraverse(Stmt *S);
-};
-
-template<typename Derived>
-bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) {
-
-  SmallVector<EnqueueJob, 16> Queue;
-  Queue.push_back(S);
-
-  while (!Queue.empty()) {
-    EnqueueJob &job = Queue.back();
-    Stmt *CurrS = job.S;
-    if (!CurrS) {
-      Queue.pop_back();
-      continue;
-    }
-
-    if (getDerived().shouldUseDataRecursionFor(CurrS)) {
-      if (job.StmtIt == Stmt::child_iterator()) {
-        if (!Walk(CurrS)) return false;
-        job.StmtIt = CurrS->child_begin();
-      } else {
-        ++job.StmtIt;
-      }
-
-      if (job.StmtIt != CurrS->child_end())
-        Queue.push_back(*job.StmtIt);
-      else
-        Queue.pop_back();
-      continue;
+    ~NewQueueRAII() {
+      RAV.Queues.pop_back();
     }
+  };
 
-    Queue.pop_back();
-    TRY_TO(TraverseStmt(CurrS));
+  StmtsTy &getCurrentQueue() {
+    assert(!Queues.empty() && "base TraverseStmt was never called?");
+    return *Queues.back();
   }
 
-  return true;
-}
-
-template<typename Derived>
-bool RecursiveASTVisitor<Derived>::Walk(Stmt *S) {
-
-#define DISPATCH_WALK(NAME, CLASS, VAR) \
-  return getDerived().WalkUpFrom##NAME(static_cast<CLASS*>(VAR));
-
-  if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
-    switch (BinOp->getOpcode()) {
-#define OPERATOR(NAME) \
-    case BO_##NAME: DISPATCH_WALK(Bin##NAME, BinaryOperator, S);
-
-    BINOP_LIST()
-#undef OPERATOR
-
-#define OPERATOR(NAME)                                          \
-    case BO_##NAME##Assign:                          \
-    DISPATCH_WALK(Bin##NAME##Assign, CompoundAssignOperator, S);
-
-    CAO_LIST()
-#undef OPERATOR
-    }
-  } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
-    switch (UnOp->getOpcode()) {
-#define OPERATOR(NAME)                                                  \
-    case UO_##NAME: DISPATCH_WALK(Unary##NAME, UnaryOperator, S);
+public:
+  class StmtQueueAction {
+    StmtsTy &CurrQueue;
+  public:
+    explicit StmtQueueAction(RecursiveASTVisitor &RAV)
+      : CurrQueue(RAV.getCurrentQueue()) { }
 
-    UNARYOP_LIST()
-#undef OPERATOR
+    void queue(Stmt *S) {
+      CurrQueue.push_back(S);
     }
-  }
-
-  // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt.
-  switch (S->getStmtClass()) {
-  case Stmt::NoStmtClass: break;
-#define ABSTRACT_STMT(STMT)
-#define STMT(CLASS, PARENT) \
-  case Stmt::CLASS##Class: DISPATCH_WALK(CLASS, CLASS, S);
-#include "clang/AST/StmtNodes.inc"
-  }
-
-#undef DISPATCH_WALK
-
-  return true;
-}
+  };
+};
 
 #define DISPATCH(NAME, CLASS, VAR) \
   return getDerived().Traverse##NAME(static_cast<CLASS*>(VAR))
@@ -509,47 +446,65 @@
   if (!S)
     return true;
 
-  if (getDerived().shouldUseDataRecursionFor(S))
-    return dataTraverse(S);
+  StmtsTy Queue, StmtsToEnqueu;
+  Queue.push_back(S);
+  NewQueueRAII NQ(StmtsToEnqueu, *this);
 
-  // If we have a binary expr, dispatch to the subcode of the binop.  A smart
-  // optimizer (e.g. LLVM) will fold this comparison into the switch stmt
-  // below.
-  if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
-    switch (BinOp->getOpcode()) {
-#define OPERATOR(NAME) \
-    case BO_##NAME: DISPATCH(Bin##NAME, BinaryOperator, S);
+  while (!Queue.empty()) {
+    S = Queue.pop_back_val();
+    if (!S)
+      continue;
+
+    StmtsToEnqueu.clear();
 
-    BINOP_LIST()
+#define DISPATCH_STMT(NAME, CLASS, VAR) \
+    TRY_TO(Traverse##NAME(static_cast<CLASS*>(VAR))); break
+
+    // If we have a binary expr, dispatch to the subcode of the binop.  A smart
+    // optimizer (e.g. LLVM) will fold this comparison into the switch stmt
+    // below.
+    if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
+      switch (BinOp->getOpcode()) {
+#define OPERATOR(NAME) \
+      case BO_##NAME: DISPATCH_STMT(Bin##NAME, BinaryOperator, S);
+  
+      BINOP_LIST()
 #undef OPERATOR
 #undef BINOP_LIST
-
+  
 #define OPERATOR(NAME)                                          \
-    case BO_##NAME##Assign:                          \
-      DISPATCH(Bin##NAME##Assign, CompoundAssignOperator, S);
-
-    CAO_LIST()
+      case BO_##NAME##Assign:                          \
+        DISPATCH_STMT(Bin##NAME##Assign, CompoundAssignOperator, S);
+  
+      CAO_LIST()
 #undef OPERATOR
 #undef CAO_LIST
-    }
-  } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
-    switch (UnOp->getOpcode()) {
+      }
+    } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
+      switch (UnOp->getOpcode()) {
 #define OPERATOR(NAME)                                                  \
-    case UO_##NAME: DISPATCH(Unary##NAME, UnaryOperator, S);
-
-    UNARYOP_LIST()
+      case UO_##NAME: DISPATCH_STMT(Unary##NAME, UnaryOperator, S);
+  
+      UNARYOP_LIST()
 #undef OPERATOR
 #undef UNARYOP_LIST
-    }
-  }
-
-  // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt.
-  switch (S->getStmtClass()) {
-  case Stmt::NoStmtClass: break;
+      }
+    } else {
+  
+      // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt.
+      switch (S->getStmtClass()) {
+      case Stmt::NoStmtClass: break;
 #define ABSTRACT_STMT(STMT)
 #define STMT(CLASS, PARENT) \
-  case Stmt::CLASS##Class: DISPATCH(CLASS, CLASS, S);
+      case Stmt::CLASS##Class: DISPATCH_STMT(CLASS, CLASS, S);
 #include "clang/AST/StmtNodes.inc"
+      }
+    }
+
+    for (SmallVector<Stmt *, 8>::reverse_iterator
+           RI = StmtsToEnqueu.rbegin(),
+           RE = StmtsToEnqueu.rend(); RI != RE; ++RI)
+      Queue.push_back(*RI);
   }
 
   return true;
@@ -1379,35 +1334,20 @@
 }
 
 // A helper method for traversing the implicit instantiations of a
-// class.
+// class template.
 template<typename Derived>
 bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
-  ClassTemplateDecl* D, Decl *Pattern) {
-  assert(isa<ClassTemplateDecl>(Pattern) ||
-         isa<ClassTemplatePartialSpecializationDecl>(Pattern));
-
+    ClassTemplateDecl *D) {
   ClassTemplateDecl::spec_iterator end = D->spec_end();
   for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
     ClassTemplateSpecializationDecl* SD = *it;
 
     switch (SD->getSpecializationKind()) {
     // Visit the implicit instantiations with the requested pattern.
-    case TSK_ImplicitInstantiation: {
-      llvm::PointerUnion<ClassTemplateDecl *,
-                         ClassTemplatePartialSpecializationDecl *> U
-        = SD->getInstantiatedFrom();
-
-      bool ShouldVisit;
-      if (U.is<ClassTemplateDecl*>())
-        ShouldVisit = (U.get<ClassTemplateDecl*>() == Pattern);
-      else
-        ShouldVisit
-          = (U.get<ClassTemplatePartialSpecializationDecl*>() == Pattern);
-
-      if (ShouldVisit)
-        TRY_TO(TraverseDecl(SD));
+    case TSK_Undeclared:
+    case TSK_ImplicitInstantiation:
+      TRY_TO(TraverseDecl(SD));
       break;
-    }
 
     // We don't need to do anything on an explicit instantiation
     // or explicit specialization because there will be an explicit
@@ -1416,11 +1356,6 @@
     case TSK_ExplicitInstantiationDefinition:
     case TSK_ExplicitSpecialization:
       break;
-
-    // We don't need to do anything for an uninstantiated
-    // specialization.
-    case TSK_Undeclared:
-      break;
     }
   }
 
@@ -1435,12 +1370,12 @@
     // By default, we do not traverse the instantiations of
     // class templates since they do not appear in the user code. The
     // following code optionally traverses them.
-    if (getDerived().shouldVisitTemplateInstantiations()) {
-      // If this is the definition of the primary template, visit
-      // instantiations which were formed from this pattern.
-      if (D->isThisDeclarationADefinition())
-        TRY_TO(TraverseClassInstantiations(D, D));
-    }
+    //
+    // We only traverse the class instantiations when we see the canonical
+    // declaration of the template, to ensure we only visit them once.
+    if (getDerived().shouldVisitTemplateInstantiations() &&
+        D == D->getCanonicalDecl())
+      TRY_TO(TraverseClassInstantiations(D));
 
     // Note that getInstantiatedFromMemberTemplate() is just a link
     // from a template instantiation back to the template from which
@@ -1451,12 +1386,13 @@
 // function while skipping its specializations.
 template<typename Derived>
 bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
-  FunctionTemplateDecl* D) {
+    FunctionTemplateDecl *D) {
   FunctionTemplateDecl::spec_iterator end = D->spec_end();
   for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
        ++it) {
     FunctionDecl* FD = *it;
     switch (FD->getTemplateSpecializationKind()) {
+    case TSK_Undeclared:
     case TSK_ImplicitInstantiation:
       // We don't know what kind of FunctionDecl this is.
       TRY_TO(TraverseDecl(FD));
@@ -1468,7 +1404,6 @@
     case TSK_ExplicitInstantiationDefinition:
       break;
 
-    case TSK_Undeclared:           // Declaration of the template definition.
     case TSK_ExplicitSpecialization:
       break;
     }
@@ -1482,19 +1417,14 @@
     TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
 
     // By default, we do not traverse the instantiations of
-    // function templates since they do not apprear in the user code. The
+    // function templates since they do not appear in the user code. The
     // following code optionally traverses them.
-    if (getDerived().shouldVisitTemplateInstantiations()) {
-      // Explicit function specializations will be traversed from the
-      // context of their declaration. There is therefore no need to
-      // traverse them for here.
-      //
-      // In addition, we only traverse the function instantiations when
-      // the function template is a function template definition.
-      if (D->isThisDeclarationADefinition()) {
-        TRY_TO(TraverseFunctionInstantiations(D));
-      }
-    }
+    //
+    // We only traverse the function instantiations when we see the canonical
+    // declaration of the template, to ensure we only visit them once.
+    if (getDerived().shouldVisitTemplateInstantiations() &&
+        D == D->getCanonicalDecl())
+      TRY_TO(TraverseFunctionInstantiations(D));
   })
 
 DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
@@ -1569,7 +1499,7 @@
     CXXRecordDecl *D) {
   if (!TraverseRecordHelper(D))
     return false;
-  if (D->hasDefinition()) {
+  if (D->isCompleteDefinition()) {
     for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
                                             E = D->bases_end();
          I != E; ++I) {
@@ -1636,11 +1566,7 @@
     // template args here.
     TRY_TO(TraverseCXXRecordHelper(D));
 
-    // If we're visiting instantiations, visit the instantiations of
-    // this template now.
-    if (getDerived().shouldVisitTemplateInstantiations() &&
-        D->isThisDeclarationADefinition())
-      TRY_TO(TraverseClassInstantiations(D->getSpecializedTemplate(), D));
+    // Instantiations will have been visited with the primary template.
   })
 
 DEF_TRAVERSE_DECL(EnumConstantDecl, {
@@ -1818,23 +1744,24 @@
 template<typename Derived>                                              \
 bool RecursiveASTVisitor<Derived>::Traverse##STMT (STMT *S) {           \
   TRY_TO(WalkUpFrom##STMT(S));                                          \
+  StmtQueueAction StmtQueue(*this);                                     \
   { CODE; }                                                             \
   for (Stmt::child_range range = S->children(); range; ++range) {       \
-    TRY_TO(TraverseStmt(*range));                                       \
+    StmtQueue.queue(*range);                                            \
   }                                                                     \
   return true;                                                          \
 }
 
 DEF_TRAVERSE_STMT(AsmStmt, {
-    TRY_TO(TraverseStmt(S->getAsmString()));
+    StmtQueue.queue(S->getAsmString());
     for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
-      TRY_TO(TraverseStmt(S->getInputConstraintLiteral(I)));
+      StmtQueue.queue(S->getInputConstraintLiteral(I));
     }
     for (unsigned I = 0, E = S->getNumOutputs(); I < E; ++I) {
-      TRY_TO(TraverseStmt(S->getOutputConstraintLiteral(I)));
+      StmtQueue.queue(S->getOutputConstraintLiteral(I));
     }
     for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
-      TRY_TO(TraverseStmt(S->getClobber(I)));
+      StmtQueue.queue(S->getClobber(I));
     }
     // children() iterates over inputExpr and outputExpr.
   })
@@ -1963,9 +1890,10 @@
   if (InitListExpr *Syn = S->getSyntacticForm())
     S = Syn;
   TRY_TO(WalkUpFromInitListExpr(S));
+  StmtQueueAction StmtQueue(*this);
   // All we need are the default actions.  FIXME: use a helper function.
   for (Stmt::child_range range = S->children(); range; ++range) {
-    TRY_TO(TraverseStmt(*range));
+    StmtQueue.queue(*range);
   }
   return true;
 }
@@ -1977,11 +1905,12 @@
 bool RecursiveASTVisitor<Derived>::
 TraverseGenericSelectionExpr(GenericSelectionExpr *S) {
   TRY_TO(WalkUpFromGenericSelectionExpr(S));
-  TRY_TO(TraverseStmt(S->getControllingExpr()));
+  StmtQueueAction StmtQueue(*this);
+  StmtQueue.queue(S->getControllingExpr());
   for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
     if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i))
       TRY_TO(TraverseTypeLoc(TS->getTypeLoc()));
-    TRY_TO(TraverseStmt(S->getAssocExpr(i)));
+    StmtQueue.queue(S->getAssocExpr(i));
   }
   return true;
 }
@@ -1992,13 +1921,14 @@
 bool RecursiveASTVisitor<Derived>::
 TraversePseudoObjectExpr(PseudoObjectExpr *S) {
   TRY_TO(WalkUpFromPseudoObjectExpr(S));
-  TRY_TO(TraverseStmt(S->getSyntacticForm()));
+  StmtQueueAction StmtQueue(*this);
+  StmtQueue.queue(S->getSyntacticForm());
   for (PseudoObjectExpr::semantics_iterator
          i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) {
     Expr *sub = *i;
     if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub))
       sub = OVE->getSourceExpr();
-    TRY_TO(TraverseStmt(sub));
+    StmtQueue.queue(sub);
   }
   return true;
 }
@@ -2062,7 +1992,7 @@
   })
 
 DEF_TRAVERSE_STMT(ExpressionTraitExpr, {
-    TRY_TO(TraverseStmt(S->getQueriedExpression()));
+    StmtQueue.queue(S->getQueriedExpression());
   })
 
 DEF_TRAVERSE_STMT(VAArgExpr, {
@@ -2102,7 +2032,8 @@
     }
   }
 
-  TRY_TO(TraverseStmt(S->getBody()));
+  StmtQueueAction StmtQueue(*this);
+  StmtQueue.queue(S->getBody());
   return true;
 }
 





More information about the cfe-commits mailing list