[cfe-commits] r169539 - in /cfe/trunk: include/clang-c/Index.h test/Index/skip-parsed-bodies/ test/Index/skip-parsed-bodies/compile_commands.json test/Index/skip-parsed-bodies/lit.local.cfg test/Index/skip-parsed-bodies/t.h test/Index/skip-parsed-bodies/t1.cpp test/Index/skip-parsed-bodies/t2.cpp test/Index/skip-parsed-bodies/t3.cpp tools/c-index-test/c-index-test.c tools/libclang/Indexing.cpp tools/libclang/IndexingContext.cpp tools/libclang/IndexingContext.h

Argyrios Kyrtzidis akyrtzi at gmail.com
Thu Dec 6 11:41:16 PST 2012


Author: akirtzidis
Date: Thu Dec  6 13:41:16 2012
New Revision: 169539

URL: http://llvm.org/viewvc/llvm-project?rev=169539&view=rev
Log:
[libclang] Introduce a new indexing mode where we skip function bodies
that were already parsed in the same "indexing session".

An indexing session is defined as using the same CXIndexAction object
for multiple clang_indexSourceFile calls.
Passing CXIndexOpt_SkipParsedBodiesInSession as an indexing option will
enable the mode where we try to skip bodies that were already parsed in
another translation unit.

If a function's body was skipped, the "flags" field in the CXIdxDeclInfo
structure will have "CXIdxDeclFlag_Skipped" bit was set.

Added:
    cfe/trunk/test/Index/skip-parsed-bodies/
    cfe/trunk/test/Index/skip-parsed-bodies/compile_commands.json
    cfe/trunk/test/Index/skip-parsed-bodies/lit.local.cfg
    cfe/trunk/test/Index/skip-parsed-bodies/t.h
    cfe/trunk/test/Index/skip-parsed-bodies/t1.cpp
    cfe/trunk/test/Index/skip-parsed-bodies/t2.cpp
    cfe/trunk/test/Index/skip-parsed-bodies/t3.cpp
Modified:
    cfe/trunk/include/clang-c/Index.h
    cfe/trunk/tools/c-index-test/c-index-test.c
    cfe/trunk/tools/libclang/Indexing.cpp
    cfe/trunk/tools/libclang/IndexingContext.cpp
    cfe/trunk/tools/libclang/IndexingContext.h

Modified: cfe/trunk/include/clang-c/Index.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=169539&r1=169538&r2=169539&view=diff
==============================================================================
--- cfe/trunk/include/clang-c/Index.h (original)
+++ cfe/trunk/include/clang-c/Index.h Thu Dec  6 13:41:16 2012
@@ -32,7 +32,7 @@
  * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
  */
 #define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 8
+#define CINDEX_VERSION_MINOR 9
 
 #define CINDEX_VERSION_ENCODE(major, minor) ( \
       ((major) * 10000)                       \
@@ -5151,6 +5151,10 @@
   CXIdxLoc classLoc;
 } CXIdxIBOutletCollectionAttrInfo;
 
