From 7d1d49d2971b20a97b3c2a301470b9eaaa130137 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 16 Oct 2009 20:01:17 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84267 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang-c/Index.h | 11 ++++++ include/clang/AST/DeclBase.h | 36 +++++++++++++++--- include/clang/Frontend/ASTUnit.h | 10 ++++- lib/Frontend/ASTUnit.cpp | 5 ++- lib/Frontend/PCHReaderDecl.cpp | 1 + lib/Frontend/PCHWriterDecl.cpp | 3 ++ test/Index/c-index-pch.c | 15 ++++++-- tools/CIndex/CIndex.cpp | 62 ++++++++++++++++++++++++++----- tools/CIndex/CIndex.exports | 1 + tools/c-index-test/c-index-test.c | 8 +++- 10 files changed, 129 insertions(+), 23 deletions(-) diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 3e7ceb3d79..b80cd47e01 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -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. diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 9e88871565..10db7030db 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -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; } diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index c1a0ebb559..0ce473f2af 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -40,6 +40,11 @@ class ASTUnit { llvm::OwningPtr 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 diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 3b2aa75008..15002385a8 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -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 AST(new ASTUnit(Diags)); - + AST->OnlyLocalDecls = OnlyLocalDecls; AST->HeaderInfo.reset(new HeaderSearch(FileMgr)); // Gather Info for preprocessor construction later on. diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index b6732561df..ed6728233a 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -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) { diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index ef7c5ec4b1..e2c1ae8715 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -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 diff --git a/test/Index/c-index-pch.c b/test/Index/c-index-pch.c index 2298c8f207..aae4eb3669 100644 --- a/test/Index/c-index-pch.c +++ b/test/Index/c-index-pch.c @@ -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); diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 23bbb0c0eb..133a269afd 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -88,14 +88,24 @@ class TUVisitor : public DeclVisitor { 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(D)); @@ -154,16 +164,27 @@ class CDeclVisitor : public DeclVisitor { 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(CIdx); + delete static_cast(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(CIdx); + CIndexer *CXXIdx = static_cast(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(CTUnit); } +void clang_wantOnlyLocalDeclarations(CXIndex CIdx) { + static_cast(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(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(Dcl)->getPCHLevel()); DVisit.Visit(static_cast(Dcl)); } diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index ea647b46a6..cbffbed1a2 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -28,3 +28,4 @@ _clang_getCursorSpelling _clang_getCursorKindSpelling _clang_getDefinitionSpellingAndExtent _clang_getTranslationUnitSpelling +_clang_wantOnlyLocalDeclarations diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 716c15ddec..bfc8e620ac 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -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; -- 2.40.0