[cfe-commits] r94022 - in /cfe/trunk: include/clang-c/Index.h tools/CIndex/CIndex.cpp tools/CIndex/CIndex.exports

Douglas Gregor dgregor at apple.com
Wed Jan 20 12:59:30 PST 2010


Author: dgregor
Date: Wed Jan 20 14:59:29 2010
New Revision: 94022

URL: http://llvm.org/viewvc/llvm-project?rev=94022&view=rev
Log:
Introduce a new, cursor-based traversal function that visits the
children of a given cursor, regardless of what kind of cursor it
is. This is a generalization of clang_loadDeclaration and
clang_loadTranslationUnit that will also extent to statements,
expressions, etc.

As proof-of-concept, switched clang_loadDeclaration() from its own
visitor over to an instance of this traversal function internally.

Modified:
    cfe/trunk/include/clang-c/Index.h
    cfe/trunk/tools/CIndex/CIndex.cpp
    cfe/trunk/tools/CIndex/CIndex.exports

Modified: cfe/trunk/include/clang-c/Index.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=94022&r1=94021&r2=94022&view=diff

==============================================================================
--- cfe/trunk/include/clang-c/Index.h (original)
+++ cfe/trunk/include/clang-c/Index.h Wed Jan 20 14:59:29 2010
@@ -402,6 +402,75 @@
  */
 CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit);
 
+/**
+ * \brief Describes how the traversal of the children of a particular
+ * cursor should proceed after visiting a particular child cursor.
+ *
+ * A value of this enumeration type should be returned by each
+ * \c CXCursorVisitor to indicate how clang_visitChildren() proceed.
+ */
+enum CXChildVisitResult {
+  /**
+   * \brief Terminates the cursor traversal. 
+   */
+  CXChildVisit_Break,
+  /** 
+   * \brief Continues the cursor traversal with the next sibling of
+   * the cursor just visited, without visiting its children.
+   */
+  CXChildVisit_Continue,
+  /**
+   * \brief Recursively traverse the children of this cursor, using
+   * the same visitor and client data.
+   */
+  CXChildVisit_Recurse
+};
+
+/**
+ * \brief Visitor invoked for each cursor found by a traversal.
+ *
+ * This visitor function will be invoked for each cursor found by
+ * clang_visitCursorChildren(). Its first argument is the cursor being
+ * visited, its second argument is the parent visitor for that cursor,
+ * and its third argument is the client data provided to
+ * clang_visitCursorChildren().
+ *
+ * The visitor should return one of the \c CXChildVisitResult values
+ * to direct clang_visitCursorChildren().
+ */
+typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor, 
+                                                   CXCursor parent, 
+                                                   CXClientData client_data);
+
+/**
+ * \brief Visit the children of a particular cursor.
+ *
+ * This function visits all the direct children of the given cursor,
+ * invoking the given \p visitor function with the cursors of each
+ * visited child. The traversal may be recursive, if the visitor returns
+ * \c CXChildVisit_Recurse. The traversal may also be ended prematurely, if
+ * the visitor returns \c CXChildVisit_Break.
+ *
+ * \param tu the translation unit into which the cursor refers.
+ *
+ * \param parent the cursor whose child may be visited. All kinds of
+ * cursors can be visited, including invalid visitors (which, by
+ * definition, have no children).
+ *
+ * \param visitor the visitor function that will be invoked for each
+ * child of \p parent.
+ *
+ * \param client_data pointer data supplied by the client, which will
+ * be passed to the visitor each time it is invoked.
+ *
+ * \returns a non-zero value if the traversal was terminated
+ * prematurely by the visitor returning \c CXChildVisit_Break.
+ */
+CINDEX_LINKAGE unsigned clang_visitChildren(CXTranslationUnit tu,
+                                            CXCursor parent, 
+                                            CXCursorVisitor visitor,
+                                            CXClientData client_data);
+
 /*
  * CXFile Operations.
  */

Modified: cfe/trunk/tools/CIndex/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.cpp?rev=94022&r1=94021&r2=94022&view=diff

==============================================================================
--- cfe/trunk/tools/CIndex/CIndex.cpp (original)
+++ cfe/trunk/tools/CIndex/CIndex.cpp Wed Jan 20 14:59:29 2010
@@ -193,70 +193,139 @@
   VisitDeclContext(dyn_cast<DeclContext>(D));
 }
 