+typedef enum {
+  CXIdxDeclFlag_Skipped = 0x1
+} CXIdxDeclInfoFlags;
+
 typedef struct {
   const CXIdxEntityInfo *entityInfo;
   CXCursor cursor;
@@ -5172,6 +5176,9 @@
   int isImplicit;
   const CXIdxAttrInfo *const *attributes;
   unsigned numAttributes;
+
+  unsigned flags;
+
 } CXIdxDeclInfo;
 
 typedef enum {
@@ -5379,16 +5386,14 @@
 clang_index_setClientEntity(const CXIdxEntityInfo *, CXIdxClientEntity);
 
 /**
- * \brief An indexing action, to be applied to one or multiple translation units
- * but not on concurrent threads. If there are threads doing indexing
- * concurrently, they should use different CXIndexAction objects.
+ * \brief An indexing action/session, to be applied to one or multiple
+ * translation units.
  */
 typedef void *CXIndexAction;
 
 /**
- * \brief An indexing action, to be applied to one or multiple translation units
- * but not on concurrent threads. If there are threads doing indexing
- * concurrently, they should use different CXIndexAction objects.
+ * \brief An indexing action/session, to be applied to one or multiple
+ * translation units.
  *
  * \param CIdx The index object with which the index action will be associated.
  */
@@ -5430,7 +5435,15 @@
   /**
    * \brief Suppress all compiler warnings when parsing for indexing.
    */
-  CXIndexOpt_SuppressWarnings = 0x8
+  CXIndexOpt_SuppressWarnings = 0x8,
+
+  /**
+   * \brief Skip a function/method body that was already parsed during an
+   * indexing session assosiated with a \c CXIndexAction object.
+   * Bodies in system headers are always skipped.
+   */
+  CXIndexOpt_SkipParsedBodiesInSession = 0x10
+
 } CXIndexOptFlags;
 
 /**

Added: cfe/trunk/test/Index/skip-parsed-bodies/compile_commands.json
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/skip-parsed-bodies/compile_commands.json?rev=169539&view=auto
==============================================================================
--- cfe/trunk/test/Index/skip-parsed-bodies/compile_commands.json (added)
+++ cfe/trunk/test/Index/skip-parsed-bodies/compile_commands.json Thu Dec  6 13:41:16 2012
@@ -0,0 +1,58 @@
+[
+{
+  "directory": ".",
+  "command": "/usr/bin/clang++ -fsyntax-only t1.cpp",
+  "file": "t1.cpp"
+},
+{
+  "directory": ".",
+  "command": "/usr/bin/clang++ -fsyntax-only t2.cpp -DBLAH",
+  "file": "t2.cpp"
+},
+{
+  "directory": ".",
+  "command": "/usr/bin/clang++ -fsyntax-only t3.cpp -DBLAH",
+  "file": "t2.cpp"
+}
+]
+
+// XFAIL: cygwin,mingw32,win32
+// RUN: c-index-test -index-compile-db %s | FileCheck %s
+
+// CHECK:      [enteredMainFile]: t1.cpp
+// CHECK:      [indexDeclaration]: kind: c++-instance-method | name: method_decl | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: 1
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: some_val | {{.*}} | loc: ./t.h:9:27
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isRedecl: 1 | isDef: 1 | isContainer: 1
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS |
+// CHECK-NEXT: [indexEntityReference]: kind: c++-class | name: C |
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: some_val | {{.*}} | loc: ./t.h:15:5
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: 1
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: some_val | {{.*}} | loc: ./t.h:19:5
+// CHECK-NEXT: [diagnostic]: {{.*}} undeclared identifier 'undef_val1'
+// CHECK-NEXT: [diagnostic]: {{.*}} undeclared identifier 'undef_val2'
+// CHECK-NEXT: [diagnostic]: {{.*}} undeclared identifier 'undef_val3'
+
+// CHECK-NEXT: [enteredMainFile]: t2.cpp
+// CHECK:      [indexDeclaration]: kind: c++-instance-method | name: method_decl | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isContainer: skipped
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS |
+// CHECK-NEXT: [indexEntityReference]: kind: c++-class | name: C |
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo2 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: 1
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: some_val | {{.*}} | loc: ./t.h:25:5
+// CHECK-NEXT: [diagnostic]: {{.*}} undeclared identifier 'undef_val4'
+
+// CHECK-NEXT: [enteredMainFile]: t3.cpp
+// CHECK:      [indexDeclaration]: kind: c++-instance-method | name: method_decl | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isRedecl: 1 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS |
+// CHECK-NEXT: [indexEntityReference]: kind: c++-class | name: C |
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo2 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NOT : [diagnostic]: {{.*}} undeclared identifier

Added: cfe/trunk/test/Index/skip-parsed-bodies/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/skip-parsed-bodies/lit.local.cfg?rev=169539&view=auto
==============================================================================
--- cfe/trunk/test/Index/skip-parsed-bodies/lit.local.cfg (added)
+++ cfe/trunk/test/Index/skip-parsed-bodies/lit.local.cfg Thu Dec  6 13:41:16 2012
@@ -0,0 +1 @@
+config.suffixes = ['.json']

Added: cfe/trunk/test/Index/skip-parsed-bodies/t.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/skip-parsed-bodies/t.h?rev=169539&view=auto
==============================================================================
--- cfe/trunk/test/Index/skip-parsed-bodies/t.h (added)
+++ cfe/trunk/test/Index/skip-parsed-bodies/t.h Thu Dec  6 13:41:16 2012
@@ -0,0 +1,30 @@
+#ifndef _T_H_
+#define _T_H_
+
+extern int some_val;
+
+namespace NS {
+  class C {
+    void method_decl();
+    int method_def1() { ++some_val; return undef_val1; }
+    inline int method_def2();
+  };
+}
+
+inline int NS::C::method_def2() {
+  ++some_val; return undef_val2;
+}
+
+static inline int foo1() {
+  ++some_val; return undef_val3;
+}
+
+#ifdef BLAH
+
+static inline int foo2() {
+  ++some_val; return undef_val4;
+}
+
+#endif
+
+#endif

Added: cfe/trunk/test/Index/skip-parsed-bodies/t1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/skip-parsed-bodies/t1.cpp?rev=169539&view=auto
==============================================================================
--- cfe/trunk/test/Index/skip-parsed-bodies/t1.cpp (added)
+++ cfe/trunk/test/Index/skip-parsed-bodies/t1.cpp Thu Dec  6 13:41:16 2012
@@ -0,0 +1 @@
+#include "t.h"

Added: cfe/trunk/test/Index/skip-parsed-bodies/t2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/skip-parsed-bodies/t2.cpp?rev=169539&view=auto
==============================================================================
--- cfe/trunk/test/Index/skip-parsed-bodies/t2.cpp (added)
+++ cfe/trunk/test/Index/skip-parsed-bodies/t2.cpp Thu Dec  6 13:41:16 2012
@@ -0,0 +1 @@
+#include "t.h"

Added: cfe/trunk/test/Index/skip-parsed-bodies/t3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/skip-parsed-bodies/t3.cpp?rev=169539&view=auto
==============================================================================
--- cfe/trunk/test/Index/skip-parsed-bodies/t3.cpp (added)
+++ cfe/trunk/test/Index/skip-parsed-bodies/t3.cpp Thu Dec  6 13:41:16 2012
@@ -0,0 +1 @@
+#include "t.h"

Modified: cfe/trunk/tools/c-index-test/c-index-test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=169539&r1=169538&r2=169539&view=diff
==============================================================================
--- cfe/trunk/tools/c-index-test/c-index-test.c (original)
+++ cfe/trunk/tools/c-index-test/c-index-test.c Thu Dec  6 13:41:16 2012
@@ -2497,7 +2497,12 @@
   printCXIndexContainer(info->lexicalContainer);
   printf(" | isRedecl: %d", info->isRedeclaration);
   printf(" | isDef: %d", info->isDefinition);
-  printf(" | isContainer: %d", info->isContainer);
+  if (info->flags & CXIdxDeclFlag_Skipped) {
+    assert(!info->isContainer);
+    printf(" | isContainer: skipped");
+  } else {
+    printf(" | isContainer: %d", info->isContainer);
+  }
   printf(" | isImplicit: %d\n", info->isImplicit);
 
   for (i = 0; i != info->numAttributes; ++i) {
@@ -2608,6 +2613,8 @@
     index_opts |= CXIndexOpt_SuppressRedundantRefs;
   if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
     index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
+  if (!getenv("CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
+    index_opts |= CXIndexOpt_SkipParsedBodiesInSession;
 
   return index_opts;
 }

Modified: cfe/trunk/tools/libclang/Indexing.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/Indexing.cpp?rev=169539&r1=169538&r2=169539&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/Indexing.cpp (original)
+++ cfe/trunk/tools/libclang/Indexing.cpp Thu Dec  6 13:41:16 2012
@@ -23,9 +23,13 @@
 #include "clang/Frontend/Utils.h"
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PPConditionalDirectiveRecord.h"
+#include "clang/Lex/HeaderSearch.h"
 #include "clang/Sema/SemaConsumer.h"
 #include "llvm/Support/CrashRecoveryContext.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/MutexGuard.h"
 
 using namespace clang;
 using namespace cxstring;
@@ -37,6 +41,203 @@
 namespace {
 
 //===----------------------------------------------------------------------===//
+// Skip Parsed Bodies
+//===----------------------------------------------------------------------===//
+
+#ifdef LLVM_ON_WIN32
+
+// FIXME: On windows it is disabled since current implementation depends on
+// file inodes.
+
+class SessionSkipBodyData { };
+
+class TUSkipBodyControl {
+public:
+  TUSkipBodyControl(SessionSkipBodyData &sessionData,
+                    PPConditionalDirectiveRecord &ppRec) { }
+  bool isParsed(SourceLocation Loc, FileID FID, const FileEntry *FE) {
+    return false;
+  }
+  void finished() { }
+};
+
+#else
+
+/// \brief A "region" in source code identified by the file/offset of the
+/// preprocessor conditional directive that it belongs to.
+/// Multiple, non-consecutive ranges can be parts of the same region.
+///
+/// As an example of different regions separated by preprocessor directives:
+///
+/// \code
+///   #1
+/// #ifdef BLAH
+///   #2
+/// #ifdef CAKE
+///   #3
+/// #endif
+///   #2
+/// #endif
+///   #1
+/// \endcode
+///
+/// There are 3 regions, with non-consecutive parts:
+///   #1 is identified as the beginning of the file
+///   #2 is identified as the location of "#ifdef BLAH"
+///   #3 is identified as the location of "#ifdef CAKE"
+///
+class PPRegion {
+  ino_t ino;
+  time_t ModTime;
+  dev_t dev;
+  unsigned Offset;
+public:
+  PPRegion() : ino(), ModTime(), dev(), Offset() {}
+  PPRegion(dev_t dev, ino_t ino, unsigned offset, time_t modTime)
+    : ino(ino), ModTime(modTime), dev(dev), Offset(offset) {}
+
+  ino_t getIno() const { return ino; }
+  dev_t getDev() const { return dev; }
+  unsigned getOffset() const { return Offset; }
+  time_t getModTime() const { return ModTime; }
+
+  bool isInvalid() const { return *this == PPRegion(); }
+
+  friend bool operator==(const PPRegion &lhs, const PPRegion &rhs) {
+    return lhs.dev == rhs.dev && lhs.ino == rhs.ino &&
+        lhs.Offset == rhs.Offset && lhs.ModTime == rhs.ModTime;
+  }
+};
+
+typedef llvm::DenseSet<PPRegion> PPRegionSetTy;
+
+} // end anonymous namespace
+
+namespace llvm {
+  template <> struct isPodLike<PPRegion> {
+    static const bool value = true;
+  };
+
+  template <>
+  struct DenseMapInfo<PPRegion> {
+    static inline PPRegion getEmptyKey() {
+      return PPRegion(0, 0, unsigned(-1), 0);
+    }
+    static inline PPRegion getTombstoneKey() {
+      return PPRegion(0, 0, unsigned(-2), 0);
+    }
+
+    static unsigned getHashValue(const PPRegion &S) {
+      llvm::FoldingSetNodeID ID;
+      ID.AddInteger(S.getIno());
+      ID.AddInteger(S.getDev());
+      ID.AddInteger(S.getOffset());
+      ID.AddInteger(S.getModTime());
+      return ID.ComputeHash();
+    }
+
+    static bool isEqual(const PPRegion &LHS, const PPRegion &RHS) {
+      return LHS == RHS;
+    }
+  };
+}
+
+namespace {
+
+class SessionSkipBodyData {
+  llvm::sys::Mutex Mux;
+  PPRegionSetTy ParsedRegions;
+
+public:
+  SessionSkipBodyData() : Mux(/*recursive=*/false) {}
+  ~SessionSkipBodyData() {
+    //llvm::errs() << "RegionData: " << Skipped.size() << " - " << Skipped.getMemorySize() << "\n";
+  }
+
+  void copyTo(PPRegionSetTy &Set) {
+    llvm::MutexGuard MG(Mux);
+    Set = ParsedRegions;
+  }
+
+  void update(ArrayRef<PPRegion> Regions) {
+    llvm::MutexGuard MG(Mux);
+    ParsedRegions.insert(Regions.begin(), Regions.end());
+  }
+};
+
+class TUSkipBodyControl {
+  SessionSkipBodyData &SessionData;
+  PPConditionalDirectiveRecord &PPRec;
+  Preprocessor &PP;
+
+  PPRegionSetTy ParsedRegions;
+  SmallVector<PPRegion, 32> NewParsedRegions;
+  PPRegion LastRegion;
+  bool LastIsParsed;
+
+public:
+  TUSkipBodyControl(SessionSkipBodyData &sessionData,
+                    PPConditionalDirectiveRecord &ppRec,
+                    Preprocessor &pp)
+    : SessionData(sessionData), PPRec(ppRec), PP(pp) {
+    SessionData.copyTo(ParsedRegions);
+  }
+
+  bool isParsed(SourceLocation Loc, FileID FID, const FileEntry *FE) {
+    PPRegion region = getRegion(Loc, FID, FE);
+    if (region.isInvalid())
+      return false;
+
+    // Check common case, consecutive functions in the same region.
+    if (LastRegion == region)
+      return LastIsParsed;
+
+    LastRegion = region;
+    LastIsParsed = ParsedRegions.count(region);
+    if (!LastIsParsed)
+      NewParsedRegions.push_back(region);
+    return LastIsParsed;
+  }
+
+  void finished() {
+    SessionData.update(NewParsedRegions);
+  }
+
+private:
+  PPRegion getRegion(SourceLocation Loc, FileID FID, const FileEntry *FE) {
+    SourceLocation RegionLoc = PPRec.findConditionalDirectiveRegionLoc(Loc);
+    if (RegionLoc.isInvalid()) {
+      if (isParsedOnceInclude(FE))
+        return PPRegion(FE->getDevice(), FE->getInode(), 0,
+                        FE->getModificationTime());
+      return PPRegion();
+    }
+
+    const SourceManager &SM = PPRec.getSourceManager();
+    assert(RegionLoc.isFileID());
+    FileID RegionFID;
+    unsigned RegionOffset;
+    llvm::tie(RegionFID, RegionOffset) = SM.getDecomposedLoc(RegionLoc);
+
+    if (RegionFID != FID) {
+      if (isParsedOnceInclude(FE))
+        return PPRegion(FE->getDevice(), FE->getInode(), 0,
+                        FE->getModificationTime());
+      return PPRegion();
+    }
+
+    return PPRegion(FE->getDevice(), FE->getInode(), RegionOffset,
+                    FE->getModificationTime());
+  }
+
+  bool isParsedOnceInclude(const FileEntry *FE) {
+    return PP.getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE);
+  }
+};
+
+#endif
+
+//===----------------------------------------------------------------------===//
 // IndexPPCallbacks
 //===----------------------------------------------------------------------===//
 
