]> granicus.if.org Git - clang/commitdiff
When using a precompiled preamble, keep track of the top-level
authorDouglas Gregor <dgregor@apple.com>
Tue, 3 Aug 2010 19:06:41 +0000 (19:06 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 3 Aug 2010 19:06:41 +0000 (19:06 +0000)
declarations that we saw when creating the precompiled preamble, and
provide those declarations in addition to the declarations parsed in
the main source file when traversing top-level declarations. This
makes the use of precompiled preambles a pure optimization, rather
than changing the semantics of the parsed translation unit.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110131 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Frontend/ASTUnit.h
include/clang/Frontend/PCHWriter.h
lib/Frontend/ASTUnit.cpp
test/Index/preamble.c
tools/libclang/CIndex.cpp

index ad622c55e65cc3b7b1cff3eeff53c3adc09b119b..58f2b38707c9d40dbea9c250d618125198b49fcc 100644 (file)
 #ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
 #define LLVM_CLANG_FRONTEND_ASTUNIT_H
 
+#include "clang/Index/ASTLocation.h"
+#include "clang/Frontend/PCHBitCodes.h"
 #include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/OwningPtr.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Index/ASTLocation.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/System/Path.h"
@@ -168,7 +169,11 @@ private:
 
   /// \brief The group of timers associated with this translation unit.
   llvm::OwningPtr<llvm::TimerGroup> TimerGroup;  
-  
+
+  /// \brief A list of the PCH ID numbers for each of the top-level
+  /// declarations parsed within the precompiled preamble.
+  std::vector<pch::DeclID> TopLevelDeclsInPreamble;
+
   /// \brief The timers we've created from the various parses, reparses, etc.
   /// involved in this translation unit.
   std::vector<llvm::Timer *> Timers;
@@ -185,7 +190,8 @@ private:
   ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer);
   
   llvm::MemoryBuffer *BuildPrecompiledPreamble();
-  
+  void RealizeTopLevelDeclsFromPreamble();
+
 public:
   class ConcurrencyCheck {
     volatile ASTUnit &Self;
@@ -236,16 +242,48 @@ public:
                         
   bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
 
+  /// \brief Retrieve the maximum PCH level of declarations that a
+  /// traversal of the translation unit should consider.
+  unsigned getMaxPCHLevel() const;
+
   void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; }
   ASTLocation getLastASTLocation() const { return LastLoc; }
 
-  std::vector<Decl*> &getTopLevelDecls() {
+  typedef std::vector<Decl *>::iterator top_level_iterator;
+
+  top_level_iterator top_level_begin() {
     assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
-    return TopLevelDecls;
+    if (!TopLevelDeclsInPreamble.empty())
+      RealizeTopLevelDeclsFromPreamble();
+    return TopLevelDecls.begin();
   }
-  const std::vector<Decl*> &getTopLevelDecls() const {
+
+  top_level_iterator top_level_end() {
     assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
-    return TopLevelDecls;
+    if (!TopLevelDeclsInPreamble.empty())
+      RealizeTopLevelDeclsFromPreamble();
+    return TopLevelDecls.end();
+  }
+
+  std::size_t top_level_size() const {
+    assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
+    return TopLevelDeclsInPreamble.size() + TopLevelDecls.size();
+  }
+
+  bool top_level_empty() const {
+    assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
+    return TopLevelDeclsInPreamble.empty() && TopLevelDecls.empty();
+  }
+
+  /// \brief Add a new top-level declaration.
+  void addTopLevelDecl(Decl *D) {
+    TopLevelDecls.push_back(D);
+  }
+
+  /// \brief Add a new top-level declaration, identified by its ID in
+  /// the precompiled preamble.
+  void addTopLevelDeclFromPreamble(pch::DeclID D) {
+    TopLevelDeclsInPreamble.push_back(D);
   }
 
   /// \brief Retrieve the mapping from File IDs to the preprocessed entities
index 3403c6e2d177ba62b8f5aa0eb005f14b8cad8250..3ba5691ebc1c46c08f2a23ef202b72bdd49505dc 100644 (file)
@@ -448,6 +448,10 @@ class PCHGenerator : public SemaConsumer {
   llvm::BitstreamWriter Stream;
   PCHWriter Writer;
 
+protected:
+  PCHWriter &getWriter() { return Writer; }
+  const PCHWriter &getWriter() const { return Writer; }
+
 public:
   PCHGenerator(const Preprocessor &PP, bool Chaining,
                const char *isysroot, llvm::raw_ostream *Out);
index bd60296ca80e6f3f63f17f036325a65fc898e7fb..c37610afc391646e279b782c092e64850c5423df 100644 (file)
@@ -309,7 +309,7 @@ public:
       // fundamental problem in the parser right now.
       if (isa<ObjCMethodDecl>(D))
         continue;
-      Unit.getTopLevelDecls().push_back(D);
+      Unit.addTopLevelDecl(D);
     }
   }
 };
