From 36c49e3f258dced101949edabd72e9bc3f1dedc4 Mon Sep 17 00:00:00 2001
From: dim <dim@FreeBSD.org>
Date: Fri, 17 Sep 2010 15:54:40 +0000
Subject: Vendor import of clang r114020 (from the release_28 branch):
 http://llvm.org/svn/llvm-project/cfe/branches/release_28@114020

Approved by:	rpaulo (mentor)
---
 lib/Frontend/ASTUnit.cpp | 1586 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 1500 insertions(+), 86 deletions(-)

(limited to 'lib/Frontend/ASTUnit.cpp')

diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 88f0037..c76488b 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -12,10 +12,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/PCHReader.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/DeclVisitor.h"
+#include "clang/AST/TypeOrdering.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/Driver.h"
@@ -25,30 +25,294 @@
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/FrontendOptions.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/ASTWriter.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Basic/TargetOptions.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/StringSet.h"
 #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>
+#include <sys/stat.h>
 using namespace clang;
 
+/// \brief After failing to build a precompiled preamble (due to
+/// errors in the source that occurs in the preamble), the number of
+/// reparses during which we'll skip even trying to precompile the
+/// preamble.
+const unsigned DefaultPreambleRebuildInterval = 5;
+
 ASTUnit::ASTUnit(bool _MainFileIsAST)
-  : MainFileIsAST(_MainFileIsAST), ConcurrencyCheckValue(CheckUnlocked) { }
+  : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), 
+    CompleteTranslationUnit(true), ConcurrencyCheckValue(CheckUnlocked), 
+    PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
+    ShouldCacheCodeCompletionResults(false),
+    NumTopLevelDeclsAtLastCompletionCache(0),
+    CacheCodeCompletionCoolDown(0),
+    UnsafeToFree(false) { 
+}
 
 ASTUnit::~ASTUnit() {
   ConcurrencyCheckValue = CheckLocked;
+  CleanTemporaryFiles();
+  if (!PreambleFile.empty())
+    llvm::sys::Path(PreambleFile).eraseFromDisk();
+  
+  // Free the buffers associated with remapped files. We are required to
+  // perform this operation here because we explicitly request that the
+  // compiler instance *not* free these buffers for each invocation of the
+  // parser.
+  if (Invocation.get()) {
+    PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
+    for (PreprocessorOptions::remapped_file_buffer_iterator
+           FB = PPOpts.remapped_file_buffer_begin(),
+           FBEnd = PPOpts.remapped_file_buffer_end();
+         FB != FBEnd;
+         ++FB)
+      delete FB->second;
+  }
+  
+  delete SavedMainFileBuffer;
+  delete PreambleBuffer;
+
+  ClearCachedCompletionResults();
+  
+  for (unsigned I = 0, N = Timers.size(); I != N; ++I)
+    delete Timers[I];
+}
+
+void ASTUnit::CleanTemporaryFiles() {
   for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
     TemporaryFiles[I].eraseFromDisk();
+  TemporaryFiles.clear();
+}
+
+/// \brief Determine the set of code-completion contexts in which this 
+/// declaration should be shown.
+static unsigned getDeclShowContexts(NamedDecl *ND,
+                                    const LangOptions &LangOpts,
+                                    bool &IsNestedNameSpecifier) {
+  IsNestedNameSpecifier = false;
+  
+  if (isa<UsingShadowDecl>(ND))
+    ND = dyn_cast<NamedDecl>(ND->getUnderlyingDecl());
+  if (!ND)
+    return 0;
+  
+  unsigned Contexts = 0;
+  if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND) || 
+      isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND)) {
+    // Types can appear in these contexts.
+    if (LangOpts.CPlusPlus || !isa<TagDecl>(ND))
+      Contexts |= (1 << (CodeCompletionContext::CCC_TopLevel - 1))
+                | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
+                | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
+                | (1 << (CodeCompletionContext::CCC_Statement - 1))
+                | (1 << (CodeCompletionContext::CCC_Type - 1));
+
+    // In C++, types can appear in expressions contexts (for functional casts).
+    if (LangOpts.CPlusPlus)
+      Contexts |= (1 << (CodeCompletionContext::CCC_Expression - 1));
+    
+    // In Objective-C, message sends can send interfaces. In Objective-C++,
+    // all types are available due to functional casts.
+    if (LangOpts.CPlusPlus || isa<ObjCInterfaceDecl>(ND))
+      Contexts |= (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
+
+    // Deal with tag names.
+    if (isa<EnumDecl>(ND)) {
+      Contexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1));
+      
+      // Part of the nested-name-specifier in C++0x.
+      if (LangOpts.CPlusPlus0x)
+        IsNestedNameSpecifier = true;
+    } else if (RecordDecl *Record = dyn_cast<RecordDecl>(ND)) {
+      if (Record->isUnion())
+        Contexts |= (1 << (CodeCompletionContext::CCC_UnionTag - 1));
+      else
+        Contexts |= (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1));
+      
+      if (LangOpts.CPlusPlus)
+        IsNestedNameSpecifier = true;
+    } else if (isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND))
+      IsNestedNameSpecifier = true;
+  } else if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
+    // Values can appear in these contexts.
+    Contexts = (1 << (CodeCompletionContext::CCC_Statement - 1))
+             | (1 << (CodeCompletionContext::CCC_Expression - 1))
+             | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
+  } else if (isa<ObjCProtocolDecl>(ND)) {
+    Contexts = (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1));
+  } else if (isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) {
+    Contexts = (1 << (CodeCompletionContext::CCC_Namespace - 1));
+   
+    // Part of the nested-name-specifier.
+    IsNestedNameSpecifier = true;
+  }
+  
+  return Contexts;
+}
+
+void ASTUnit::CacheCodeCompletionResults() {
+  if (!TheSema)
+    return;
+  
+  llvm::Timer *CachingTimer = 0;
+  if (TimerGroup.get()) {
+    CachingTimer = new llvm::Timer("Cache global code completions", 
+                                   *TimerGroup);
+    CachingTimer->startTimer();
+    Timers.push_back(CachingTimer);
+  }
+
+  // Clear out the previous results.
+  ClearCachedCompletionResults();
+  
+  // Gather the set of global code completions.
+  typedef CodeCompletionResult Result;
+  llvm::SmallVector<Result, 8> Results;
+  TheSema->GatherGlobalCodeCompletions(Results);
+  
+  // Translate global code completions into cached completions.
+  llvm::DenseMap<CanQualType, unsigned> CompletionTypes;
+  
+  for (unsigned I = 0, N = Results.size(); I != N; ++I) {
+    switch (Results[I].Kind) {
+    case Result::RK_Declaration: {
+      bool IsNestedNameSpecifier = false;
+      CachedCodeCompletionResult CachedResult;
+      CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema);
+      CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration,
+                                                        Ctx->getLangOptions(),
+                                                        IsNestedNameSpecifier);
+      CachedResult.Priority = Results[I].Priority;
+      CachedResult.Kind = Results[I].CursorKind;
+      CachedResult.Availability = Results[I].Availability;
+
+      // Keep track of the type of this completion in an ASTContext-agnostic 
+      // way.
+      QualType UsageType = getDeclUsageType(*Ctx, Results[I].Declaration);
+      if (UsageType.isNull()) {
+        CachedResult.TypeClass = STC_Void;
+        CachedResult.Type = 0;
+      } else {
+        CanQualType CanUsageType
+          = Ctx->getCanonicalType(UsageType.getUnqualifiedType());
+        CachedResult.TypeClass = getSimplifiedTypeClass(CanUsageType);
+
+        // Determine whether we have already seen this type. If so, we save
+        // ourselves the work of formatting the type string by using the 
+        // temporary, CanQualType-based hash table to find the associated value.
+        unsigned &TypeValue = CompletionTypes[CanUsageType];
+        if (TypeValue == 0) {
+          TypeValue = CompletionTypes.size();
+          CachedCompletionTypes[QualType(CanUsageType).getAsString()]
+            = TypeValue;
+        }
+        
+        CachedResult.Type = TypeValue;
+      }
+      
+      CachedCompletionResults.push_back(CachedResult);
+      
+      /// Handle nested-name-specifiers in C++.
+      if (TheSema->Context.getLangOptions().CPlusPlus && 
+          IsNestedNameSpecifier && !Results[I].StartsNestedNameSpecifier) {
+        // The contexts in which a nested-name-specifier can appear in C++.
+        unsigned NNSContexts
+          = (1 << (CodeCompletionContext::CCC_TopLevel - 1))
+          | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
+          | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
+          | (1 << (CodeCompletionContext::CCC_Statement - 1))
+          | (1 << (CodeCompletionContext::CCC_Expression - 1))
+          | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
+          | (1 << (CodeCompletionContext::CCC_EnumTag - 1))
+          | (1 << (CodeCompletionContext::CCC_UnionTag - 1))
+          | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1))
+          | (1 << (CodeCompletionContext::CCC_Type - 1))
+          | (1 << (CodeCompletionContext::CCC_PotentiallyQualifiedName - 1));
+
+        if (isa<NamespaceDecl>(Results[I].Declaration) ||
+            isa<NamespaceAliasDecl>(Results[I].Declaration))
+          NNSContexts |= (1 << (CodeCompletionContext::CCC_Namespace - 1));
+
+        if (unsigned RemainingContexts 
+                                = NNSContexts & ~CachedResult.ShowInContexts) {
+          // If there any contexts where this completion can be a 
+          // nested-name-specifier but isn't already an option, create a 
+          // nested-name-specifier completion.
+          Results[I].StartsNestedNameSpecifier = true;
+          CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema);
+          CachedResult.ShowInContexts = RemainingContexts;
+          CachedResult.Priority = CCP_NestedNameSpecifier;
+          CachedResult.TypeClass = STC_Void;
+          CachedResult.Type = 0;
+          CachedCompletionResults.push_back(CachedResult);
+        }
+      }
+      break;
+    }
+        
+    case Result::RK_Keyword:
+    case Result::RK_Pattern:
+      // Ignore keywords and patterns; we don't care, since they are so
+      // easily regenerated.
+      break;
+      
+    case Result::RK_Macro: {
+      CachedCodeCompletionResult CachedResult;
+      CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema);
+      CachedResult.ShowInContexts
+        = (1 << (CodeCompletionContext::CCC_TopLevel - 1))
+        | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1))
+        | (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1))
+        | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
+        | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
+        | (1 << (CodeCompletionContext::CCC_Statement - 1))
+        | (1 << (CodeCompletionContext::CCC_Expression - 1))
+        | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
+        | (1 << (CodeCompletionContext::CCC_MacroNameUse - 1))
+        | (1 << (CodeCompletionContext::CCC_PreprocessorExpression - 1));
+      
+      CachedResult.Priority = Results[I].Priority;
+      CachedResult.Kind = Results[I].CursorKind;
+      CachedResult.Availability = Results[I].Availability;
+      CachedResult.TypeClass = STC_Void;
+      CachedResult.Type = 0;
+      CachedCompletionResults.push_back(CachedResult);
+      break;
+    }
+    }
+    Results[I].Destroy();
+  }
+
+  if (CachingTimer)
+    CachingTimer->stopTimer();
+  
+  // Make a note of the state when we performed this caching.
+  NumTopLevelDeclsAtLastCompletionCache = top_level_size();
+  CacheCodeCompletionCoolDown = 15;
+}
+
+void ASTUnit::ClearCachedCompletionResults() {
+  for (unsigned I = 0, N = CachedCompletionResults.size(); I != N; ++I)
+    delete CachedCompletionResults[I].Completion;
+  CachedCompletionResults.clear();
+  CachedCompletionTypes.clear();
 }
 
 namespace {
 
-/// \brief Gathers information from PCHReader that will be used to initialize
+/// \brief Gathers information from ASTReader that will be used to initialize
 /// a Preprocessor.
-class PCHInfoCollector : public PCHReaderListener {
+class ASTInfoCollector : public ASTReaderListener {
   LangOptions &LangOpt;
   HeaderSearch &HSI;
   std::string &TargetTriple;
@@ -58,7 +322,7 @@ class PCHInfoCollector : public PCHReaderListener {
   unsigned NumHeaderInfos;
 
 public:
-  PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
+  ASTInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
                    std::string &TargetTriple, std::string &Predefines,
                    unsigned &Counter)
     : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
@@ -115,14 +379,19 @@ class CaptureDroppedDiagnostics {
 public:
   CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags, 
                            llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
-    : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient()) 
+    : Diags(Diags), Client(StoredDiags), PreviousClient(0)
   {
-    if (RequestCapture || Diags.getClient() == 0)
+    if (RequestCapture || Diags.getClient() == 0) {
+      PreviousClient = Diags.takeClient();
       Diags.setClient(&Client);
+    }
   }
 
   ~CaptureDroppedDiagnostics() {
-    Diags.setClient(PreviousClient);
+    if (Diags.getClient() == &Client) {
+      Diags.takeClient();
+      Diags.setClient(PreviousClient);
+    }
   }
 };
 
@@ -137,12 +406,12 @@ const std::string &ASTUnit::getOriginalSourceFileName() {
   return OriginalSourceFile;
 }
 
-const std::string &ASTUnit::getPCHFileName() {
-  assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
-  return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
+const std::string &ASTUnit::getASTFileName() {
+  assert(isMainFileAST() && "Not an ASTUnit from an AST file!");
+  return static_cast<ASTReader *>(Ctx->getExternalSource())->getFileName();
 }
 
-ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
+ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
                                   llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
                                   bool OnlyLocalDecls,
                                   RemappedFile *RemappedFiles,
@@ -156,13 +425,14 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
     DiagnosticOptions DiagOpts;
     Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
   }
-  
+
+  AST->CaptureDiagnostics = CaptureDiagnostics;
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->Diagnostics = Diags;
   AST->FileMgr.reset(new FileManager);
   AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
   AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
-
+  
   // If requested, capture diagnostics in the ASTUnit.
   CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
                                     AST->StoredDiagnostics);
@@ -194,34 +464,33 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
   std::string Predefines;
   unsigned Counter;
 
-  llvm::OwningPtr<PCHReader> Reader;
-  llvm::OwningPtr<ExternalASTSource> Source;
+  llvm::OwningPtr<ASTReader> Reader;
 
-  Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
+  Reader.reset(new ASTReader(AST->getSourceManager(), AST->getFileManager(),
                              AST->getDiagnostics()));
-  Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
+  Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple,
                                            Predefines, Counter));
 