@@ -91,7 +292,7 @@
   virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
                             SourceRange Range) {
   }
-  
+
   /// SourceRangeSkipped - This hook is called when a source range is skipped.
   /// \param Range The SourceRange that was skipped. The range begins at the
   /// #if/#else directive and ends after the #endif/#else directive.
@@ -105,10 +306,11 @@
 
 class IndexingConsumer : public ASTConsumer {
   IndexingContext &IndexCtx;
+  TUSkipBodyControl *SKCtrl;
 
 public:
-  explicit IndexingConsumer(IndexingContext &indexCtx)
-    : IndexCtx(indexCtx) { }
+  IndexingConsumer(IndexingContext &indexCtx, TUSkipBodyControl *skCtrl)
+    : IndexCtx(indexCtx), SKCtrl(skCtrl) { }
 
   // ASTConsumer Implementation
 
@@ -118,6 +320,8 @@
   }
 
   virtual void HandleTranslationUnit(ASTContext &Ctx) {
+    if (SKCtrl)
+      SKCtrl->finished();
   }
 
   virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
@@ -151,6 +355,32 @@
 
     IndexCtx.indexDecl(D);
   }
+
+  virtual bool shouldSkipFunctionBody(Decl *D) {
+    if (!SKCtrl) {
+      // Always skip bodies.
+      return true;
+    }
+
+    const SourceManager &SM = IndexCtx.getASTContext().getSourceManager();
+    SourceLocation Loc = D->getLocation();
+    if (Loc.isMacroID())
+      return false;
+    if (SM.isInSystemHeader(Loc))
+      return true; // always skip bodies from system headers.
+
+    FileID FID;
+    unsigned Offset;
+    llvm::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
+    // Don't skip bodies from main files; this may be revisited.
+    if (SM.getMainFileID() == FID)
+      return false;
+    const FileEntry *FE = SM.getFileEntryForID(FID);
+    if (!FE)
+      return false;
+
+    return SKCtrl->isParsed(Loc, FID, FE);
+  }
 };
 
 //===----------------------------------------------------------------------===//