-// Declaration visitor.
-class CDeclVisitor : public DeclVisitor<CDeclVisitor> {
-  CXDecl CDecl;
-  CXDeclIterator Callback;
-  CXClientData CData;
-
+// Cursor visitor.
+class CursorVisitor : public DeclVisitor<CursorVisitor, bool> {
+  CXCursor Parent;
+  CXCursorVisitor Visitor;
+  CXClientData ClientData;
+  
   // MaxPCHLevel - the maximum PCH level of declarations that we will pass on
   // to the visitor. Declarations with a PCH level greater than this value will
   // be suppressed.
   unsigned MaxPCHLevel;
+  
+  using DeclVisitor<CursorVisitor, bool>::Visit;
+  
+public:
+  CursorVisitor(CXCursorVisitor Visitor, CXClientData ClientData, 
+                unsigned MaxPCHLevel)
+    : Visitor(Visitor), ClientData(ClientData), MaxPCHLevel(MaxPCHLevel)
+  {
+    Parent.kind = CXCursor_NoDeclFound;
+    Parent.data[0] = 0;
+    Parent.data[1] = 0;
+    Parent.data[2] = 0;
+  }
+  
+  bool Visit(CXCursor Cursor);
+  bool VisitChildren(CXCursor Parent);
+  
+  bool VisitDeclContext(DeclContext *DC);
+  
+  bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
+  bool VisitFunctionDecl(FunctionDecl *ND);
+  bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
+  bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+  bool VisitObjCMethodDecl(ObjCMethodDecl *ND);
+  bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
+  bool VisitTagDecl(TagDecl *D);
+};
+  
+} // end anonymous namespace
 
-  void Call(enum CXCursorKind CK, NamedDecl *ND) {
-    // Disable the callback when the context is equal to the visiting decl.
-    if (CDecl == ND && !clang_isReference(CK))
-      return;
-
-    // Filter any declarations that have a PCH level greater than what we allow.
-    if (ND->getPCHLevel() > MaxPCHLevel)
-      return;
+/// \brief Visit the given cursor and, if requested by the visitor,
+/// its children.
+///
+/// \returns true if the visitation should be aborted, false if it
+/// should continue.
+bool CursorVisitor::Visit(CXCursor Cursor) {
+  if (clang_isInvalid(Cursor.kind))
+    return false;
+  
+  if (clang_isDeclaration(Cursor.kind)) {
+    Decl *D = getCursorDecl(Cursor);
+    assert(D && "Invalid declaration cursor");
+    if (D->getPCHLevel() > MaxPCHLevel)
+      return false;
 
-    CXCursor C = { CK, { ND, 0, 0 } };
-    Callback(CDecl, C, CData);
+    if (D->isImplicit())
+      return false;
   }
 
-public:
-  CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D,
-               unsigned MaxPCHLevel) :
-    CDecl(C), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {}
-
-  void VisitDeclContext(DeclContext *DC);
-  void VisitEnumConstantDecl(EnumConstantDecl *ND);
-  void VisitFieldDecl(FieldDecl *ND);
-  void VisitFunctionDecl(FunctionDecl *ND);
-  void VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
-  void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
-  void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
-  void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
-  void VisitObjCIvarDecl(ObjCIvarDecl *ND);
-  void VisitObjCMethodDecl(ObjCMethodDecl *ND);
-  void VisitObjCPropertyDecl(ObjCPropertyDecl *ND);
-  void VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
-  void VisitParmVarDecl(ParmVarDecl *ND);
-  void VisitTagDecl(TagDecl *D);
-  void VisitVarDecl(VarDecl *ND);
-};
-} // end anonymous namespace
+  switch (Visitor(Cursor, Parent, ClientData)) {
+  case CXChildVisit_Break:
+    return true;
 
-void CDeclVisitor::VisitDeclContext(DeclContext *DC) {
-  for (DeclContext::decl_iterator
-       I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
-    Visit(*I);
+  case CXChildVisit_Continue:
+    return false;
+
+  case CXChildVisit_Recurse:
+    return VisitChildren(Cursor);
+  }
+
+  llvm_unreachable("Silly GCC, we can't get here");
+}
+
+/// \brief Visit the children of the given cursor.
+///
+/// \returns true if the visitation should be aborted, false if it
+/// should continue.
+bool CursorVisitor::VisitChildren(CXCursor Cursor) { 
+  // Set the Parent field to Cursor, then back to its old value once we're 
+  // done.
+  class SetParentRAII {
+    CXCursor &Parent;
+    CXCursor OldParent;
+    
+  public:
+    SetParentRAII(CXCursor &Parent, CXCursor NewParent)
+      : Parent(Parent), OldParent(Parent) 
+    {
+      Parent = NewParent;
+    }
+    
+    ~SetParentRAII() {
+      Parent = OldParent;
+    }
+  } SetParent(Parent, Cursor);
+  
+  if (clang_isDeclaration(Cursor.kind)) {
+    Decl *D = getCursorDecl(Cursor);
+    assert(D && "Invalid declaration cursor");
+    return Visit(D);
+  }
+  
+  if (clang_isTranslationUnit(Cursor.kind)) {
+    ASTUnit *CXXUnit = static_cast<ASTUnit *>(Cursor.data[0]);
+    return VisitTranslationUnitDecl(
+                            CXXUnit->getASTContext().getTranslationUnitDecl());
+  }
+    
+  // Nothing to visit at the moment.
+  // FIXME: Traverse statements, declarations, etc. here.
+  return false;
 }
 
-void CDeclVisitor::VisitEnumConstantDecl(EnumConstantDecl *ND) {
-  Call(CXCursor_EnumConstantDecl, ND);
+bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+  return VisitDeclContext(D);
 }
 
-void CDeclVisitor::VisitFieldDecl(FieldDecl *ND) {
-  Call(CXCursor_FieldDecl, ND);
+bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
+  for (DeclContext::decl_iterator
+       I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
+    if (Visit(MakeCXCursor(*I)))
+      return true;
+  }
+  
+  return false;
 }
 
-void CDeclVisitor::VisitFunctionDecl(FunctionDecl *ND) {
+bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
+  // FIXME: This is wrong. We always want to visit the parameters and
+  // the body, if available.
   if (ND->isThisDeclarationADefinition()) {
-    VisitDeclContext(dyn_cast<DeclContext>(ND));
+    return VisitDeclContext(ND);
+    
 #if 0
     // Not currently needed.
     CompoundStmt *Body = dyn_cast<CompoundStmt>(ND->getBody());
@@ -264,78 +333,59 @@
     RVisit.Visit(Body);
 #endif
   }
-}  
+  
+  return false;
+}
 