-  switch (Reader->ReadPCH(Filename)) {
-  case PCHReader::Success:
+  switch (Reader->ReadAST(Filename)) {
+  case ASTReader::Success:
     break;
 
-  case PCHReader::Failure:
-  case PCHReader::IgnorePCH:
+  case ASTReader::Failure:
+  case ASTReader::IgnorePCH:
     AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
     return NULL;
   }
 
   AST->OriginalSourceFile = Reader->getOriginalSourceFile();
 
-  // PCH loaded successfully. Now create the preprocessor.
+  // AST file loaded successfully. Now create the preprocessor.
 
   // Get information about the target being compiled for.
   //
-  // FIXME: This is broken, we should store the TargetOptions in the PCH.
+  // FIXME: This is broken, we should store the TargetOptions in the AST file.
   TargetOptions TargetOpts;
   TargetOpts.ABI = "";
-  TargetOpts.CXXABI = "itanium";
+  TargetOpts.CXXABI = "";
   TargetOpts.CPU = "";
   TargetOpts.Features.clear();
   TargetOpts.Triple = TargetTriple;
@@ -244,18 +513,26 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
                                 PP.getIdentifierTable(),
                                 PP.getSelectorTable(),
                                 PP.getBuiltinInfo(),
-                                /* FreeMemory = */ false,
                                 /* size_reserve = */0));
   ASTContext &Context = *AST->Ctx.get();
 
   Reader->InitializeContext(Context);
 
-  // Attach the PCH reader to the AST context as an external AST
+  // Attach the AST reader to the AST context as an external AST
   // source, so that declarations will be deserialized from the
