forked from OSchip/llvm-project
Keep track of whether declararions were loaded from a precompiled
header or not via a new "PCHLevel" field in Decl. We currently use this information to help CIndex filter out declarations that came from a precompiled header (rather than from an AST file). Further down the road, it can be used to help implement multi-level precompiled headers. llvm-svn: 84267
This commit is contained in:
parent
7d3c275526
commit
16bef857d9
|
@ -117,6 +117,17 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile(
|
|||
);
|
||||
void clang_disposeTranslationUnit(CXTranslationUnit);
|
||||
|
||||
/**
|
||||
* \brief Indicate to Clang that it should only enumerate "local" declarations
|
||||
* when loading any new translation units.
|
||||
*
|
||||
* A "local" declaration is one that belongs in the translation unit itself and
|
||||
* not in a precompiled header that was used by the translation unit.
|
||||
*
|
||||
* FIXME: Remove this hook.
|
||||
*/
|
||||
void clang_wantOnlyLocalDeclarations(CXIndex);
|
||||
|
||||
/*
|
||||
Usage: clang_loadTranslationUnit(). Will load the toplevel declarations
|
||||
within a translation unit, issuing a 'callback' for each one.
|
||||
|
|
|
@ -166,6 +166,15 @@ private:
|
|||
bool Used : 1;
|
||||
|
||||
protected:
|
||||
/// Access - Used by C++ decls for the access specifier.
|
||||
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
|
||||
unsigned Access : 2;
|
||||
friend class CXXClassMemberWrapper;
|
||||
|
||||
// PCHLevel - the "level" of precompiled header/AST file from which this
|
||||
// declaration was built.
|
||||
unsigned PCHLevel : 2;
|
||||
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 16;
|
||||
|
||||
|
@ -177,16 +186,13 @@ private:
|
|||
#endif
|
||||
|
||||
protected:
|
||||
/// Access - Used by C++ decls for the access specifier.
|
||||
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
|
||||
unsigned Access : 2;
|
||||
friend class CXXClassMemberWrapper;
|
||||
|
||||
Decl(Kind DK, DeclContext *DC, SourceLocation L)
|
||||
: NextDeclInContext(0), DeclCtx(DC),
|
||||
Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)), Access(AS_none) {
|
||||
Access(AS_none), PCHLevel(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)) {
|
||||
if (Decl::CollectingStats()) addDeclKind(DK);
|
||||
}
|
||||
|
||||
|
@ -274,6 +280,26 @@ public:
|
|||
bool isUsed() const { return Used; }
|
||||
void setUsed(bool U = true) { Used = U; }
|
||||
|
||||
/// \brief Retrieve the level of precompiled header from which this
|
||||
/// declaration was generated.
|
||||
///
|
||||
/// The PCH level of a declaration describes where the declaration originated
|
||||
/// from. A PCH level of 0 indicates that the declaration was not from a
|
||||
/// precompiled header. A PCH level of 1 indicates that the declaration was
|
||||
/// from a top-level precompiled header; 2 indicates that the declaration
|
||||
/// comes from a precompiled header on which the top-level precompiled header
|
||||
/// depends, and so on.
|
||||
unsigned getPCHLevel() const { return PCHLevel; }
|
||||
|
||||
/// \brief The maximum PCH level that any declaration may have.
|
||||
static const unsigned MaxPCHLevel = 3;
|
||||
|
||||
/// \brief Set the PCH level of this declaration.
|
||||
void setPCHLevel(unsigned Level) {
|
||||
assert(Level < MaxPCHLevel && "PCH level exceeds the maximum");
|
||||
PCHLevel = Level;
|
||||
}
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IdentifierNamespace;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,11 @@ class ASTUnit {
|
|||
llvm::OwningPtr<ASTContext> Ctx;
|
||||
bool tempFile;
|
||||
|
||||
// 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.
|
||||
bool OnlyLocalDecls;
|
||||
|
||||
ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT
|
||||
ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT
|
||||
ASTUnit(Diagnostic &_Diag);
|
||||
|
@ -65,6 +70,8 @@ public:
|
|||
|
||||
void unlinkTemporaryFile() { tempFile = true; }
|
||||
|
||||
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
|
||||
|
||||
/// \brief Create a ASTUnit from a PCH file.
|
||||
///
|
||||
/// \param Filename - The PCH file to load.
|
||||
|
@ -80,7 +87,8 @@ public:
|
|||
static ASTUnit *LoadFromPCHFile(const std::string &Filename,
|
||||
Diagnostic &Diags,
|
||||
FileManager &FileMgr,
|
||||
std::string *ErrMsg = 0);
|
||||
std::string *ErrMsg = 0,
|
||||
bool OnlyLocalDecls = false);
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
|
|
@ -94,9 +94,10 @@ FileManager &ASTUnit::getFileManager() {
|
|||
ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
|
||||
Diagnostic &Diags,
|
||||
FileManager &FileMgr,
|
||||
std::string *ErrMsg) {
|
||||
std::string *ErrMsg,
|
||||
bool OnlyLocalDecls) {
|
||||
llvm::OwningPtr<ASTUnit> AST(new ASTUnit(Diags));
|
||||
|
||||
AST->OnlyLocalDecls = OnlyLocalDecls;
|
||||
AST->HeaderInfo.reset(new HeaderSearch(FileMgr));
|
||||
|
||||
// Gather Info for preprocessor construction later on.
|
||||
|
|
|
@ -86,6 +86,7 @@ void PCHDeclReader::VisitDecl(Decl *D) {
|
|||
D->setImplicit(Record[Idx++]);
|
||||
D->setUsed(Record[Idx++]);
|
||||
D->setAccess((AccessSpecifier)Record[Idx++]);
|
||||
D->setPCHLevel(Record[Idx++] + 1);
|
||||
}
|
||||
|
||||
void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
|
||||
|
|
|
@ -88,6 +88,7 @@ void PCHDeclWriter::VisitDecl(Decl *D) {
|
|||
Record.push_back(D->isImplicit());
|
||||
Record.push_back(D->isUsed());
|
||||
Record.push_back(D->getAccess());
|
||||
Record.push_back(D->getPCHLevel());
|
||||
}
|
||||
|
||||
void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
|
||||
|
@ -448,6 +449,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
|
|||
!D->isImplicit() &&
|
||||
!D->isUsed() &&
|
||||
D->getAccess() == AS_none &&
|
||||
D->getPCHLevel() == 0 &&
|
||||
D->getStorageClass() == 0 &&
|
||||
!D->hasCXXDirectInitializer() && // Can params have this ever?
|
||||
D->getObjCDeclQualifier() == 0)
|
||||
|
@ -523,6 +525,7 @@ void PCHWriter::WriteDeclsBlockAbbrevs() {
|
|||
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
|
||||
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
|
||||
|
||||
// NamedDecl
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
// RUN: clang-cc -emit-pch -x c -o %t.pch %S/c-index-pch.h &&
|
||||
// RUN: clang-cc -include-pch %t.pch -x c -emit-pch -o %t.ast %s &&
|
||||
// RUN: c-index-test %t.ast all | FileCheck -check-prefix=ALL %s
|
||||
// CHECK-ALL: FunctionDecl=foo
|
||||
// CHECK-ALL: VarDecl=bar
|
||||
// CHECK-ALL: FunctionDecl=wibble
|
||||
// RUN: c-index-test %t.ast all | FileCheck -check-prefix=ALL %s &&
|
||||
// RUN: c-index-test %t.ast local | FileCheck -check-prefix=LOCAL %s
|
||||
// ALL: FunctionDecl=foo
|
||||
// ALL: VarDecl=bar
|
||||
// ALL: FunctionDecl=wibble
|
||||
// ALL: FunctionDecl=wonka
|
||||
// LOCAL-NOT: FunctionDecl=foo
|
||||
// LOCAL-NOT: VarDecl=bar
|
||||
// LOCAL: FunctionDecl=wibble
|
||||
// LOCAL: FunctionDecl=wonka
|
||||
void wibble(int i);
|
||||
void wonka(float);
|
||||
|
|
|
@ -88,14 +88,24 @@ class TUVisitor : public DeclVisitor<TUVisitor> {
|
|||
CXTranslationUnitIterator Callback;
|
||||
CXClientData CData;
|
||||
|
||||
// MaxPCHLevel - the maximum PCH level of declarations that we will pass on
|
||||
// to the visitor. Declarations with a PCH level greater than this value will
|
||||
// be suppressed.
|
||||
unsigned MaxPCHLevel;
|
||||
|
||||
void Call(enum CXCursorKind CK, NamedDecl *ND) {
|
||||
// Filter any declarations that have a PCH level greater than what we allow.
|
||||
if (ND->getPCHLevel() > MaxPCHLevel)
|
||||
return;
|
||||
|
||||
CXCursor C = { CK, ND, 0 };
|
||||
Callback(TUnit, C, CData);
|
||||
}
|
||||
public:
|
||||
TUVisitor(CXTranslationUnit CTU,
|
||||
CXTranslationUnitIterator cback, CXClientData D) :
|
||||
TUnit(CTU), Callback(cback), CData(D) {}
|
||||
CXTranslationUnitIterator cback, CXClientData D,
|
||||
unsigned MaxPCHLevel) :
|
||||
TUnit(CTU), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {}
|
||||
|
||||
void VisitTranslationUnitDecl(TranslationUnitDecl *D) {
|
||||
VisitDeclContext(dyn_cast<DeclContext>(D));
|
||||
|
@ -154,16 +164,27 @@ class CDeclVisitor : public DeclVisitor<CDeclVisitor> {
|
|||
CXDeclIterator Callback;
|
||||
CXClientData CData;
|
||||
|
||||
// MaxPCHLevel - the maximum PCH level of declarations that we will pass on
|
||||
// to the visitor. Declarations with a PCH level greater than this value will
|
||||
// be suppressed.
|
||||
unsigned MaxPCHLevel;
|
||||
|
||||
void Call(enum CXCursorKind CK, NamedDecl *ND) {
|
||||
// Disable the callback when the context is equal to the visiting decl.
|
||||
if (CDecl == ND && !clang_isReference(CK))
|
||||
return;
|
||||
|
||||
// Filter any declarations that have a PCH level greater than what we allow.
|
||||
if (ND->getPCHLevel() > MaxPCHLevel)
|
||||
return;
|
||||
|
||||
CXCursor C = { CK, ND, 0 };
|
||||
Callback(CDecl, C, CData);
|
||||
}
|
||||
public:
|
||||
CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) :
|
||||
CDecl(C), Callback(cback), CData(D) {}
|
||||
CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D,
|
||||
unsigned MaxPCHLevel) :
|
||||
CDecl(C), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {}
|
||||
|
||||
void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
|
||||
// Issue callbacks for the containing class.
|
||||
|
@ -242,6 +263,20 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class CIndexer : public Indexer {
|
||||
public:
|
||||
explicit CIndexer(Program &prog) : Indexer(prog), OnlyLocalDecls(false) { }
|
||||
|
||||
/// \brief Whether we only want to see "local" declarations (that did not
|
||||
/// come from a previous precompiled header). If false, we want to see all
|
||||
/// declarations.
|
||||
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
|
||||
void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; }
|
||||
|
||||
private:
|
||||
bool OnlyLocalDecls;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
@ -267,13 +302,13 @@ CXIndex clang_createIndex()
|
|||
|
||||
clangPath = ClangPath.c_str();
|
||||
|
||||
return new Indexer(*new Program());
|
||||
return new CIndexer(*new Program());
|
||||
}
|
||||
|
||||
void clang_disposeIndex(CXIndex CIdx)
|
||||
{
|
||||
assert(CIdx && "Passed null CXIndex");
|
||||
delete static_cast<Indexer *>(CIdx);
|
||||
delete static_cast<CIndexer *>(CIdx);
|
||||
}
|
||||
|
||||
// FIXME: need to pass back error info.
|
||||
|
@ -281,12 +316,13 @@ CXTranslationUnit clang_createTranslationUnit(
|
|||
CXIndex CIdx, const char *ast_filename)
|
||||
{
|
||||
assert(CIdx && "Passed null CXIndex");
|
||||
Indexer *CXXIdx = static_cast<Indexer *>(CIdx);
|
||||
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
|
||||
std::string astName(ast_filename);
|
||||
std::string ErrMsg;
|
||||
|
||||
return ASTUnit::LoadFromPCHFile(astName, CXXIdx->getDiagnostics(),
|
||||
CXXIdx->getFileManager(), &ErrMsg);
|
||||
CXXIdx->getFileManager(), &ErrMsg,
|
||||
CXXIdx->getOnlyLocalDecls());
|
||||
}
|
||||
|
||||
CXTranslationUnit clang_createTranslationUnitFromSourceFile(
|
||||
|
@ -338,6 +374,10 @@ void clang_disposeTranslationUnit(
|
|||
delete static_cast<ASTUnit *>(CTUnit);
|
||||
}
|
||||
|
||||
void clang_wantOnlyLocalDeclarations(CXIndex CIdx) {
|
||||
static_cast<CIndexer *>(CIdx)->setOnlyLocalDecls(true);
|
||||
}
|
||||
|
||||
const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit)
|
||||
{
|
||||
assert(CTUnit && "Passed null CXTranslationUnit");
|
||||
|
@ -353,7 +393,8 @@ void clang_loadTranslationUnit(CXTranslationUnit CTUnit,
|
|||
ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
|
||||
ASTContext &Ctx = CXXUnit->getASTContext();
|
||||
|
||||
TUVisitor DVisit(CTUnit, callback, CData);
|
||||
TUVisitor DVisit(CTUnit, callback, CData,
|
||||
CXXUnit->getOnlyLocalDecls()? 1 : Decl::MaxPCHLevel);
|
||||
DVisit.Visit(Ctx.getTranslationUnitDecl());
|
||||
}
|
||||
|
||||
|
@ -363,7 +404,8 @@ void clang_loadDeclaration(CXDecl Dcl,
|
|||
{
|
||||
assert(Dcl && "Passed null CXDecl");
|
||||
|
||||
CDeclVisitor DVisit(Dcl, callback, CData);
|
||||
CDeclVisitor DVisit(Dcl, callback, CData,
|
||||
static_cast<Decl *>(Dcl)->getPCHLevel());
|
||||
DVisit.Visit(static_cast<Decl *>(Dcl));
|
||||
}
|
||||
|
||||
|
|
|
@ -28,3 +28,4 @@ _clang_getCursorSpelling
|
|||
_clang_getCursorKindSpelling
|
||||
_clang_getDefinitionSpellingAndExtent
|
||||
_clang_getTranslationUnitSpelling
|
||||
_clang_wantOnlyLocalDeclarations
|
||||
|
|
|
@ -86,10 +86,16 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
{
|
||||
CXIndex Idx = clang_createIndex();
|
||||
if (!strcmp(argv[2], "local"))
|
||||
clang_wantOnlyLocalDeclarations(Idx);
|
||||
CXTranslationUnit TU = clang_createTranslationUnit(Idx, argv[1]);
|
||||
if (!TU) {
|
||||
fprintf(stderr, "Unable to load translation unit!\n");
|
||||
return 1;
|
||||
}
|
||||
enum CXCursorKind K = CXCursor_NotImplemented;
|
||||
|
||||
if (!strcmp(argv[2], "all")) {
|
||||
if (!strcmp(argv[2], "all") || !strcmp(argv[2], "local")) {
|
||||
clang_loadTranslationUnit(TU, TranslationUnitVisitor, 0);
|
||||
clang_disposeTranslationUnit(TU);
|
||||
return 1;
|
||||
|
|
Loading…
Reference in New Issue