-void CDeclVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
-  // Issue callbacks for the containing class.
-  Callback(CDecl, 
-           MakeCursorObjCClassRef(ND->getClassInterface(), ND->getLocation()),
-           CData);
+bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
+  if (Visit(MakeCursorObjCClassRef(ND->getClassInterface(), ND->getLocation())))
+    return true;
+  
   ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin();
   for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(),
          E = ND->protocol_end(); I != E; ++I, ++PL)
-    Callback(CDecl, MakeCursorObjCProtocolRef(*I, *PL), CData);
-  VisitDeclContext(dyn_cast<DeclContext>(ND));
-}
-
-void CDeclVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
-  VisitDeclContext(dyn_cast<DeclContext>(D));
-}
-
-void CDeclVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
-  VisitDeclContext(dyn_cast<DeclContext>(D));
+    if (Visit(MakeCursorObjCProtocolRef(*I, *PL)))
+      return true;
+  
+  return VisitDeclContext(ND);
 }
 
-void CDeclVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
   // Issue callbacks for super class.
-  if (D->getSuperClass())
-    Callback(CDecl, 
-             MakeCursorObjCSuperClassRef(D->getSuperClass(),
-                                         D->getSuperClassLoc()), 
-             CData);
+  if (D->getSuperClass() &&
+      Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(),
+                                        D->getSuperClassLoc())))
+    return true;
   
   ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin();
   for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(),
          E = D->protocol_end(); I != E; ++I, ++PL)
-    Callback(CDecl, MakeCursorObjCProtocolRef(*I, *PL), CData);
-  VisitDeclContext(dyn_cast<DeclContext>(D));
-}
-
-void CDeclVisitor::VisitObjCIvarDecl(ObjCIvarDecl *ND) {
-  Call(CXCursor_ObjCIvarDecl, ND);
+    if (Visit(MakeCursorObjCProtocolRef(*I, *PL)))
+      return true;
+  
+  return VisitDeclContext(D);
 }
 
-void CDeclVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
-  Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl
-       : CXCursor_ObjCClassMethodDecl, ND);
-
+bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
+  // FIXME: Wrong in the same way that VisitFunctionDecl is wrong.
   if (ND->getBody())