-  // PCH file as needed.
-  Source.reset(Reader.take());
+  // AST file as needed.
+  ASTReader *ReaderPtr = Reader.get();
+  llvm::OwningPtr<ExternalASTSource> Source(Reader.take());
   Context.setExternalSource(Source);
 
+  // Create an AST consumer, even though it isn't used.
+  AST->Consumer.reset(new ASTConsumer);
+  
+  // Create a semantic analysis object and tell the AST reader about it.
+  AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer));
+  AST->TheSema->Initialize();
+  ReaderPtr->InitializeSema(*AST->TheSema);
+
   return AST.take();
 }
 
@@ -276,9 +553,12 @@ public:
       // fundamental problem in the parser right now.
       if (isa<ObjCMethodDecl>(D))
         continue;
-      Unit.getTopLevelDecls().push_back(D);
+      Unit.addTopLevelDecl(D);
     }
   }
+
+  // We're not interested in "interesting" decls.
+  void HandleInterestingDecl(DeclGroupRef) {}
 };
 
 class TopLevelDeclTrackerAction : public ASTFrontendAction {
@@ -294,37 +574,108 @@ public:
   TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
 
   virtual bool hasCodeCompletionSupport() const { return false; }
+  virtual bool usesCompleteTranslationUnit()  { 
+    return Unit.isCompleteTranslationUnit(); 
+  }
 };
 
-}
+class PrecompilePreambleConsumer : public PCHGenerator {
+  ASTUnit &Unit;
+  std::vector<Decl *> TopLevelDecls;
 
-ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
-                                   llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
-                                             bool OnlyLocalDecls,
-                                             bool CaptureDiagnostics) {
-  // Create the compiler instance to use for building the AST.
-  CompilerInstance Clang;
-  llvm::OwningPtr<ASTUnit> AST;
-  llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
+public:
+  PrecompilePreambleConsumer(ASTUnit &Unit,
+                             const Preprocessor &PP, bool Chaining,
+                             const char *isysroot, llvm::raw_ostream *Out)
+    : PCHGenerator(PP, Chaining, isysroot, Out), Unit(Unit) { }
 
-  if (!Diags.getPtr()) {
-    // No diagnostics engine was provided, so create our own diagnostics object
-    // with the default options.
-    DiagnosticOptions DiagOpts;
-    Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
+  virtual void HandleTopLevelDecl(DeclGroupRef D) {
+    for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
+      Decl *D = *it;
+      // FIXME: Currently ObjC method declarations are incorrectly being
+      // reported as top-level declarations, even though their DeclContext
+      // is the containing ObjC @interface/@implementation.  This is a
+      // fundamental problem in the parser right now.
+      if (isa<ObjCMethodDecl>(D))
+        continue;
+      TopLevelDecls.push_back(D);
+    }
   }
-  
-  Clang.setInvocation(CI);
 
-  Clang.setDiagnostics(Diags.getPtr());
-  Clang.setDiagnosticClient(Diags->getClient());
+  virtual void HandleTranslationUnit(ASTContext &Ctx) {
+    PCHGenerator::HandleTranslationUnit(Ctx);
+    if (!Unit.getDiagnostics().hasErrorOccurred()) {
+      // Translate the top-level declarations we captured during
+      // parsing into declaration IDs in the precompiled
+      // preamble. This will allow us to deserialize those top-level
+      // declarations when requested.
+      for (unsigned I = 0, N = TopLevelDecls.size(); I != N; ++I)
+        Unit.addTopLevelDeclFromPreamble(
+                                      getWriter().getDeclID(TopLevelDecls[I]));
+    }
+  }
+};
+
+class PrecompilePreambleAction : public ASTFrontendAction {
+  ASTUnit &Unit;
+
+public:
+  explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit) {}
+
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         llvm::StringRef InFile) {
+    std::string Sysroot;
+    llvm::raw_ostream *OS = 0;
+    bool Chaining;
+    if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, 
+                                                       OS, Chaining))
+      return 0;
+    
+    const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
+                             Sysroot.c_str() : 0;  
+    return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Chaining,
+                                          isysroot, OS);
+  }
+
+  virtual bool hasCodeCompletionSupport() const { return false; }
+  virtual bool hasASTFileSupport() const { return false; }
+  virtual bool usesCompleteTranslationUnit() { return false; }
+};
+
+}
 
+/// Parse the source file into a translation unit using the given compiler
+/// invocation, replacing the current translation unit.
+///
+/// \returns True if a failure occurred that causes the ASTUnit not to
+/// contain any translation-unit information, false otherwise.
+bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
+  delete SavedMainFileBuffer;
+  SavedMainFileBuffer = 0;
+  
+  if (!Invocation.get()) {
+    delete OverrideMainBuffer;
+    return true;
+  }
+  
+  // Create the compiler instance to use for building the AST.
+  CompilerInstance Clang;
+  Clang.setInvocation(Invocation.take());
+  OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
+    
+  // Set up diagnostics, capturing any diagnostics that would
+  // otherwise be dropped.
+  Clang.setDiagnostics(&getDiagnostics());
+  CaptureDroppedDiagnostics Capture(CaptureDiagnostics, 
+                                    getDiagnostics(),
+                                    StoredDiagnostics);
+  
   // Create the target instance.
   Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
                                                Clang.getTargetOpts()));
   if (!Clang.hasTarget()) {
-    Clang.takeDiagnosticClient();
-    return 0;
+    delete OverrideMainBuffer;
+    return true;
   }
 
   // Inform the target of the language options.
@@ -332,7 +683,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
   // FIXME: We shouldn't need to do this, the target should be immutable once
   // created. This complexity should be lifted elsewhere.
   Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
-
+  
   assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
          "Invocation must have exactly one source file!");
   assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
@@ -340,53 +691,649 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
   assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
          "IR inputs not support here!");
 
-  // Create the AST unit.
-  AST.reset(new ASTUnit(false));
-  AST->Diagnostics = Diags;
-  AST->FileMgr.reset(new FileManager);
-  AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
-  AST->OnlyLocalDecls = OnlyLocalDecls;
-  AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
-
-  // Capture any diagnostics that would otherwise be dropped.
-  CaptureDroppedDiagnostics Capture(CaptureDiagnostics, 
-                                    Clang.getDiagnostics(),
-                                    AST->StoredDiagnostics);
+  // Configure the various subsystems.
+  // FIXME: Should we retain the previous file manager?
+  FileMgr.reset(new FileManager);
+  SourceMgr.reset(new SourceManager(getDiagnostics()));
+  TheSema.reset();
+  Ctx.reset();
+  PP.reset();
+  
+  // Clear out old caches and data.
+  TopLevelDecls.clear();
+  CleanTemporaryFiles();
+  PreprocessedEntitiesByFile.clear();
+
+  if (!OverrideMainBuffer) {
+    StoredDiagnostics.clear();
+    TopLevelDeclsInPreamble.clear();
+  }
 
   // Create a file manager object to provide access to and cache the filesystem.
-  Clang.setFileManager(&AST->getFileManager());
-
+  Clang.setFileManager(&getFileManager());
+  
   // Create the source manager.
-  Clang.setSourceManager(&AST->getSourceManager());
-
-  Act.reset(new TopLevelDeclTrackerAction(*AST));
+  Clang.setSourceManager(&getSourceManager());
+  
+  // If the main file has been overridden due to the use of a preamble,
+  // make that override happen and introduce the preamble.
+  PreprocessorOptions &PreprocessorOpts = Clang.getPreprocessorOpts();
+  std::string PriorImplicitPCHInclude;
+  if (OverrideMainBuffer) {
+    PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
+    PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
+    PreprocessorOpts.PrecompiledPreambleBytes.second
+                                                    = PreambleEndsAtStartOfLine;
+    PriorImplicitPCHInclude = PreprocessorOpts.ImplicitPCHInclude;
+    PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
+    PreprocessorOpts.DisablePCHValidation = true;
+    
+    // Keep track of the override buffer;
+    SavedMainFileBuffer = OverrideMainBuffer;
+
+    // The stored diagnostic has the old source manager in it; update
+    // the locations to refer into the new source manager. Since we've
+    // been careful to make sure that the source manager's state
+    // before and after are identical, so that we can reuse the source
+    // location itself.
+    for (unsigned I = 0, N = StoredDiagnostics.size(); I != N; ++I) {
+      FullSourceLoc Loc(StoredDiagnostics[I].getLocation(),
+                        getSourceManager());
+      StoredDiagnostics[I].setLocation(Loc);
+    }
+  } else {
+    PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
+    PreprocessorOpts.PrecompiledPreambleBytes.second = false;
+  }
+  
+  llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
+  Act.reset(new TopLevelDeclTrackerAction(*this));
   if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
                             Clang.getFrontendOpts().Inputs[0].first))
     goto error;