@@ -331,6 +331,7 @@ public:
 
 class PrecompilePreambleConsumer : public PCHGenerator {
   ASTUnit &Unit;
+  std::vector<Decl *> TopLevelDecls;
 
 public:
   PrecompilePreambleConsumer(ASTUnit &Unit,
@@ -338,7 +339,7 @@ public:
                              const char *isysroot, llvm::raw_ostream *Out)
     : PCHGenerator(PP, Chaining, isysroot, Out), Unit(Unit) { }
 
-  void HandleTopLevelDecl(DeclGroupRef D) {
+  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
@@ -347,7 +348,20 @@ public:
       // fundamental problem in the parser right now.
       if (isa<ObjCMethodDecl>(D))
         continue;
-      Unit.getTopLevelDecls().push_back(D);
+      TopLevelDecls.push_back(D);
+    }
+  }
+
+  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]));
     }
   }
 };
@@ -855,7 +869,9 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
   
   // Clear out old caches and data.
   StoredDiagnostics.clear();
-  
+  TopLevelDecls.clear();
+  TopLevelDeclsInPreamble.clear();
+
   // Capture any diagnostics that would otherwise be dropped.
   CaptureDroppedDiagnostics Capture(CaptureDiagnostics, 
                                     getDiagnostics(),
@@ -867,7 +883,6 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
   // Create the source manager.
   Clang.setSourceManager(new SourceManager(getDiagnostics()));
   
-  // FIXME: Eventually, we'll have to track top-level declarations here, too.
   llvm::OwningPtr<PrecompilePreambleAction> Act;
   Act.reset(new PrecompilePreambleAction(*this));
   if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
@@ -889,7 +904,7 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
   Clang.takeDiagnosticClient();
   Clang.takeInvocation();
   
-  if (Diagnostics->getNumErrors() > 0) {
+  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?
@@ -899,7 +914,7 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
       delete NewPreamble.first;
     if (PreambleTimer)
       PreambleTimer->stopTimer();
-
+    TopLevelDeclsInPreamble.clear();
     return 0;
   }
   
@@ -935,6 +950,31 @@ llvm::MemoryBuffer *ASTUnit::BuildPrecompiledPreamble() {
                                     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,
index e1a64c2fbe186f0510f4e01406529f0ac59fdb64..7e75bf9b89c890f2d15e07b3c2143092189c2a0f 100644 (file)
@@ -5,6 +5,16 @@ int wibble(int);
 // 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
+// CHECK: preamble.h:1:12: FunctionDecl=bar:1:12 (Definition) Extent=[1:12 - 6:2]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[1:23 - 6:2]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[2:3 - 2:16]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[3:3 - 3:15]
+// CHECK: preamble.h:4:3: UnexposedExpr= Extent=[4:3 - 4:13]
+// CHECK: preamble.h:4:3: DeclRefExpr=ptr:2:8 Extent=[4:3 - 4:6]
+// CHECK: preamble.h:4:9: UnexposedExpr=ptr1:3:10 Extent=[4:9 - 4:13]
+// CHECK: preamble.h:4:9: DeclRefExpr=ptr1:3:10 Extent=[4:9 - 4:13]
+// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[5:3 - 5:11]
+// CHECK: preamble.h:5:10: UnexposedExpr= Extent=[5:10 - 5:11]
 // 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 *'
index 1b3c6a2c73bcc3581efdd7e5a78dfe4cea989e64..b90740f8b0a75c2aad25e7b4dd05471cbe89c056 100644 (file)
@@ -478,10 +478,10 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
     ASTUnit *CXXUnit = getCursorASTUnit(Cursor);
     if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() &&
         RegionOfInterest.isInvalid()) {
-      const std::vector<Decl*> &TLDs = CXXUnit->getTopLevelDecls();
-      for (std::vector<Decl*>::const_iterator it = TLDs.begin(),
-           ie = TLDs.end(); it != ie; ++it) {
-        if (Visit(MakeCXCursor(*it, CXXUnit), true))
+      for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(),
+                                    TLEnd = CXXUnit->top_level_end();
+           TL != TLEnd; ++TL) {
+        if (Visit(MakeCXCursor(*TL, CXXUnit), true))
           return true;
       }
     } else if (VisitDeclContext(
@@ -1636,18 +1636,8 @@ unsigned clang_visitChildren(CXCursor parent,
                              CXClientData client_data) {
   ASTUnit *CXXUnit = getCursorASTUnit(parent);
 
-  unsigned PCHLevel = Decl::MaxPCHLevel;
-
-  // Set the PCHLevel to filter out unwanted decls if requested.
-  if (CXXUnit->getOnlyLocalDecls()) {
-    PCHLevel = 0;
-
-    // If the main input was an AST, bump the level.
-    if (CXXUnit->isMainFileAST())
-      ++PCHLevel;
-  }
-
-  CursorVisitor CursorVis(CXXUnit, visitor, client_data, PCHLevel);
+  CursorVisitor CursorVis(CXXUnit, visitor, client_data, 
+                          CXXUnit->getMaxPCHLevel());
   return CursorVis.VisitChildren(parent);
 }