-    VisitDeclContext(dyn_cast<DeclContext>(ND));
-}
-
-void CDeclVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *ND) {
-  Call(CXCursor_ObjCPropertyDecl, ND);
+    return VisitDeclContext(ND);
+  
+  return false;
 }
 
-void CDeclVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
+bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
   ObjCProtocolDecl::protocol_loc_iterator PL = PID->protocol_loc_begin();
   for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
          E = PID->protocol_end(); I != E; ++I, ++PL)
-    Callback(CDecl, MakeCursorObjCProtocolRef(*I, *PL), CData);
+    if (Visit(MakeCursorObjCProtocolRef(*I, *PL)))
+      return true;
   
-  VisitDeclContext(dyn_cast<DeclContext>(PID));
-}
-
-void CDeclVisitor::VisitParmVarDecl(ParmVarDecl *ND) {
-  Call(CXCursor_ParmDecl, ND);
+  return VisitDeclContext(PID);
 }
 
-void CDeclVisitor::VisitTagDecl(TagDecl *D) {
-  VisitDeclContext(dyn_cast<DeclContext>(D));
-}
-
-void CDeclVisitor::VisitVarDecl(VarDecl *ND) {
-  Call(CXCursor_VarDecl, ND);
+bool CursorVisitor::VisitTagDecl(TagDecl *D) {
+  return VisitDeclContext(D);
 }
 
 CXString CIndexer::createCXString(const char *String, bool DupString){
@@ -541,14 +591,28 @@
     DVisit.Visit(Ctx.getTranslationUnitDecl());
 }
 
+struct LoadDeclarationData {
+  CXDeclIterator Callback;
+  CXClientData ClientData;
+};
+
+CXChildVisitResult LoadDeclarationVisitor(CXCursor cursor, 
+                                          CXCursor parent, 
+                                          CXClientData client_data) {
+  LoadDeclarationData *Data = static_cast<LoadDeclarationData *>(client_data);
+  Data->Callback(clang_getCursorDecl(cursor), cursor, Data->ClientData);
+  return CXChildVisit_Recurse;
+}
+  
 void clang_loadDeclaration(CXDecl Dcl,
                            CXDeclIterator callback,
                            CXClientData CData) {
   assert(Dcl && "Passed null CXDecl");
 
-  CDeclVisitor DVisit(Dcl, callback, CData,
-                      static_cast<Decl *>(Dcl)->getPCHLevel());
-  DVisit.Visit(static_cast<Decl *>(Dcl));
+  LoadDeclarationData Data = { callback, CData };
+  CursorVisitor CurVisit(&LoadDeclarationVisitor, &Data, 
+                         static_cast<Decl *>(Dcl)->getPCHLevel());
+  CurVisit.VisitChildren(clang_getCursorFromDecl(Dcl));
 }
 } // end: extern "C"
 
@@ -703,6 +767,28 @@
 }
 
 extern "C" {
+  
+unsigned clang_visitChildren(CXTranslationUnit tu,
+                             CXCursor parent, 
+                             CXCursorVisitor visitor,
+                             CXClientData client_data) {
+  ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu);
+
+  unsigned PCHLevel = Decl::MaxPCHLevel;
+  
+  // Set the PCHLevel to filter out unwanted decls if requested.
+  if (CXXUnit->getOnlyLocalDecls()) {
+    PCHLevel = 0;
+    
+    // If the main input was an AST, bump the level.
+    if (CXXUnit->isMainFileAST())
+      ++PCHLevel;
+  }
+  
+  CursorVisitor CursorVis(visitor, client_data, PCHLevel);
+  return CursorVis.VisitChildren(parent);
+}
+
 CXString clang_getCursorSpelling(CXCursor C) {
   assert(getCursorDecl(C) && "CXCursor has null decl");
   if (clang_isTranslationUnit(C.kind))

Modified: cfe/trunk/tools/CIndex/CIndex.exports
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.exports?rev=94022&r1=94021&r2=94022&view=diff

==============================================================================
--- cfe/trunk/tools/CIndex/CIndex.exports (original)
+++ cfe/trunk/tools/CIndex/CIndex.exports Wed Jan 20 14:59:29 2010
@@ -45,3 +45,4 @@
 _clang_loadDeclaration
 _clang_loadTranslationUnit
 _clang_setUseExternalASTGeneration
+_clang_visitChildren





More information about the cfe-commits mailing list