-
+  
   Act->Execute();
-
+  
   // Steal the created target, context, and preprocessor, and take back the
   // source and file managers.
-  AST->Ctx.reset(Clang.takeASTContext());
-  AST->PP.reset(Clang.takePreprocessor());
+  TheSema.reset(Clang.takeSema());
+  Consumer.reset(Clang.takeASTConsumer());
+  Ctx.reset(Clang.takeASTContext());
+  PP.reset(Clang.takePreprocessor());
   Clang.takeSourceManager();
   Clang.takeFileManager();
-  AST->Target.reset(Clang.takeTarget());
-
+  Target.reset(Clang.takeTarget());
+  
   Act->EndSourceFile();
 
-  Clang.takeDiagnosticClient();
-  Clang.takeInvocation();
-
-  AST->Invocation.reset(Clang.takeInvocation());
-  return AST.take();
+  // Remove the overridden buffer we used for the preamble.
+  if (OverrideMainBuffer) {
+    PreprocessorOpts.eraseRemappedFile(
+                               PreprocessorOpts.remapped_file_buffer_end() - 1);
+    PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude;
+  }
 
+  Invocation.reset(Clang.takeInvocation());
+  
+  // If we were asked to cache code-completion results and don't have any
+  // results yet, do so now.
+  if (ShouldCacheCodeCompletionResults && CachedCompletionResults.empty())
+    CacheCodeCompletionResults();
+  
+  return false;
+  
 error:
+  // Remove the overridden buffer we used for the preamble.
+  if (OverrideMainBuffer) {
+    PreprocessorOpts.eraseRemappedFile(
+                               PreprocessorOpts.remapped_file_buffer_end() - 1);
+    PreprocessorOpts.DisablePCHValidation = true;
+    PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude;
+    delete OverrideMainBuffer;
+  }
+  
   Clang.takeSourceManager();
   Clang.takeFileManager();