@@ -180,13 +410,17 @@
   IndexingContext IndexCtx;
   CXTranslationUnit CXTU;
 
+  SessionSkipBodyData *SKData;
+  OwningPtr<TUSkipBodyControl> SKCtrl;
+
 public:
   IndexingFrontendAction(CXClientData clientData,
                          IndexerCallbacks &indexCallbacks,
                          unsigned indexOptions,
-                         CXTranslationUnit cxTU)
+                         CXTranslationUnit cxTU,
+                         SessionSkipBodyData *skData)
     : IndexCtx(clientData, indexCallbacks, indexOptions, cxTU),
-      CXTU(cxTU) { }
+      CXTU(cxTU), SKData(skData) { }
 
   virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
                                          StringRef InFile) {
@@ -201,7 +435,15 @@
     Preprocessor &PP = CI.getPreprocessor();
     PP.addPPCallbacks(new IndexPPCallbacks(PP, IndexCtx));
     IndexCtx.setPreprocessor(PP);
-    return new IndexingConsumer(IndexCtx);
+
+    if (SKData) {
+      PPConditionalDirectiveRecord *
+        PPRec = new PPConditionalDirectiveRecord(PP.getSourceManager());
+      PP.addPPCallbacks(PPRec);
+      SKCtrl.reset(new TUSkipBodyControl(*SKData, *PPRec, PP));
+    }
+
+    return new IndexingConsumer(IndexCtx, SKCtrl.get());
   }
 
   virtual void EndSourceFileAction() {
@@ -221,6 +463,14 @@
 // clang_indexSourceFileUnit Implementation
 //===----------------------------------------------------------------------===//
 
+struct IndexSessionData {
+  CXIndex CIdx;
+  OwningPtr<SessionSkipBodyData> SkipBodyData;
+
+  explicit IndexSessionData(CXIndex cIdx)
+    : CIdx(cIdx), SkipBodyData(new SessionSkipBodyData) {}
+};
+
 struct IndexSourceFileInfo {
   CXIndexAction idxAction;
   CXClientData client_data;
@@ -252,7 +502,7 @@
 static void clang_indexSourceFile_Impl(void *UserData) {
   IndexSourceFileInfo *ITUI =
     static_cast<IndexSourceFileInfo*>(UserData);
-  CXIndex CIdx = (CXIndex)ITUI->idxAction;
+  CXIndexAction cxIdxAction = ITUI->idxAction;
   CXClientData client_data = ITUI->client_data;
   IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks;
   unsigned index_callbacks_size = ITUI->index_callbacks_size;
@@ -270,7 +520,7 @@
     *out_TU = 0;
   bool requestedToGetTU = (out_TU != 0); 
 
-  if (!CIdx)
+  if (!cxIdxAction)
     return;
   if (!client_index_callbacks || index_callbacks_size == 0)
     return;
@@ -281,7 +531,8 @@
                                   ? index_callbacks_size : sizeof(CB);
   memcpy(&CB, client_index_callbacks, ClientCBSize);
 
-  CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+  IndexSessionData *IdxSession = static_cast<IndexSessionData *>(cxIdxAction);
+  CIndexer *CXXIdx = static_cast<CIndexer *>(IdxSession->CIdx);
 
   if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
     setThreadBackgroundPriority();
@@ -366,9 +617,17 @@
   llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner>
     CXTUCleanup(CXTU.get());
 
+  // Enable the skip-parsed-bodies optimization only for C++; this may be
+  // revisited.
+  bool SkipBodies = (index_options & CXIndexOpt_SkipParsedBodiesInSession) &&
+      CInvok->getLangOpts()->CPlusPlus;
+  if (SkipBodies)
+    CInvok->getFrontendOpts().SkipFunctionBodies = true;
+
   OwningPtr<IndexingFrontendAction> IndexAction;
   IndexAction.reset(new IndexingFrontendAction(client_data, CB,
-                                               index_options, CXTU->getTU()));
+                                               index_options, CXTU->getTU(),
+                              SkipBodies ? IdxSession->SkipBodyData.get() : 0));
 
   // Recover resources if we crash before exiting this method.
   llvm::CrashRecoveryContextCleanupRegistrar<IndexingFrontendAction>
@@ -519,7 +778,7 @@
     IndexCtxCleanup(IndexCtx.get());
 
   OwningPtr<IndexingConsumer> IndexConsumer;
-  IndexConsumer.reset(new IndexingConsumer(*IndexCtx));
+  IndexConsumer.reset(new IndexingConsumer(*IndexCtx, 0));
 
   // Recover resources if we crash before exiting this method.
   llvm::CrashRecoveryContextCleanupRegistrar<IndexingConsumer>
@@ -689,12 +948,12 @@
 }
 
 CXIndexAction clang_IndexAction_create(CXIndex CIdx) {
-  // For now, CXIndexAction is featureless. 
-  return CIdx;
+  return new IndexSessionData(CIdx);
 }
 
 void clang_IndexAction_dispose(CXIndexAction idxAction) {
-  // For now, CXIndexAction is featureless. 
+  if (idxAction)
+    delete static_cast<IndexSessionData *>(idxAction);
 }
 
 int clang_indexSourceFile(CXIndexAction idxAction,

Modified: cfe/trunk/tools/libclang/IndexingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/IndexingContext.cpp?rev=169539&r1=169538&r2=169539&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/IndexingContext.cpp (original)
+++ cfe/trunk/tools/libclang/IndexingContext.cpp Thu Dec  6 13:41:16 2012
@@ -364,8 +364,18 @@
 }
 
 bool IndexingContext::handleFunction(const FunctionDecl *D) {
-  DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(),
-                 D->isThisDeclarationADefinition());
+  bool isDef = D->isThisDeclarationADefinition();
+  bool isContainer = isDef;
+  bool isSkipped = false;
+  if (D->hasSkippedBody()) {
+    isSkipped = true;
+    isDef = true;
+    isContainer = false;
+  }
+
+  DeclInfo DInfo(!D->isFirstDeclaration(), isDef, isContainer);
+  if (isSkipped)
+    DInfo.flags |= CXIdxDeclFlag_Skipped;
   return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
 }
 
