Use precompiled preambles for in-process code completion.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110596 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index bbc8fba..0885037 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -686,7 +686,19 @@
    * clang_reparseTranslationUnit() will re-use the implicit
    * precompiled header to improve parsing performance.
    */
-  CXTranslationUnit_PrecompiledPreamble = 0x04
+  CXTranslationUnit_PrecompiledPreamble = 0x04,
+  /**
+   * \brief Used to indicate that the translation unit is incomplete.
+   *
+   * When a translation unit is considered "incomplete", semantic
+   * analysis that is typically performed at the end of the
+   * translation unit will be suppressed. For example, this suppresses
+   * the completion of tentative declarations in C and of
+   * instantiation of implicitly-instantiation function templates in
+   * C++. This option is typically used when parsing a header with the
+   * intent of producing a precompiled header.
+   */
+  CXTranslationUnit_Incomplete = 0x08
 };
 
 /**
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index e8d4cce..6651743 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -78,9 +78,12 @@
   /// \brief Whether to capture any diagnostics produced.
   bool CaptureDiagnostics;
   
-  /// Track whether the main file was loaded from an AST or not.
+  /// \brief Track whether the main file was loaded from an AST or not.
   bool MainFileIsAST;
 
+  /// \brief Whether this AST represents a complete translation unit.
+  bool CompleteTranslationUnit;
+
   /// Track the top-level decls which appeared in an ASTUnit which was loaded
   /// from a source file.
   //
@@ -199,9 +202,12 @@
   bool Parse(llvm::MemoryBuffer *OverrideMainBuffer);
   
   std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> >
-  ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer);
+  ComputePreamble(CompilerInvocation &Invocation, 
+                  unsigned MaxLines, bool &CreatedBuffer);
   
-  llvm::MemoryBuffer *BuildPrecompiledPreamble();
+  llvm::MemoryBuffer *getMainBufferWithPrecompiledPreamble(
+                                                     bool AllowRebuild = true,
+                                                        unsigned MaxLines = 0);
   void RealizeTopLevelDeclsFromPreamble();
 
 public:
@@ -318,6 +324,12 @@
     return StoredDiagnostics; 
   }
 
+  /// \brief Whether this AST represents a complete translation unit.
+  ///
+  /// If false, this AST is only a partial translation unit, e.g., one
+  /// that might still be used as a precompiled header or preamble.
+  bool isCompleteTranslationUnit() const { return CompleteTranslationUnit; }
+
   /// \brief A mapping from a file name to the memory buffer that stores the
   /// remapped contents of that file.
   typedef std::pair<std::string, const llvm::MemoryBuffer *> RemappedFile;
@@ -352,7 +364,8 @@
                                      llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
                                              bool OnlyLocalDecls = false,
                                              bool CaptureDiagnostics = false,
-                                             bool PrecompilePreamble = false);
+                                             bool PrecompilePreamble = false,
+                                          bool CompleteTranslationUnit = true);
 
   /// LoadFromCommandLine - Create an ASTUnit from a vector of command line
   /// arguments, which must specify exactly one source file.
@@ -376,7 +389,8 @@
                                       RemappedFile *RemappedFiles = 0,
                                       unsigned NumRemappedFiles = 0,
                                       bool CaptureDiagnostics = false,
-                                      bool PrecompilePreamble = false);
+                                      bool PrecompilePreamble = false,
+                                      bool CompleteTranslationUnit = true);
   
   /// \brief Reparse the source files using the same command-line options that
   /// were originally used to produce this translation unit.
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index 66a33f2..9e0fb7e 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -237,11 +237,14 @@
   ///
   /// \param Buffer The memory buffer containing the file's contents.
   ///
+  /// \param MaxLines If non-zero, restrict the length of the preamble
+  /// to fewer than this number of lines.
+  ///
   /// \returns The offset into the file where the preamble ends and the rest
   /// of the file begins along with a boolean value indicating whether 
   /// the preamble ends at the beginning of a new line.
   static std::pair<unsigned, bool>
-  ComputePreamble(const llvm::MemoryBuffer *Buffer);
+  ComputePreamble(const llvm::MemoryBuffer *Buffer, unsigned MaxLines = 0);
                                         
   //===--------------------------------------------------------------------===//
   // Internal implementation interfaces.
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 88c55a8..b287522 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -34,6 +34,7 @@
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/System/Host.h"
 #include "llvm/System/Path.h"
+#include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Timer.h"
 #include <cstdlib>
 #include <cstdio>
@@ -48,8 +49,8 @@
 
 ASTUnit::ASTUnit(bool _MainFileIsAST)
   : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), 
-    ConcurrencyCheckValue(CheckUnlocked), PreambleRebuildCounter(0),
-    SavedMainFileBuffer(0) { 
+    CompleteTranslationUnit(true), ConcurrencyCheckValue(CheckUnlocked), 
+    PreambleRebuildCounter(0), SavedMainFileBuffer(0) { 
 }
 
 ASTUnit::~ASTUnit() {
@@ -334,6 +335,9 @@
   TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
 
   virtual bool hasCodeCompletionSupport() const { return false; }
+  virtual bool usesCompleteTranslationUnit()  { 
+    return Unit.isCompleteTranslationUnit(); 
+  }
 };
 
 class PrecompilePreambleConsumer : public PCHGenerator {
@@ -396,6 +400,7 @@
 
   virtual bool hasCodeCompletionSupport() const { return false; }
   virtual bool hasASTFileSupport() const { return false; }
+  virtual bool usesCompleteTranslationUnit() { return false; }
 };
 
 }
@@ -567,7 +572,8 @@
 /// that corresponds to the main file along with a pair (bytes, start-of-line)
 /// that describes the preamble.
 std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > 
-ASTUnit::ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer) {
+ASTUnit::ComputePreamble(CompilerInvocation &Invocation, 
+                         unsigned MaxLines, bool &CreatedBuffer) {
   FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
   PreprocessorOptions &PreprocessorOpts
     = Invocation.getPreprocessorOpts();
@@ -642,7 +648,7 @@
     CreatedBuffer = true;
   }
   
-  return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer));
+  return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer, MaxLines));
 }
 
 static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
@@ -673,10 +679,19 @@
 /// this routine will determine if it is still valid and, if so, avoid 
 /// rebuilding the precompiled preamble.
 ///
+/// \param AllowRebuild When true (the default), this routine is
+/// allowed to rebuild the precompiled preamble if it is found to be
+/// out-of-date.
+///
+/// \param MaxLines When non-zero, the maximum number of lines that
+/// can occur within the preamble.
+///
 /// \returns If the precompiled preamble can be used, returns a newly-allocated
 /// buffer that should be used in place of the main file when doing so.
 /// Otherwise, returns a NULL pointer.
-llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
+llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
+                                                           bool AllowRebuild,
+                                                           unsigned MaxLines) {
   CompilerInvocation PreambleInvocation(*Invocation);
   FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts();
   PreprocessorOptions &PreprocessorOpts
@@ -684,7 +699,7 @@
 
   bool CreatedPreambleBuffer = false;
   std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble 
-    = ComputePreamble(PreambleInvocation, CreatedPreambleBuffer);
+    = ComputePreamble(PreambleInvocation, MaxLines, CreatedPreambleBuffer);
 
   if (!NewPreamble.second.first) {
     // We couldn't find a preamble in the main source. Clear out the current
@@ -793,12 +808,21 @@
                                           FrontendOpts.Inputs[0].second);
       }
     }
+
+    // If we aren't allowed to rebuild the precompiled preamble, just
+    // return now.
+    if (!AllowRebuild)
+      return 0;
     
     // We can't reuse the previously-computed preamble. Build a new one.
     Preamble.clear();
     llvm::sys::Path(PreambleFile).eraseFromDisk();
     PreambleRebuildCounter = 1;
-  } 
+  } else if (!AllowRebuild) {
+    // We aren't allowed to rebuild the precompiled preamble; just
+    // return now.
+    return 0;
+  }
 
   // If the preamble rebuild counter > 1, it's because we previously
   // failed to build a preamble and we're not yet ready to try
@@ -1004,7 +1028,8 @@
                                    llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
                                              bool OnlyLocalDecls,
                                              bool CaptureDiagnostics,
-                                             bool PrecompilePreamble) {
+                                             bool PrecompilePreamble,
+                                             bool CompleteTranslationUnit) {
   if (!Diags.getPtr()) {
     // No diagnostics engine was provided, so create our own diagnostics object
     // with the default options.
@@ -1018,6 +1043,7 @@
   AST->Diagnostics = Diags;
   AST->CaptureDiagnostics = CaptureDiagnostics;
   AST->OnlyLocalDecls = OnlyLocalDecls;
+  AST->CompleteTranslationUnit = CompleteTranslationUnit;
   AST->Invocation.reset(CI);
   CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
   
@@ -1030,7 +1056,7 @@
   // FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble.
   if (PrecompilePreamble && !CI->getLangOpts().CPlusPlus) {
     AST->PreambleRebuildCounter = 1;
-    OverrideMainBuffer = AST->BuildPrecompiledPreamble();
+    OverrideMainBuffer = AST->getMainBufferWithPrecompiledPreamble();
   }
   
   llvm::Timer *ParsingTimer = 0;
@@ -1055,7 +1081,8 @@
                                       RemappedFile *RemappedFiles,
                                       unsigned NumRemappedFiles,
                                       bool CaptureDiagnostics,
-                                      bool PrecompilePreamble) {
+                                      bool PrecompilePreamble,
+                                      bool CompleteTranslationUnit) {
   if (!Diags.getPtr()) {
     // No diagnostics engine was provided, so create our own diagnostics object
     // with the default options.
@@ -1116,7 +1143,8 @@
 
   CI->getFrontendOpts().DisableFree = true;
   return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
-                                    CaptureDiagnostics, PrecompilePreamble);
+                                    CaptureDiagnostics, PrecompilePreamble,
+                                    CompleteTranslationUnit);
 }
 
 bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
@@ -1140,7 +1168,7 @@
   // build a precompiled preamble, do so now.
   llvm::MemoryBuffer *OverrideMainBuffer = 0;
   if (!PreambleFile.empty() || PreambleRebuildCounter > 0)
-    OverrideMainBuffer = BuildPrecompiledPreamble();
+    OverrideMainBuffer = getMainBufferWithPrecompiledPreamble();
     
   // Clear out the diagnostics state.
   if (!OverrideMainBuffer)
@@ -1165,6 +1193,17 @@
   if (!Invocation.get())
     return;
 
+  llvm::Timer *CompletionTimer = 0;
+  if (TimerGroup.get()) {
+    llvm::SmallString<128> TimerName;
+    llvm::raw_svector_ostream TimerNameOut(TimerName);
+    TimerNameOut << "Code completion @ " << File << ":" << Line << ":" 
+                 << Column;
+    CompletionTimer = new llvm::Timer(TimerNameOut.str(), *TimerGroup);
+    CompletionTimer->startTimer();
+    Timers.push_back(CompletionTimer);
+  }
+
   CompilerInvocation CCInvocation(*Invocation);
   FrontendOptions &FrontendOpts = CCInvocation.getFrontendOpts();
   PreprocessorOptions &PreprocessorOpts = CCInvocation.getPreprocessorOpts();
@@ -1230,6 +1269,42 @@
   // Use the code completion consumer we were given.
   Clang.setCodeCompletionConsumer(&Consumer);
 
+  // If we have a precompiled preamble, try to use it. We only allow
+  // the use of the precompiled preamble if we're if the completion
+  // point is within the main file, after the end of the precompiled
+  // preamble.
+  llvm::MemoryBuffer *OverrideMainBuffer = 0;
+  if (!PreambleFile.empty()) {
+    using llvm::sys::FileStatus;
+    llvm::sys::PathWithStatus CompleteFilePath(File);
+    llvm::sys::PathWithStatus MainPath(OriginalSourceFile);
+    if (const FileStatus *CompleteFileStatus = CompleteFilePath.getFileStatus())
+      if (const FileStatus *MainStatus = MainPath.getFileStatus())
+        if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID())
+          OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(false, 
+                                                                    Line);
+  }
+
+  // If the main file has been overridden due to the use of a preamble,
+  // make that override happen and introduce the preamble.
+  if (OverrideMainBuffer) {
+    PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
+    PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
+    PreprocessorOpts.PrecompiledPreambleBytes.second
+                                                    = PreambleEndsAtStartOfLine;
+    PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
+    PreprocessorOpts.DisablePCHValidation = true;
+    
+    // The stored diagnostics have the old source manager. Copy them
+    // to our output set of stored diagnostics, updating the source
+    // manager to the one we were given.
+    for (unsigned I = 0, N = this->StoredDiagnostics.size(); I != N; ++I) {
+      StoredDiagnostics.push_back(this->StoredDiagnostics[I]);
+      FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SourceMgr);
+      StoredDiagnostics[I].setLocation(Loc);
+    }
+  }
+
   llvm::OwningPtr<SyntaxOnlyAction> Act;
   Act.reset(new SyntaxOnlyAction);
   if (Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
@@ -1237,8 +1312,12 @@
     Act->Execute();
     Act->EndSourceFile();
   }
+
+  if (CompletionTimer)
+    CompletionTimer->stopTimer();
   
   // Steal back our resources. 
+  delete OverrideMainBuffer;
   Clang.takeFileManager();
   Clang.takeSourceManager();
   Clang.takeInvocation();
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 5e43590..b492d77 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -311,7 +311,7 @@
 }
 
 std::pair<unsigned, bool>
-Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer) {
+Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, unsigned MaxLines) {
   // Create a lexer starting at the beginning of the file. Note that we use a
   // "fake" file source location at offset 1 so that the lexer will track our
   // position within the file.
@@ -325,6 +325,8 @@
   Token TheTok;
   Token IfStartTok;
   unsigned IfCount = 0;
+  unsigned Line = 0;
+
   do {
     TheLexer.LexFromRawLexer(TheTok);
 
@@ -345,6 +347,16 @@
       InPreprocessorDirective = false;
     }
     
+    // Keep track of the # of lines in the preamble.
+    if (TheTok.isAtStartOfLine()) {
+      ++Line;
+
+      // If we were asked to limit the number of lines in the preamble,
+      // and we're about to exceed that limit, we're done.
+      if (MaxLines && Line >= MaxLines)
+        break;
+    }
+
     // Comments are okay; skip over them.
     if (TheTok.getKind() == tok::comment)
       continue;
@@ -418,7 +430,9 @@
       TheTok = HashTok;
     }
 
-    // We hit a token
+    // We hit a token that we don't recognize as being in the
+    // "preprocessing only" part of the file, so we're no longer in
+    // the preamble.
     break;
   } while (true);
   
diff --git a/test/Index/preamble.c b/test/Index/preamble.c
index 7e75bf9..c285cd2 100644
--- a/test/Index/preamble.c
+++ b/test/Index/preamble.c
@@ -2,6 +2,9 @@
 #include "preamble.h"
 int wibble(int);
 
+void f(int x) {
+  
+}
 // RUN: %clang -x c-header -o %t.pch %S/Inputs/prefix.h
 // RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -I %S/Inputs -include %t %s 2> %t.stderr.txt | FileCheck %s
 // RUN: FileCheck -check-prefix CHECK-DIAG %s < %t.stderr.txt
@@ -18,3 +21,8 @@
 // CHECK: preamble.c:3:5: FunctionDecl=wibble:3:5 Extent=[3:5 - 3:16]
 // CHECK: preamble.c:3:15: ParmDecl=:3:15 (Definition) Extent=[3:12 - 3:16]
 // CHECK-DIAG: preamble.h:4:7:{4:9-4:13}: warning: incompatible pointer types assigning to 'int *' from 'float *'
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:6:1 -I %S/Inputs -include %t %s 2> %t.stderr.txt | FileCheck -check-prefix CHECK-CC %s
+// CHECK-CC: FunctionDecl:{ResultType int}{TypedText bar}{LeftParen (}{Placeholder int i}{RightParen )} (50)
+// CHECK-CC: FunctionDecl:{ResultType void}{TypedText f}{LeftParen (}{Placeholder int x}{RightParen )} (50)
+// CHECK-CC: FunctionDecl:{ResultType int}{TypedText foo}{LeftParen (}{Placeholder int}{RightParen )} (50)
+// CHECK-CC: FunctionDecl:{ResultType int}{TypedText wibble}{LeftParen (}{Placeholder int}{RightParen )} (50)
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 1530aa8..db897b3 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -874,7 +874,8 @@
   struct CXUnsavedFile *unsaved_files = 0;
   int num_unsaved_files = 0;
   CXCodeCompleteResults *results = 0;
-
+  CXTranslationUnit *TU = 0;
+  
   if (timing_only)
     input += strlen("-code-completion-timing=");
   else
@@ -889,15 +890,20 @@
 
   CIdx = clang_createIndex(0, 1);
   if (getenv("CINDEXTEST_EDITING")) {
-    CXTranslationUnit *TU = clang_parseTranslationUnit(CIdx, 0,
-                                  argv + num_unsaved_files + 2,
-                                  argc - num_unsaved_files - 2,
-                                  unsaved_files,
-                                  num_unsaved_files,
-                                  getDefaultParsingOptions());
-    results = clang_codeCompleteAt(TU, filename, line, column,
-                                   unsaved_files, num_unsaved_files,
-                                   clang_defaultCodeCompleteOptions());
+    TU = clang_parseTranslationUnit(CIdx, 0,
+                                    argv + num_unsaved_files + 2,
+                                    argc - num_unsaved_files - 2,
+                                    unsaved_files,
+                                    num_unsaved_files,
+                                    getDefaultParsingOptions());
+    unsigned I, Repeats = 5;
+    for (I = 0; I != Repeats; ++I) {
+      results = clang_codeCompleteAt(TU, filename, line, column,
+                                     unsaved_files, num_unsaved_files,
+                                     clang_defaultCodeCompleteOptions());
+      if (I != Repeats-1)
+        clang_disposeCodeCompleteResults(results);
+    }
   } else
     results = clang_codeComplete(CIdx,
                                  argv[argc - 1], argc - num_unsaved_files - 3,
@@ -918,7 +924,7 @@
     }
     clang_disposeCodeCompleteResults(results);
   }
-
+  clang_disposeTranslationUnit(TU);
   clang_disposeIndex(CIdx);
   free(filename);
 
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 6414166..60eef4d 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1195,7 +1195,9 @@
   if (options & CXTranslationUnit_Editing)
     options |= CXTranslationUnit_PrecompiledPreamble;
   bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble;
-  
+  bool CompleteTranslationUnit
+    = ((options & CXTranslationUnit_Incomplete) == 0);
+
   // Configure the diagnostics.
   DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
@@ -1250,7 +1252,8 @@
                                    RemappedFiles.data(),
                                    RemappedFiles.size(),
                                    /*CaptureDiagnostics=*/true,