-  Clang.takeDiagnosticClient();
-  return 0;
+  Invocation.reset(Clang.takeInvocation());
+  return true;
+}
+
+/// \brief Simple function to retrieve a path for a preamble precompiled header.
+static std::string GetPreamblePCHPath() {
+  // FIXME: This is lame; sys::Path should provide this function (in particular,
+  // it should know how to find the temporary files dir).
+  // FIXME: This is really lame. I copied this code from the Driver!
+  std::string Error;
+  const char *TmpDir = ::getenv("TMPDIR");
+  if (!TmpDir)
+    TmpDir = ::getenv("TEMP");
+  if (!TmpDir)
+    TmpDir = ::getenv("TMP");
+  if (!TmpDir)
+    TmpDir = "/tmp";
+  llvm::sys::Path P(TmpDir);
+  P.appendComponent("preamble");
+  P.appendSuffix("pch");
+  if (P.createTemporaryFileOnDisk())
+    return std::string();
+  
+  return P.str();
+}
+
+/// \brief Compute the preamble for the main file, providing the source buffer
+/// 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, 
+                         unsigned MaxLines, bool &CreatedBuffer) {
+  FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
+  PreprocessorOptions &PreprocessorOpts
+    = Invocation.getPreprocessorOpts();
+  CreatedBuffer = false;
+  
+  // Try to determine if the main file has been remapped, either from the 
+  // command line (to another file) or directly through the compiler invocation
+  // (to a memory buffer).
+  llvm::MemoryBuffer *Buffer = 0;
+  llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
+  if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
+    // Check whether there is a file-file remapping of the main file
+    for (PreprocessorOptions::remapped_file_iterator
+          M = PreprocessorOpts.remapped_file_begin(),
+          E = PreprocessorOpts.remapped_file_end();
+         M != E;
+         ++M) {
+      llvm::sys::PathWithStatus MPath(M->first);    
+      if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
+        if (MainFileStatus->uniqueID == MStatus->uniqueID) {
+          // We found a remapping. Try to load the resulting, remapped source.
+          if (CreatedBuffer) {
+            delete Buffer;
+            CreatedBuffer = false;
+          }
+          
+          Buffer = llvm::MemoryBuffer::getFile(M->second);
+          if (!Buffer)
+            return std::make_pair((llvm::MemoryBuffer*)0, 
+                                  std::make_pair(0, true));
+          CreatedBuffer = true;
+          
+          // Remove this remapping. We've captured the buffer already.
+          M = PreprocessorOpts.eraseRemappedFile(M);
+          E = PreprocessorOpts.remapped_file_end();
+          if (M == E)
+            break;
+        }
+      }
+    }
+    
+    // Check whether there is a file-buffer remapping. It supercedes the
+    // file-file remapping.
+    for (PreprocessorOptions::remapped_file_buffer_iterator
+           M = PreprocessorOpts.remapped_file_buffer_begin(),
+           E = PreprocessorOpts.remapped_file_buffer_end();
+         M != E;
+         ++M) {
+      llvm::sys::PathWithStatus MPath(M->first);    
+      if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
+        if (MainFileStatus->uniqueID == MStatus->uniqueID) {
+          // We found a remapping. 
+          if (CreatedBuffer) {
+            delete Buffer;
+            CreatedBuffer = false;
+          }
+          
+          Buffer = const_cast<llvm::MemoryBuffer *>(M->second);
+
+          // Remove this remapping. We've captured the buffer already.
+          M = PreprocessorOpts.eraseRemappedFile(M);
+          E = PreprocessorOpts.remapped_file_buffer_end();
+          if (M == E)
+            break;
+        }
+      }
+    }
+  }
+  
+  // If the main source file was not remapped, load it now.
+  if (!Buffer) {
+    Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
+    if (!Buffer)
+      return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));    
+    
+    CreatedBuffer = true;
+  }
+  
+  return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer, MaxLines));
+}
+
+static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
+                                                      bool DeleteOld,
+                                                      unsigned NewSize,
+                                                      llvm::StringRef NewName) {
+  llvm::MemoryBuffer *Result
+    = llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName);
+  memcpy(const_cast<char*>(Result->getBufferStart()), 
+         Old->getBufferStart(), Old->getBufferSize());
+  memset(const_cast<char*>(Result->getBufferStart()) + Old->getBufferSize(), 
+         ' ', NewSize - Old->getBufferSize() - 1);
+  const_cast<char*>(Result->getBufferEnd())[-1] = '\n';  
+  
+  if (DeleteOld)
+    delete Old;
+  
+  return Result;
+}
+
+/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing
+/// the source file.
+///
+/// This routine will compute the preamble of the main source file. If a
+/// non-trivial preamble is found, it will precompile that preamble into a 
+/// precompiled header so that the precompiled preamble can be used to reduce
+/// reparsing time. If a precompiled preamble has already been constructed,
+/// 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::getMainBufferWithPrecompiledPreamble(
+                                          CompilerInvocation PreambleInvocation,
+                                                           bool AllowRebuild,
+                                                           unsigned MaxLines) {
+  FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts();
+  PreprocessorOptions &PreprocessorOpts
+    = PreambleInvocation.getPreprocessorOpts();
+
+  bool CreatedPreambleBuffer = false;
+  std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble 
+    = ComputePreamble(PreambleInvocation, MaxLines, CreatedPreambleBuffer);
+
+  if (!NewPreamble.second.first) {
+    // We couldn't find a preamble in the main source. Clear out the current
+    // preamble, if we have one. It's obviously no good any more.
+    Preamble.clear();
+    if (!PreambleFile.empty()) {
+      llvm::sys::Path(PreambleFile).eraseFromDisk();
+      PreambleFile.clear();
+    }
+    if (CreatedPreambleBuffer)
+      delete NewPreamble.first;
+
+    // The next time we actually see a preamble, precompile it.
+    PreambleRebuildCounter = 1;
+    return 0;
+  }
+  
+  if (!Preamble.empty()) {
+    // We've previously computed a preamble. Check whether we have the same
+    // preamble now that we did before, and that there's enough space in
+    // the main-file buffer within the precompiled preamble to fit the
+    // new main file.
+    if (Preamble.size() == NewPreamble.second.first &&
+        PreambleEndsAtStartOfLine == NewPreamble.second.second &&
+        NewPreamble.first->getBufferSize() < PreambleReservedSize-2 &&
+        memcmp(&Preamble[0], NewPreamble.first->getBufferStart(),
+               NewPreamble.second.first) == 0) {
+      // The preamble has not changed. We may be able to re-use the precompiled
+      // preamble.
+
+      // Check that none of the files used by the preamble have changed.
+      bool AnyFileChanged = false;
+          
+      // First, make a record of those files that have been overridden via
+      // remapping or unsaved_files.
+      llvm::StringMap<std::pair<off_t, time_t> > OverriddenFiles;
+      for (PreprocessorOptions::remapped_file_iterator
+                R = PreprocessorOpts.remapped_file_begin(),
+             REnd = PreprocessorOpts.remapped_file_end();
+           !AnyFileChanged && R != REnd;
+           ++R) {
+        struct stat StatBuf;
+        if (stat(R->second.c_str(), &StatBuf)) {
+          // If we can't stat the file we're remapping to, assume that something
+          // horrible happened.
+          AnyFileChanged = true;
+          break;
+        }
+        
+        OverriddenFiles[R->first] = std::make_pair(StatBuf.st_size, 
+                                                   StatBuf.st_mtime);
+      }
+      for (PreprocessorOptions::remapped_file_buffer_iterator
+                R = PreprocessorOpts.remapped_file_buffer_begin(),
+             REnd = PreprocessorOpts.remapped_file_buffer_end();
+           !AnyFileChanged && R != REnd;
+           ++R) {
+        // FIXME: Should we actually compare the contents of file->buffer
+        // remappings?
+        OverriddenFiles[R->first] = std::make_pair(R->second->getBufferSize(), 
+                                                   0);
+      }
+       
+      // Check whether anything has changed.
+      for (llvm::StringMap<std::pair<off_t, time_t> >::iterator 
+             F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
+           !AnyFileChanged && F != FEnd; 
+           ++F) {
+        llvm::StringMap<std::pair<off_t, time_t> >::iterator Overridden
+          = OverriddenFiles.find(F->first());
+        if (Overridden != OverriddenFiles.end()) {
+          // This file was remapped; check whether the newly-mapped file 
+          // matches up with the previous mapping.
+          if (Overridden->second != F->second)
+            AnyFileChanged = true;
+          continue;
+        }
+        
+        // The file was not remapped; check whether it has changed on disk.
+        struct stat StatBuf;
+        if (stat(F->first(), &StatBuf)) {
+          // If we can't stat the file, assume that something horrible happened.
+          AnyFileChanged = true;
+        } else if (StatBuf.st_size != F->second.first || 
+                   StatBuf.st_mtime != F->second.second)
+          AnyFileChanged = true;
+      }
+          
+      if (!AnyFileChanged) {
+        // Okay! We can re-use the precompiled preamble.
+
+        // Set the state of the diagnostic object to mimic its state
+        // after parsing the preamble.
+        getDiagnostics().Reset();
+        getDiagnostics().setNumWarnings(NumWarningsInPreamble);
+        if (StoredDiagnostics.size() > NumStoredDiagnosticsInPreamble)
+          StoredDiagnostics.erase(
+            StoredDiagnostics.begin() + NumStoredDiagnosticsInPreamble,
+                                  StoredDiagnostics.end());
+
+        // Create a version of the main file buffer that is padded to
+        // buffer size we reserved when creating the preamble.
+        return CreatePaddedMainFileBuffer(NewPreamble.first, 
+                                          CreatedPreambleBuffer,
+                                          PreambleReservedSize,
+                                          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
+  // again. Decrement the counter and return a failure.
+  if (PreambleRebuildCounter > 1) {
+    --PreambleRebuildCounter;
+    return 0;
+  }
+
+  // We did not previously compute a preamble, or it can't be reused anyway.
+  llvm::Timer *PreambleTimer = 0;
+  if (TimerGroup.get()) {
+    PreambleTimer = new llvm::Timer("Precompiling preamble", *TimerGroup);
+    PreambleTimer->startTimer();
+    Timers.push_back(PreambleTimer);
+  }
+  
+  // Create a new buffer that stores the preamble. The buffer also contains
+  // extra space for the original contents of the file (which will be present
+  // when we actually parse the file) along with more room in case the file
+  // grows.  
+  PreambleReservedSize = NewPreamble.first->getBufferSize();
+  if (PreambleReservedSize < 4096)
+    PreambleReservedSize = 8191;
+  else
+    PreambleReservedSize *= 2;
+
+  // Save the preamble text for later; we'll need to compare against it for
+  // subsequent reparses.
+  Preamble.assign(NewPreamble.first->getBufferStart(), 
+                  NewPreamble.first->getBufferStart() 
+                                                  + NewPreamble.second.first);
+  PreambleEndsAtStartOfLine = NewPreamble.second.second;
+
+  delete PreambleBuffer;
+  PreambleBuffer
+    = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize,
+                                                FrontendOpts.Inputs[0].second);
+  memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()), 
+         NewPreamble.first->getBufferStart(), Preamble.size());
+  memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(), 
+         ' ', PreambleReservedSize - Preamble.size() - 1);
+  const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n';  
+  
+  // Remap the main source file to the preamble buffer.
+  llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
+  PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
+  
+  // Tell the compiler invocation to generate a temporary precompiled header.
+  FrontendOpts.ProgramAction = frontend::GeneratePCH;
+  // FIXME: Set ChainedPCH unconditionally, once it is ready.
+  if (::getenv("LIBCLANG_CHAINING"))
+    FrontendOpts.ChainedPCH = true;
+  // FIXME: Generate the precompiled header into memory?
+  FrontendOpts.OutputFile = GetPreamblePCHPath();
+  
+  // Create the compiler instance to use for building the precompiled preamble.
+  CompilerInstance Clang;
+  Clang.setInvocation(&PreambleInvocation);
+  OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
+  
+  // Set up diagnostics, capturing all of the diagnostics produced.
+  Clang.setDiagnostics(&getDiagnostics());
+  CaptureDroppedDiagnostics Capture(CaptureDiagnostics, 
+                                    getDiagnostics(),
+                                    StoredDiagnostics);
+  
+  // Create the target instance.
+  Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
+                                               Clang.getTargetOpts()));
+  if (!Clang.hasTarget()) {
+    llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
+    Preamble.clear();
+    if (CreatedPreambleBuffer)
+      delete NewPreamble.first;
+    if (PreambleTimer)
+      PreambleTimer->stopTimer();
+    PreambleRebuildCounter = DefaultPreambleRebuildInterval;
+    PreprocessorOpts.eraseRemappedFile(
+                               PreprocessorOpts.remapped_file_buffer_end() - 1);
+    return 0;
+  }
+  
+  // Inform the target of the language options.
+  //
+  // FIXME: We shouldn't need to do this, the target should be immutable once
+  // created. This complexity should be lifted elsewhere.
+  Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
+  
+  assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
+         "Invocation must have exactly one source file!");
+  assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
+         "FIXME: AST inputs not yet supported here!");
+  assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+         "IR inputs not support here!");
+  
+  // Clear out old caches and data.
+  StoredDiagnostics.clear();
+  TopLevelDecls.clear();
+  TopLevelDeclsInPreamble.clear();
+  
+  // Create a file manager object to provide access to and cache the filesystem.
+  Clang.setFileManager(new FileManager);
+  
+  // Create the source manager.
+  Clang.setSourceManager(new SourceManager(getDiagnostics()));
+  
+  llvm::OwningPtr<PrecompilePreambleAction> Act;
+  Act.reset(new PrecompilePreambleAction(*this));
+  if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
+                            Clang.getFrontendOpts().Inputs[0].first)) {
+    Clang.takeInvocation();
+    llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
+    Preamble.clear();
+    if (CreatedPreambleBuffer)
+      delete NewPreamble.first;
+    if (PreambleTimer)
+      PreambleTimer->stopTimer();
+    PreambleRebuildCounter = DefaultPreambleRebuildInterval;
+    PreprocessorOpts.eraseRemappedFile(
+                               PreprocessorOpts.remapped_file_buffer_end() - 1);
+    return 0;
+  }
+  
+  Act->Execute();
+  Act->EndSourceFile();
+  Clang.takeInvocation();
+  
+  if (Diagnostics->hasErrorOccurred()) {
+    // There were errors parsing the preamble, so no precompiled header was
+    // generated. Forget that we even tried.
+    // FIXME: Should we leave a note for ourselves to try again?
+    llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
+    Preamble.clear();
+    if (CreatedPreambleBuffer)
+      delete NewPreamble.first;
+    if (PreambleTimer)
+      PreambleTimer->stopTimer();
+    TopLevelDeclsInPreamble.clear();
+    PreambleRebuildCounter = DefaultPreambleRebuildInterval;
+    PreprocessorOpts.eraseRemappedFile(
+                               PreprocessorOpts.remapped_file_buffer_end() - 1);
+    return 0;
+  }
+  
+  // Keep track of the preamble we precompiled.
+  PreambleFile = FrontendOpts.OutputFile;
+  NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
+  NumWarningsInPreamble = getDiagnostics().getNumWarnings();
+  
+  // Keep track of all of the files that the source manager knows about,
+  // so we can verify whether they have changed or not.
+  FilesInPreamble.clear();
+  SourceManager &SourceMgr = Clang.getSourceManager();
+  const llvm::MemoryBuffer *MainFileBuffer
+    = SourceMgr.getBuffer(SourceMgr.getMainFileID());
+  for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(),
+                                     FEnd = SourceMgr.fileinfo_end();
+       F != FEnd;
+       ++F) {
+    const FileEntry *File = F->second->Entry;
+    if (!File || F->second->getRawBuffer() == MainFileBuffer)
+      continue;
+    
+    FilesInPreamble[File->getName()]
+      = std::make_pair(F->second->getSize(), File->getModificationTime());
+  }
+  
+  if (PreambleTimer)
+    PreambleTimer->stopTimer();
+  
+  PreambleRebuildCounter = 1;
+  PreprocessorOpts.eraseRemappedFile(
+                               PreprocessorOpts.remapped_file_buffer_end() - 1);
+  return CreatePaddedMainFileBuffer(NewPreamble.first, 
+                                    CreatedPreambleBuffer,
+                                    PreambleReservedSize,
+                                    FrontendOpts.Inputs[0].second);
+}
+
+void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
+  std::vector<Decl *> Resolved;
+  Resolved.reserve(TopLevelDeclsInPreamble.size());
+  ExternalASTSource &Source = *getASTContext().getExternalSource();
+  for (unsigned I = 0, N = TopLevelDeclsInPreamble.size(); I != N; ++I) {
+    // Resolve the declaration ID to an actual declaration, possibly
+    // deserializing the declaration in the process.
+    Decl *D = Source.GetExternalDecl(TopLevelDeclsInPreamble[I]);
+    if (D)
+      Resolved.push_back(D);
+  }
+  TopLevelDeclsInPreamble.clear();
+  TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end());
+}
+
+unsigned ASTUnit::getMaxPCHLevel() const {
+  if (!getOnlyLocalDecls())
+    return Decl::MaxPCHLevel;
+
+  unsigned Result = 0;
+  if (isMainFileAST() || SavedMainFileBuffer)
+    ++Result;
+  return Result;
+}
+
+ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
+                                   llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+                                             bool OnlyLocalDecls,
+                                             bool CaptureDiagnostics,
+                                             bool PrecompilePreamble,
+                                             bool CompleteTranslationUnit,
+                                             bool CacheCodeCompletionResults) {
+  if (!Diags.getPtr()) {
+    // No diagnostics engine was provided, so create our own diagnostics object
+    // with the default options.
+    DiagnosticOptions DiagOpts;
+    Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
+  }
+  
+  // Create the AST unit.
+  llvm::OwningPtr<ASTUnit> AST;
+  AST.reset(new ASTUnit(false));
+  AST->Diagnostics = Diags;
+  AST->CaptureDiagnostics = CaptureDiagnostics;
+  AST->OnlyLocalDecls = OnlyLocalDecls;
+  AST->CompleteTranslationUnit = CompleteTranslationUnit;
+  AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
+  AST->Invocation.reset(CI);
+  CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
+  
+  if (getenv("LIBCLANG_TIMING"))
+    AST->TimerGroup.reset(
+                  new llvm::TimerGroup(CI->getFrontendOpts().Inputs[0].second));
+  
+  
+  llvm::MemoryBuffer *OverrideMainBuffer = 0;
+  // FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble.
+  if (PrecompilePreamble && !CI->getLangOpts().CPlusPlus) {
+    AST->PreambleRebuildCounter = 1;
+    OverrideMainBuffer
+      = AST->getMainBufferWithPrecompiledPreamble(*AST->Invocation);
+  }
+  
+  llvm::Timer *ParsingTimer = 0;
+  if (AST->TimerGroup.get()) {
+    ParsingTimer = new llvm::Timer("Initial parse", *AST->TimerGroup);
+    ParsingTimer->startTimer();
+    AST->Timers.push_back(ParsingTimer);
+  }
+  
+  bool Failed = AST->Parse(OverrideMainBuffer);
+  if (ParsingTimer)
+    ParsingTimer->stopTimer();
+  
+  return Failed? 0 : AST.take();
 }
 
 ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
