Teach ASTUnit to hold on to the Sema object and ASTConsumer that are
used when parsing (or re-parsing) a file. Also, when loading a
precompiled header into ASTUnit, create a Sema object that holds onto
semantic-analysis information.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111003 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 6651743..d4a351c 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -16,6 +16,7 @@
 
 #include "clang/Index/ASTLocation.h"
 #include "clang/Frontend/PCHBitCodes.h"
+#include "clang/Sema/Sema.h"
 #include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/FileManager.h"
@@ -66,10 +67,18 @@
   llvm::OwningPtr<Preprocessor>     PP;
   llvm::OwningPtr<ASTContext>       Ctx;
   
+  /// \brief The AST consumer that received information about the translation
+  /// unit as it was parsed or loaded.
+  llvm::OwningPtr<ASTConsumer> Consumer;
+  
+  /// \brief The semantic analysis object used to type-check the translation
+  /// unit.
+  llvm::OwningPtr<Sema> TheSema;
+  
   /// Optional owned invocation, just used to make the invocation used in
   /// LoadFromCommandLine available.
   llvm::OwningPtr<CompilerInvocation> Invocation;
-
+  
   // OnlyLocalDecls - when true, walking this AST should only visit declarations
   // that come from the AST itself, not from included precompiled headers.
   // FIXME: This is temporary; eventually, CIndex will always do this.
@@ -245,6 +254,12 @@
   const ASTContext &getASTContext() const { return *Ctx.get(); }
         ASTContext &getASTContext()       { return *Ctx.get(); }
 
+  bool hasSema() const { return TheSema; }
+  Sema &getSema() const { 
+    assert(TheSema && "ASTUnit does not have a Sema object!");
+    return *TheSema; 
+  }
+  
   const FileManager &getFileManager() const { return *FileMgr; }
         FileManager &getFileManager()       { return *FileMgr; }
 
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index e916e20..cbaa6a3 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -44,6 +44,12 @@
     if (!Unit)
       continue;
 
+    // Reset the argument -> string function so that it has the AST
+    // context we want, since the Sema object created by
+    // LoadFromPCHFile will override it.
+    CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
+                                         &CI.getASTContext());
+
     ASTImporter Importer(CI.getDiagnostics(),
                          CI.getASTContext(), 
                          CI.getFileManager(),
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index bbe2ec5..b56a0d8 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -204,7 +204,7 @@
   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);
@@ -237,7 +237,6 @@
   unsigned Counter;
 
   llvm::OwningPtr<PCHReader> Reader;
-  llvm::OwningPtr<ExternalASTSource> Source;
 
   Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
                              AST->getDiagnostics()));
@@ -294,9 +293,18 @@
   // Attach the PCH 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());
+  PCHReader *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 PCH reader about it.
+  AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer));
+  AST->TheSema->Initialize();
+  ReaderPtr->InitializeSema(*AST->TheSema);
+
   return AST.take();
 }
 
@@ -458,6 +466,7 @@
   // FIXME: Should we retain the previous file manager?
   FileMgr.reset(new FileManager);
   SourceMgr.reset(new SourceManager(getDiagnostics()));
+  TheSema.reset();
   Ctx.reset();
   PP.reset();
   
@@ -513,6 +522,8 @@
   
   // Steal the created target, context, and preprocessor, and take back the
   // source and file managers.
+  TheSema.reset(Clang.takeSema());
+  Consumer.reset(Clang.takeASTConsumer());
   Ctx.reset(Clang.takeASTContext());
   PP.reset(Clang.takePreprocessor());
   Clang.takeSourceManager();
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index e55605b..137c2d7 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -3135,9 +3135,11 @@
 
   // Makes sure any declarations that were deserialized "too early"
   // still get added to the identifier's declaration chains.
-  for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
-    SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(PreloadedDecls[I]));
-    SemaObj->IdResolver.AddDecl(PreloadedDecls[I]);
+  if (SemaObj->TUScope) {
+    for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
+      SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(PreloadedDecls[I]));
+      SemaObj->IdResolver.AddDecl(PreloadedDecls[I]);
+    }
   }
   PreloadedDecls.clear();
 
@@ -3332,11 +3334,13 @@
   for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
     NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
     if (SemaObj) {
-      // Introduce this declaration into the translation-unit scope
-      // and add it to the declaration chain for this identifier, so
-      // that (unqualified) name lookup will find it.
-      SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(D));
-      SemaObj->IdResolver.AddDeclToIdentifierChain(II, D);
+      if (SemaObj->TUScope) {
+        // Introduce this declaration into the translation-unit scope
+        // and add it to the declaration chain for this identifier, so
+        // that (unqualified) name lookup will find it.
+        SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(D));
+        SemaObj->IdResolver.AddDeclToIdentifierChain(II, D);
+      }
     } else {
       // Queue this declaration so that it will be added to the
       // translation unit scope and identifier's declaration chain
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 0d05b57..778bf8c 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -172,7 +172,7 @@
 
   // Detach from the external Sema source.
   if (ExternalSemaSource *ExternalSema
-      = dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource()))
+        = dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource()))
     ExternalSema->ForgetSema();
 }