[libclang] Introduce a new high level API for indexing clients that assumes
more of the work involved in indexing a translation unit and simplifies client
implementations.

Only C/ObjC for now, C++ (and comments) to come.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142233 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp
new file mode 100644
index 0000000..5cf9f80
--- /dev/null
+++ b/tools/libclang/IndexDecl.cpp
@@ -0,0 +1,218 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+
+#include "clang/AST/DeclVisitor.h"
+
+using namespace clang;
+using namespace cxindex;
+
+namespace {
+
+class IndexingDeclVisitor : public DeclVisitor<IndexingDeclVisitor, bool> {
+  IndexingContext &IndexCtx;
+
+public:
+  explicit IndexingDeclVisitor(IndexingContext &indexCtx)
+    : IndexCtx(indexCtx) { }
+
+  bool VisitFunctionDecl(FunctionDecl *D) {
+    IndexCtx.handleFunction(D);
+    IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+    if (D->isThisDeclarationADefinition()) {
+      const Stmt *Body = D->getBody();
+      if (Body) {
+        IndexCtx.invokeStartedStatementBody(D, D);
+        IndexCtx.indexBody(Body, D);
+        IndexCtx.invokeEndedContainer(D);
+      }
+    }
+    return true;
+  }
+
+  bool VisitVarDecl(VarDecl *D) {
+    IndexCtx.handleVar(D);
+    IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+    return true;
+  }
+
+  bool VisitFieldDecl(FieldDecl *D) {
+    IndexCtx.handleField(D);
+    IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+    return true;
+  }
+  
+  bool VisitEnumConstantDecl(EnumConstantDecl *D) {
+    IndexCtx.handleEnumerator(D);
+    return true;
+  }
+
+  bool VisitTypedefDecl(TypedefDecl *D) {
+    IndexCtx.handleTypedef(D);
+    IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+    return true;
+  }
+
+  bool VisitTagDecl(TagDecl *D) {
+    // Non-free standing tags are handled in indexTypeSourceInfo.
+    if (D->isFreeStanding())
+      IndexCtx.indexTagDecl(D);
+    return true;
+  }
+
+  bool VisitObjCClassDecl(ObjCClassDecl *D) {
+    ObjCClassDecl::ObjCClassRef *Ref = D->getForwardDecl();
+    if (Ref->getInterface()->getLocation() == Ref->getLocation()) {
+      IndexCtx.handleObjCInterface(Ref->getInterface());
+    } else {
+      IndexCtx.handleReference(Ref->getInterface(),
+                               Ref->getLocation(),
+                               0,
+                               Ref->getInterface()->getDeclContext());
+    }
+    return true;
+  }
+
+  bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
+    ObjCForwardProtocolDecl::protocol_loc_iterator LI = D->protocol_loc_begin();
+    for (ObjCForwardProtocolDecl::protocol_iterator
+           I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I, ++LI) {
+      SourceLocation Loc = *LI;
+      ObjCProtocolDecl *PD = *I;
+
+      if (PD->getLocation() == Loc) {
+        IndexCtx.handleObjCProtocol(PD);
+      } else {
+        IndexCtx.handleReference(PD, Loc, 0, PD->getDeclContext());
+      }
+    }
+    return true;
+  }
+
+  bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+    // Only definitions are handled here.
+    if (D->isForwardDecl())
+      return true;
+
+    if (!D->isInitiallyForwardDecl())
+      IndexCtx.handleObjCInterface(D);
+
+    IndexCtx.indexTUDeclsInObjCContainer();
+    IndexCtx.invokeStartedObjCContainer(D);
+    IndexCtx.defineObjCInterface(D);
+    IndexCtx.indexDeclContext(D);
+    IndexCtx.invokeEndedContainer(D);
+    return true;
+  }
+
+  bool VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+    // Only definitions are handled here.
+    if (D->isForwardDecl())
+      return true;
+
+    if (!D->isInitiallyForwardDecl())
+      IndexCtx.handleObjCProtocol(D);
+
+    IndexCtx.indexTUDeclsInObjCContainer();
+    IndexCtx.invokeStartedObjCContainer(D);
+    IndexCtx.indexDeclContext(D);
+    IndexCtx.invokeEndedContainer(D);
+    return true;
+  }
+
+  bool VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+    ObjCInterfaceDecl *Class = D->getClassInterface();
+    if (Class->isImplicitInterfaceDecl())
+      IndexCtx.handleObjCInterface(Class);
+
+    IndexCtx.indexTUDeclsInObjCContainer();
+    IndexCtx.invokeStartedObjCContainer(D);
+    IndexCtx.indexDeclContext(D);
+    IndexCtx.invokeEndedContainer(D);
+    return true;
+  }
+
+  bool VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
+    if (!D->IsClassExtension())
+      IndexCtx.handleObjCCategory(D);
+
+    IndexCtx.indexTUDeclsInObjCContainer();
+    IndexCtx.invokeStartedObjCContainer(D);
+    IndexCtx.indexDeclContext(D);
+    IndexCtx.invokeEndedContainer(D);
+    return true;
+  }
+
+  bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+    IndexCtx.indexTUDeclsInObjCContainer();
+    IndexCtx.invokeStartedObjCContainer(D);
+    IndexCtx.indexDeclContext(D);
+    IndexCtx.invokeEndedContainer(D);
+    return true;
+  }
+
+  bool VisitObjCMethodDecl(ObjCMethodDecl *D) {
+    IndexCtx.handleObjCMethod(D);
+    IndexCtx.indexTypeSourceInfo(D->getResultTypeSourceInfo(), D);
+    for (ObjCMethodDecl::param_iterator
+           I = D->param_begin(), E = D->param_end(); I != E; ++I)
+      IndexCtx.indexTypeSourceInfo((*I)->getTypeSourceInfo(), D);
+
+    if (D->isThisDeclarationADefinition()) {
+      const Stmt *Body = D->getBody();
+      if (Body) {
+        IndexCtx.invokeStartedStatementBody(D, D);
+        IndexCtx.indexBody(Body, D);
+        IndexCtx.invokeEndedContainer(D);
+      }
+    }
+    return true;
+  }
+
+  bool VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+    IndexCtx.handleObjCProperty(D);
+    IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+    return true;
+  }
+};
+
+} // anonymous namespace
+
+void IndexingContext::indexDecl(const Decl *D) {
+  bool Handled = IndexingDeclVisitor(*this).Visit(const_cast<Decl*>(D));
+  if (!Handled && isa<DeclContext>(D))
+    indexDeclContext(cast<DeclContext>(D));
+}
+
+void IndexingContext::indexDeclContext(const DeclContext *DC) {
+  for (DeclContext::decl_iterator
+         I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
+    indexDecl(*I);
+  }
+}
+
+void IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
+  for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
+    Decl *D = *I;
+    if (isNotFromSourceFile(D->getLocation()))
+      return;
+
+    if (isa<ObjCMethodDecl>(D))
+      continue; // Wait for the objc container.
+
+    indexDecl(D);
+  }
+}
+
+void IndexingContext::indexTUDeclsInObjCContainer() {
+  for (unsigned i = 0, e = TUDeclsInObjCContainer.size(); i != e; ++i)
+    indexDeclGroupRef(TUDeclsInObjCContainer[i]);
+  TUDeclsInObjCContainer.clear();
+}