@@ -396,12 +1343,18 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
                                       bool OnlyLocalDecls,
                                       RemappedFile *RemappedFiles,
                                       unsigned NumRemappedFiles,
-                                      bool CaptureDiagnostics) {
+                                      bool CaptureDiagnostics,
+                                      bool PrecompilePreamble,
+                                      bool CompleteTranslationUnit,
+                                      bool CacheCodeCompletionResults) {
+  bool CreatedDiagnosticsObject = false;
+  
   if (!Diags.getPtr()) {
     // No diagnostics engine was provided, so create our own diagnostics object
     // with the default options.
     DiagnosticOptions DiagOpts;
     Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
+    CreatedDiagnosticsObject = true;
   }
   
   llvm::SmallVector<const char *, 16> Args;
@@ -413,7 +1366,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
   Args.push_back("-fsyntax-only");
 
   // FIXME: We shouldn't have to pass in the path info.
-  driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
+  driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
                            "a.out", false, false, *Diags);
 
   // Don't check that inputs exist, they have been remapped.
@@ -444,7 +1397,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
   CompilerInvocation::CreateFromArgs(*CI,
                                      const_cast<const char **>(CCArgs.data()),
                                      const_cast<const char **>(CCArgs.data()) +
-                                       CCArgs.size(),
+                                     CCArgs.size(),
                                      *Diags);
 
   // Override any files that need remapping
@@ -455,7 +1408,468 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
   // Override the resources path.
   CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
 
-  CI->getFrontendOpts().DisableFree = true;
+  CI->getFrontendOpts().DisableFree = false;
   return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