-                                   PrecompilePreamble));
+                                   PrecompilePreamble,
+                                   CompleteTranslationUnit));
 
     if (NumErrors != Diags->getNumErrors()) {
       // Make sure to check that 'Unit' is non-NULL.
@@ -1451,7 +1454,7 @@
   return static_cast<ASTUnit *>(TU)->Reparse(RemappedFiles.data(),
                                              RemappedFiles.size())? 1 : 0;
 }
-  
+
 CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
   if (!CTUnit)
     return createCXString("");
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 4ab6b9b..790f32f 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -20,17 +20,18 @@
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
 #include "llvm/System/Program.h"
 #include <cstdlib>
 #include <cstdio>
 
+
 #ifdef UDP_CODE_COMPLETION_LOGGER
 #include "clang/Basic/Version.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Timer.h"
-#include "llvm/Support/raw_ostream.h"
 #include <arpa/inet.h>
 #include <sys/socket.h>
 #include <sys/types.h>
@@ -277,7 +278,16 @@
 #endif
 
   bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0;
-  
+
+  llvm::OwningPtr<llvm::NamedRegionTimer> CCTimer;
+  if (getenv("LIBCLANG_TIMING")) {
+    llvm::SmallString<128> TimerName;
+    llvm::raw_svector_ostream TimerNameOut(TimerName);
+    TimerNameOut << "Code completion @ " << complete_filename << ":"
+      << complete_line << ":" << complete_column;
+    CCTimer.reset(new llvm::NamedRegionTimer(TimerNameOut.str()));
+  }
+
   // The indexer, which is mainly used to determine where diagnostics go.
   CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);