@@ -548,8 +558,18 @@
 }
 
 bool IndexingContext::handleObjCMethod(const ObjCMethodDecl *D) {
-  DeclInfo DInfo(!D->isCanonicalDecl(), D->isThisDeclarationADefinition(),
-                 D->isThisDeclarationADefinition());
+  bool isDef = D->isThisDeclarationADefinition();
+  bool isContainer = isDef;
+  bool isSkipped = false;
+  if (D->hasSkippedBody()) {
+    isSkipped = true;
+    isDef = true;
+    isContainer = false;
+  }
+
+  DeclInfo DInfo(!D->isCanonicalDecl(), isDef, isContainer);
+  if (isSkipped)
+    DInfo.flags |= CXIdxDeclFlag_Skipped;
   return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
 }
 

Modified: cfe/trunk/tools/libclang/IndexingContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/IndexingContext.h?rev=169539&r1=169538&r2=169539&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/IndexingContext.h (original)
+++ cfe/trunk/tools/libclang/IndexingContext.h Thu Dec  6 13:41:16 2012
@@ -88,6 +88,7 @@
     attributes = 0;
     numAttributes = 0;
     declAsContainer = semanticContainer = lexicalContainer = 0;
+    flags = 0;
   }
   DeclInfo(DInfoKind K,
            bool isRedeclaration, bool isDefinition, bool isContainer)
@@ -98,6 +99,7 @@
     attributes = 0;
     numAttributes = 0;
     declAsContainer = semanticContainer = lexicalContainer = 0;
+    flags = 0;
   }
 };
 





More information about the cfe-commits mailing list