-                                    CaptureDiagnostics);
+                                    CaptureDiagnostics, PrecompilePreamble,
+                                    CompleteTranslationUnit,
+                                    CacheCodeCompletionResults);
+}
+
+bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
+  if (!Invocation.get())
+    return true;
+  
+  llvm::Timer *ReparsingTimer = 0;
+  if (TimerGroup.get()) {
+    ReparsingTimer = new llvm::Timer("Reparse", *TimerGroup);
+    ReparsingTimer->startTimer();
+    Timers.push_back(ReparsingTimer);
+  }
+  
+  // Remap files.
+  PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
+  for (PreprocessorOptions::remapped_file_buffer_iterator 
+         R = PPOpts.remapped_file_buffer_begin(),
+         REnd = PPOpts.remapped_file_buffer_end();
+       R != REnd; 
+       ++R) {
+    delete R->second;
+  }
+  Invocation->getPreprocessorOpts().clearRemappedFiles();
+  for (unsigned I = 0; I != NumRemappedFiles; ++I)
+    Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+                                                      RemappedFiles[I].second);
+  
+  // If we have a preamble file lying around, or if we might try to
+  // build a precompiled preamble, do so now.
+  llvm::MemoryBuffer *OverrideMainBuffer = 0;
+  if (!PreambleFile.empty() || PreambleRebuildCounter > 0)
+    OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation);
+    
+  // Clear out the diagnostics state.
+  if (!OverrideMainBuffer)
+    getDiagnostics().Reset();
+  
+  // Parse the sources
+  bool Result = Parse(OverrideMainBuffer);  
+  if (ReparsingTimer)
+    ReparsingTimer->stopTimer();
+  
+  if (ShouldCacheCodeCompletionResults) {
+    if (CacheCodeCompletionCoolDown > 0)
+      --CacheCodeCompletionCoolDown;
+    else if (top_level_size() != NumTopLevelDeclsAtLastCompletionCache)
+      CacheCodeCompletionResults();
+  }
+  
+  return Result;
+}
+
+//----------------------------------------------------------------------------//
+// Code completion
+//----------------------------------------------------------------------------//
+
+namespace {
+  /// \brief Code completion consumer that combines the cached code-completion
+  /// results from an ASTUnit with the code-completion results provided to it,
+  /// then passes the result on to 
+  class AugmentedCodeCompleteConsumer : public CodeCompleteConsumer {
+    unsigned NormalContexts;
+    ASTUnit &AST;
+    CodeCompleteConsumer &Next;
+    
+  public:
+    AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next,
+                                  bool IncludeMacros, bool IncludeCodePatterns,
+                                  bool IncludeGlobals)
+      : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals,
+                             Next.isOutputBinary()), AST(AST), Next(Next) 
+    { 
+      // Compute the set of contexts in which we will look when we don't have
+      // any information about the specific context.
+      NormalContexts 
+        = (1 << (CodeCompletionContext::CCC_TopLevel - 1))
+        | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1))
+        | (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1))
+        | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
+        | (1 << (CodeCompletionContext::CCC_Statement - 1))
+        | (1 << (CodeCompletionContext::CCC_Expression - 1))
+        | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
+        | (1 << (CodeCompletionContext::CCC_MemberAccess - 1))
+        | (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1));
+      
+      if (AST.getASTContext().getLangOptions().CPlusPlus)
+        NormalContexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1))
+                    | (1 << (CodeCompletionContext::CCC_UnionTag - 1))
+                    | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1));
+    }
+    
+    virtual void ProcessCodeCompleteResults(Sema &S, 
+                                            CodeCompletionContext Context,
+                                            CodeCompletionResult *Results,
+                                            unsigned NumResults);
+    
+    virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
+                                           OverloadCandidate *Candidates,
+                                           unsigned NumCandidates) { 
+      Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates);
+    }
+  };
+}
+
+/// \brief Helper function that computes which global names are hidden by the
+/// local code-completion results.
+void CalculateHiddenNames(const CodeCompletionContext &Context,
+                          CodeCompletionResult *Results,
+                          unsigned NumResults,
+                          ASTContext &Ctx,
+                          llvm::StringSet<> &HiddenNames) {
+  bool OnlyTagNames = false;
+  switch (Context.getKind()) {
+  case CodeCompletionContext::CCC_Other:
+  case CodeCompletionContext::CCC_TopLevel:
+  case CodeCompletionContext::CCC_ObjCInterface:
+  case CodeCompletionContext::CCC_ObjCImplementation:
+  case CodeCompletionContext::CCC_ObjCIvarList:
+  case CodeCompletionContext::CCC_ClassStructUnion:
+  case CodeCompletionContext::CCC_Statement:
+  case CodeCompletionContext::CCC_Expression:
+  case CodeCompletionContext::CCC_ObjCMessageReceiver:
+  case CodeCompletionContext::CCC_MemberAccess:
+  case CodeCompletionContext::CCC_Namespace:
+  case CodeCompletionContext::CCC_Type:
+  case CodeCompletionContext::CCC_Name:
+  case CodeCompletionContext::CCC_PotentiallyQualifiedName:
+    break;
+    
+  case CodeCompletionContext::CCC_EnumTag:
+  case CodeCompletionContext::CCC_UnionTag:
+  case CodeCompletionContext::CCC_ClassOrStructTag:
+    OnlyTagNames = true;
+    break;
+    
+  case CodeCompletionContext::CCC_ObjCProtocolName:
+  case CodeCompletionContext::CCC_MacroName:
+  case CodeCompletionContext::CCC_MacroNameUse:
+  case CodeCompletionContext::CCC_PreprocessorExpression:
+  case CodeCompletionContext::CCC_PreprocessorDirective:
+  case CodeCompletionContext::CCC_NaturalLanguage:
+  case CodeCompletionContext::CCC_SelectorName:
+  case CodeCompletionContext::CCC_TypeQualifiers:
+    // We're looking for nothing, or we're looking for names that cannot
+    // be hidden.
+    return;
+  }
+  
+  typedef CodeCompletionResult Result;
+  for (unsigned I = 0; I != NumResults; ++I) {
+    if (Results[I].Kind != Result::RK_Declaration)
+      continue;
+    
+    unsigned IDNS
+      = Results[I].Declaration->getUnderlyingDecl()->getIdentifierNamespace();
+
+    bool Hiding = false;
+    if (OnlyTagNames)
+      Hiding = (IDNS & Decl::IDNS_Tag);
+    else {
+      unsigned HiddenIDNS = (Decl::IDNS_Type | Decl::IDNS_Member | 
+                             Decl::IDNS_Namespace | Decl::IDNS_Ordinary |
+                             Decl::IDNS_NonMemberOperator);
+      if (Ctx.getLangOptions().CPlusPlus)
+        HiddenIDNS |= Decl::IDNS_Tag;
+      Hiding = (IDNS & HiddenIDNS);
+    }
+  
+    if (!Hiding)
+      continue;
+    
+    DeclarationName Name = Results[I].Declaration->getDeclName();
+    if (IdentifierInfo *Identifier = Name.getAsIdentifierInfo())
+      HiddenNames.insert(Identifier->getName());
+    else
+      HiddenNames.insert(Name.getAsString());
+  }
+}
+
+
+void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
+                                            CodeCompletionContext Context,
+                                            CodeCompletionResult *Results,
+                                            unsigned NumResults) { 
+  // Merge the results we were given with the results we cached.
+  bool AddedResult = false;
+  unsigned InContexts  
+    = (Context.getKind() == CodeCompletionContext::CCC_Other? NormalContexts
+                                            : (1 << (Context.getKind() - 1)));
+
+  // Contains the set of names that are hidden by "local" completion results.
+  llvm::StringSet<> HiddenNames;
+  llvm::SmallVector<CodeCompletionString *, 4> StringsToDestroy;
+  typedef CodeCompletionResult Result;
+  llvm::SmallVector<Result, 8> AllResults;
+  for (ASTUnit::cached_completion_iterator 
+            C = AST.cached_completion_begin(),
+         CEnd = AST.cached_completion_end();
+       C != CEnd; ++C) {
+    // If the context we are in matches any of the contexts we are 
+    // interested in, we'll add this result.
+    if ((C->ShowInContexts & InContexts) == 0)
+      continue;
+    
+    // If we haven't added any results previously, do so now.
+    if (!AddedResult) {
+      CalculateHiddenNames(Context, Results, NumResults, S.Context, 
+                           HiddenNames);
+      AllResults.insert(AllResults.end(), Results, Results + NumResults);
+      AddedResult = true;
+    }
+    
+    // Determine whether this global completion result is hidden by a local
+    // completion result. If so, skip it.
+    if (C->Kind != CXCursor_MacroDefinition &&
+        HiddenNames.count(C->Completion->getTypedText()))
+      continue;
+    
+    // Adjust priority based on similar type classes.
+    unsigned Priority = C->Priority;
+    CXCursorKind CursorKind = C->Kind;
+    CodeCompletionString *Completion = C->Completion;
+    if (!Context.getPreferredType().isNull()) {
+      if (C->Kind == CXCursor_MacroDefinition) {
+        Priority = getMacroUsagePriority(C->Completion->getTypedText(),
+                               Context.getPreferredType()->isAnyPointerType());        
+      } else if (C->Type) {
+        CanQualType Expected
+          = S.Context.getCanonicalType(
+                               Context.getPreferredType().getUnqualifiedType());
+        SimplifiedTypeClass ExpectedSTC = getSimplifiedTypeClass(Expected);
+        if (ExpectedSTC == C->TypeClass) {
+          // We know this type is similar; check for an exact match.
+          llvm::StringMap<unsigned> &CachedCompletionTypes
+            = AST.getCachedCompletionTypes();
+          llvm::StringMap<unsigned>::iterator Pos
+            = CachedCompletionTypes.find(QualType(Expected).getAsString());
+          if (Pos != CachedCompletionTypes.end() && Pos->second == C->Type)
+            Priority /= CCF_ExactTypeMatch;
+          else
+            Priority /= CCF_SimilarTypeMatch;
+        }
+      }
+    }
+    
+    // Adjust the completion string, if required.
+    if (C->Kind == CXCursor_MacroDefinition &&
+        Context.getKind() == CodeCompletionContext::CCC_MacroNameUse) {
+      // Create a new code-completion string that just contains the
+      // macro name, without its arguments.
+      Completion = new CodeCompletionString;
+      Completion->AddTypedTextChunk(C->Completion->getTypedText());
+      StringsToDestroy.push_back(Completion);
+      CursorKind = CXCursor_NotImplemented;
+      Priority = CCP_CodePattern;
+    }
+    
+    AllResults.push_back(Result(Completion, Priority, CursorKind, 
+                                C->Availability));
+  }
+  
+  // If we did not add any cached completion results, just forward the
+  // results we were given to the next consumer.
+  if (!AddedResult) {
+    Next.ProcessCodeCompleteResults(S, Context, Results, NumResults);
+    return;
+  }
+  
+  Next.ProcessCodeCompleteResults(S, Context, AllResults.data(),
+                                  AllResults.size());
+  
+  for (unsigned I = 0, N = StringsToDestroy.size(); I != N; ++I)
+    delete StringsToDestroy[I];
+}
+
+
+
+void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
+                           RemappedFile *RemappedFiles, 
+                           unsigned NumRemappedFiles,
+                           bool IncludeMacros, 
+                           bool IncludeCodePatterns,
+                           CodeCompleteConsumer &Consumer,
+                           Diagnostic &Diag, LangOptions &LangOpts,
+                           SourceManager &SourceMgr, FileManager &FileMgr,
+                   llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics,
+             llvm::SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) {
+  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();
+
+  FrontendOpts.ShowMacrosInCodeCompletion
+    = IncludeMacros && CachedCompletionResults.empty();
+  FrontendOpts.ShowCodePatternsInCodeCompletion = IncludeCodePatterns;
+  FrontendOpts.ShowGlobalSymbolsInCodeCompletion
+    = CachedCompletionResults.empty();
+  FrontendOpts.CodeCompletionAt.FileName = File;
+  FrontendOpts.CodeCompletionAt.Line = Line;
+  FrontendOpts.CodeCompletionAt.Column = Column;
+
+  // Turn on spell-checking when performing code completion. It leads
+  // to better results.
+  unsigned SpellChecking = CCInvocation.getLangOpts().SpellChecking;
+  CCInvocation.getLangOpts().SpellChecking = 1;
+
+  // Set the language options appropriately.
+  LangOpts = CCInvocation.getLangOpts();
+
+  CompilerInstance Clang;
+  Clang.setInvocation(&CCInvocation);
+  OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
+    
+  // Set up diagnostics, capturing any diagnostics produced.
+  Clang.setDiagnostics(&Diag);
+  CaptureDroppedDiagnostics Capture(true, 
+                                    Clang.getDiagnostics(),
+                                    StoredDiagnostics);
+  
+  // Create the target instance.
+  Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
+                                               Clang.getTargetOpts()));
+  if (!Clang.hasTarget()) {
+    Clang.takeInvocation();
+    CCInvocation.getLangOpts().SpellChecking = SpellChecking;
+    return;
+  }
+  
+  // Inform the target of the language options.
+  //
+  // FIXME: We shouldn't need to do this, the target should be immutable once
+  // created. This complexity should be lifted elsewhere.
+  Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
+  
+  assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
+         "Invocation must have exactly one source file!");
+  assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
+         "FIXME: AST inputs not yet supported here!");
+  assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+         "IR inputs not support here!");
+
+  
+  // Use the source and file managers that we were given.
+  Clang.setFileManager(&FileMgr);
+  Clang.setSourceManager(&SourceMgr);
+
+  // Remap files.
+  PreprocessorOpts.clearRemappedFiles();
+  PreprocessorOpts.RetainRemappedFileBuffers = true;
+  for (unsigned I = 0; I != NumRemappedFiles; ++I) {
+    PreprocessorOpts.addRemappedFile(RemappedFiles[I].first,
+                                     RemappedFiles[I].second);
+    OwnedBuffers.push_back(RemappedFiles[I].second);
+  }
+  
+  // Use the code completion consumer we were given, but adding any cached
+  // code-completion results.
+  AugmentedCodeCompleteConsumer 
+  AugmentedConsumer(*this, Consumer, FrontendOpts.ShowMacrosInCodeCompletion,
+                    FrontendOpts.ShowCodePatternsInCodeCompletion,
+                    FrontendOpts.ShowGlobalSymbolsInCodeCompletion);
+  Clang.setCodeCompletionConsumer(&AugmentedConsumer);
+
+  // 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(CCInvocation, false, 
+                                                   Line - 1);
+  }
+
+  // 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);
+    }
+    
+    OwnedBuffers.push_back(OverrideMainBuffer);
+  } else {
+    PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
+    PreprocessorOpts.PrecompiledPreambleBytes.second = false;
+  }
+
+  llvm::OwningPtr<SyntaxOnlyAction> Act;
+  Act.reset(new SyntaxOnlyAction);
+  if (Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
+                           Clang.getFrontendOpts().Inputs[0].first)) {
+    Act->Execute();
+    Act->EndSourceFile();
+  }
+
+  if (CompletionTimer)
+    CompletionTimer->stopTimer();
+  
+  // Steal back our resources. 
+  Clang.takeFileManager();
+  Clang.takeSourceManager();
+  Clang.takeInvocation();
+  Clang.takeCodeCompletionConsumer();
+  CCInvocation.getLangOpts().SpellChecking = SpellChecking;
+}
+
+bool ASTUnit::Save(llvm::StringRef File) {
+  if (getDiagnostics().hasErrorOccurred())
+    return true;
+  
+  // FIXME: Can we somehow regenerate the stat cache here, or do we need to 
+  // unconditionally create a stat cache when we parse the file?
+  std::string ErrorInfo;
+  llvm::raw_fd_ostream Out(File.str().c_str(), ErrorInfo,
+                           llvm::raw_fd_ostream::F_Binary);
+  if (!ErrorInfo.empty() || Out.has_error())
+    return true;
+  
+  std::vector<unsigned char> Buffer;
+  llvm::BitstreamWriter Stream(Buffer);
+  ASTWriter Writer(Stream);
+  Writer.WriteAST(getSema(), 0, 0);
+  
+  // Write the generated bitstream to "Out".
+  if (!Buffer.empty())
+    Out.write((char *)&Buffer.front(), Buffer.size());  
+  Out.close();
+  return Out.has_error();
 }
-- 
cgit v1.1