#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"
/// \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;
ComputePreamble(CompilerInvocation &Invocation, bool &CreatedBuffer);
llvm::MemoryBuffer *BuildPrecompiledPreamble();
-
+ void RealizeTopLevelDeclsFromPreamble();
+
public:
class ConcurrencyCheck {
volatile ASTUnit &Self;
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
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);
// fundamental problem in the parser right now.
if (isa<ObjCMethodDecl>(D))
continue;
- Unit.getTopLevelDecls().push_back(D);
+ Unit.addTopLevelDecl(D);
}
}
};
class PrecompilePreambleConsumer : public PCHGenerator {
ASTUnit &Unit;
+ std::vector<Decl *> TopLevelDecls;
public:
PrecompilePreambleConsumer(ASTUnit &Unit,
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
// 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]));
}
}
};
// Clear out old caches and data.
StoredDiagnostics.clear();
-
+ TopLevelDecls.clear();
+ TopLevelDeclsInPreamble.clear();
+
// Capture any diagnostics that would otherwise be dropped.
CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
getDiagnostics(),
// 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,
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?
delete NewPreamble.first;
if (PreambleTimer)
PreambleTimer->stopTimer();
-
+ TopLevelDeclsInPreamble.clear();
return 0;
}
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,
// 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 *'
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(
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);
}