From: Douglas Gregor Date: Fri, 19 Mar 2010 21:51:54 +0000 (+0000) Subject: Implement serialization and lazy deserialization of the preprocessing X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6a5a23f8e7fb65e028c8092bc1d1a1d9dfe2e9bc;p=clang Implement serialization and lazy deserialization of the preprocessing record (which includes all macro instantiations and definitions). As with all lay deserialization, this introduces a new external source (here, an external preprocessing record source) that loads all of the preprocessed entities prior to iterating over the entities. The preprocessing record is an optional part of the precompiled header that is disabled by default (enabled with -detailed-preprocessing-record). When the preprocessor given to the PCH writer has a preprocessing record, that record is written into the PCH file. When the PCH reader is given a PCH file that contains a preprocessing record, it will be lazily loaded (which, effectively, implicitly adds -detailed-preprocessing-record). This is the first case where we have sections of the precompiled header that are added/removed based on a compilation flag, which is unfortunate. However, this data consumes ~550k in the PCH file for Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering this detailed preprocessing information, so it's too expensive to turn on by default. In the future, we should investigate a better encoding of this information. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99002 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index e2c27e6ddf..de7888e797 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -224,8 +224,11 @@ namespace clang { VERSION_CONTROL_BRANCH_REVISION = 21, /// \brief Record code for the array of unused static functions. - UNUSED_STATIC_FUNCS = 22 + UNUSED_STATIC_FUNCS = 22, + /// \brief Record code for the table of offsets to macro definition + /// entries in the preprocessing record. + MACRO_DEFINITION_OFFSETS = 23 }; /// \brief Record types used within a source manager block. @@ -264,7 +267,14 @@ namespace clang { /// \brief Describes one token. /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags] - PP_TOKEN = 3 + PP_TOKEN = 3, + + /// \brief Describes a macro instantiation within the preprocessing + /// record. + PP_MACRO_INSTANTIATION = 4, + + /// \brief Describes a macro definition within the preprocessing record. + PP_MACRO_DEFINITION = 5 }; /// \defgroup PCHAST Precompiled header AST constants diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index e4fd1a2b15..9ccd382dba 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -21,6 +21,7 @@ #include "clang/AST/Type.h" #include "clang/AST/TemplateBase.h" #include "clang/Lex/ExternalPreprocessorSource.h" +#include "clang/Lex/PreprocessingRecord.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceManager.h" @@ -53,6 +54,7 @@ class Decl; class DeclContext; class GotoStmt; class LabelStmt; +class MacroDefinition; class NamedDecl; class Preprocessor; class Sema; @@ -151,6 +153,7 @@ private: /// actually required will be de-serialized. class PCHReader : public ExternalPreprocessorSource, + public ExternalPreprocessingRecordSource, public ExternalSemaSource, public IdentifierInfoLookup, public ExternalIdentifierLookup, @@ -296,6 +299,17 @@ private: /// been loaded. llvm::SmallVector SelectorsLoaded; + /// \brief Offsets of all of the macro definitions in the preprocessing + /// record in the PCH file. + const uint32_t *MacroDefinitionOffsets; + + /// \brief The macro definitions we have already loaded. + llvm::SmallVector MacroDefinitionsLoaded; + + /// \brief The number of preallocated preprocessing entities in the + /// preprocessing record. + unsigned NumPreallocatedPreprocessingEntities; + /// \brief A sorted array of source ranges containing comments. SourceRange *Comments; @@ -527,9 +541,7 @@ public: } /// \brief Set the Preprocessor to use. - void setPreprocessor(Preprocessor &pp) { - PP = &pp; - } + void setPreprocessor(Preprocessor &pp); /// \brief Sets and initializes the given Context. void InitializeContext(ASTContext &Context); @@ -550,6 +562,9 @@ public: /// which contains a (typically-empty) subset of the predefines /// build prior to including the precompiled header. const std::string &getSuggestedPredefines() { return SuggestedPredefines; } + + /// \brief Read preprocessed entities into the + virtual void ReadPreprocessedEntities(); /// \brief Reads the source ranges that correspond to comments from /// an external AST source. @@ -727,6 +742,9 @@ public: /// \brief Read the set of macros defined by this external macro source. virtual void ReadDefinedMacros(); + /// \brief Retrieve the macro definition with the given ID. + MacroDefinition *getMacroDefinition(pch::IdentID ID); + /// \brief Retrieve the AST context that this PCH reader /// supplements. ASTContext *getContext() { return Context; } diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index c05e2436bc..df733b6cae 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -33,6 +33,7 @@ namespace clang { class ASTContext; class LabelStmt; +class MacroDefinition; class MemorizeStatCalls; class Preprocessor; class Sema; @@ -160,6 +161,14 @@ private: /// defined. llvm::DenseMap MacroOffsets; + /// \brief Mapping from macro definitions (as they occur in the preprocessing + /// record) to the index into the macro definitions table. + llvm::DenseMap MacroDefinitions; + + /// \brief Mapping from the macro definition indices in \c MacroDefinitions + /// to the corresponding offsets within the preprocessor block. + std::vector MacroDefinitionOffsets; + /// \brief Declarations encountered that might be external /// definitions. /// @@ -272,6 +281,10 @@ public: return MacroOffsets[II]; } + /// \brief Retrieve the ID number corresponding to the given macro + /// definition. + pch::IdentID getMacroDefinitionID(MacroDefinition *MD); + /// \brief Emit a reference to a type. void AddTypeRef(QualType T, RecordData &Record); diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h index 30e5a5a4b0..b40bf36bc1 100644 --- a/include/clang/Lex/PreprocessingRecord.h +++ b/include/clang/Lex/PreprocessingRecord.h @@ -173,7 +173,18 @@ namespace clang { } static bool classof(const MacroDefinition *) { return true; } }; + + /// \brief An abstract class that should be subclassed by any external source + /// of preprocessing record entries. + class ExternalPreprocessingRecordSource { + public: + virtual ~ExternalPreprocessingRecordSource(); + /// \brief Read any preallocated preprocessed entities from the external + /// source. + virtual void ReadPreprocessedEntities() = 0; + }; + /// \brief A record of the steps taken while preprocessing a source file, /// including the various preprocessing directives processed, macros /// instantiated, etc. @@ -188,7 +199,21 @@ namespace clang { /// \brief Mapping from MacroInfo structures to their definitions. llvm::DenseMap MacroDefinitions; + /// \brief External source of preprocessed entities. + ExternalPreprocessingRecordSource *ExternalSource; + + /// \brief The number of preallocated entities (that are known to the + /// external source). + unsigned NumPreallocatedEntities; + + /// \brief Whether we have already loaded all of the preallocated entities. + mutable bool LoadedPreallocatedEntities; + + void MaybeLoadPreallocatedEntities() const ; + public: + PreprocessingRecord(); + /// \brief Allocate memory in the preprocessing record. void *Allocate(unsigned Size, unsigned Align = 8) { return BumpAlloc.Allocate(Size, Align); @@ -200,14 +225,32 @@ namespace clang { // Iteration over the preprocessed entities. typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; - iterator begin() { return PreprocessedEntities.begin(); } - iterator end() { return PreprocessedEntities.end(); } - const_iterator begin() const { return PreprocessedEntities.begin(); } - const_iterator end() const { return PreprocessedEntities.end(); } + iterator begin(bool OnlyLocalEntities = false); + iterator end(bool OnlyLocalEntities = false); + const_iterator begin(bool OnlyLocalEntities = false) const; + const_iterator end(bool OnlyLocalEntities = false) const; /// \brief Add a new preprocessed entity to this record. void addPreprocessedEntity(PreprocessedEntity *Entity); + /// \brief Set the external source for preprocessed entities. + void SetExternalSource(ExternalPreprocessingRecordSource &Source, + unsigned NumPreallocatedEntities); + + /// \brief Set the preallocated entry at the given index to the given + /// preprocessed entity. + void SetPreallocatedEntity(unsigned Index, PreprocessedEntity *Entity); + + /// \brief Register a new macro definition. + void RegisterMacroDefinition(MacroInfo *Macro, MacroDefinition *MD); + + /// \brief Retrieve the preprocessed entity at the given index. + PreprocessedEntity *getPreprocessedEntity(unsigned Index) { + assert(Index < PreprocessedEntities.size() && + "Out-of-bounds preprocessed entity"); + return PreprocessedEntities[Index]; + } + /// \brief Retrieve the macro definition that corresponds to the given /// \c MacroInfo. MacroDefinition *findMacroDefinition(MacroInfo *MI); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 36cddd32e5..7d8fee94f0 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -21,6 +21,7 @@ #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Basic/OnDiskHashTable.h" @@ -326,8 +327,9 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), TotalSelectorsInMethodPool(0), SelectorOffsets(0), - TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot), - NumStatHits(0), NumStatMisses(0), + TotalNumSelectors(0), MacroDefinitionOffsets(0), + NumPreallocatedPreprocessingEntities(0), Comments(0), NumComments(0), + isysroot(isysroot), NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0), NumStatementsRead(0), NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0), @@ -343,8 +345,9 @@ PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), TotalSelectorsInMethodPool(0), SelectorOffsets(0), - TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot), - NumStatHits(0), NumStatMisses(0), + TotalNumSelectors(0), MacroDefinitionOffsets(0), + NumPreallocatedPreprocessingEntities(0), Comments(0), NumComments(0), + isysroot(isysroot), NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0), NumStatementsRead(0), NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0), @@ -1047,12 +1050,14 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) { MacroInfo *MI = PP->AllocateMacroInfo(Loc); MI->setIsUsed(isUsed); + unsigned NextIndex = 3; if (RecType == pch::PP_MACRO_FUNCTION_LIKE) { // Decode function-like macro info. bool isC99VarArgs = Record[3]; bool isGNUVarArgs = Record[4]; MacroArgs.clear(); unsigned NumArgs = Record[5]; + NextIndex = 6 + NumArgs; for (unsigned i = 0; i != NumArgs; ++i) MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i])); @@ -1070,6 +1075,13 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) { // Remember that we saw this macro last so that we add the tokens that // form its body to it. Macro = MI; + + if (NextIndex + 1 == Record.size() && PP->getPreprocessingRecord()) { + // We have a macro definition. Load it now. + PP->getPreprocessingRecord()->RegisterMacroDefinition(Macro, + getMacroDefinition(Record[NextIndex])); + } + ++NumMacrosRead; break; } @@ -1090,6 +1102,64 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) { Macro->AddTokenToBody(Tok); break; } + + case pch::PP_MACRO_INSTANTIATION: { + // If we already have a macro, that means that we've hit the end + // of the definition of the macro we were looking for. We're + // done. + if (Macro) + return; + + if (!PP->getPreprocessingRecord()) { + Error("missing preprocessing record in PCH file"); + return; + } + + PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); + if (PPRec.getPreprocessedEntity(Record[0])) + return; + + MacroInstantiation *MI + = new (PPRec) MacroInstantiation(DecodeIdentifierInfo(Record[3]), + SourceRange( + SourceLocation::getFromRawEncoding(Record[1]), + SourceLocation::getFromRawEncoding(Record[2])), + getMacroDefinition(Record[4])); + PPRec.SetPreallocatedEntity(Record[0], MI); + return; + } + + case pch::PP_MACRO_DEFINITION: { + // If we already have a macro, that means that we've hit the end + // of the definition of the macro we were looking for. We're + // done. + if (Macro) + return; + + if (!PP->getPreprocessingRecord()) { + Error("missing preprocessing record in PCH file"); + return; + } + + PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); + if (PPRec.getPreprocessedEntity(Record[0])) + return; + + if (Record[1] >= MacroDefinitionsLoaded.size()) { + Error("out-of-bounds macro definition record"); + return; + } + + MacroDefinition *MD + = new (PPRec) MacroDefinition(DecodeIdentifierInfo(Record[4]), + SourceLocation::getFromRawEncoding(Record[5]), + SourceRange( + SourceLocation::getFromRawEncoding(Record[2]), + SourceLocation::getFromRawEncoding(Record[3]))); + PPRec.SetPreallocatedEntity(Record[0], MD); + MacroDefinitionsLoaded[Record[1]] = MD; + return; + } } } } @@ -1139,16 +1209,32 @@ void PCHReader::ReadDefinedMacros() { case pch::PP_MACRO_OBJECT_LIKE: case pch::PP_MACRO_FUNCTION_LIKE: - DecodeIdentifierInfo(Record[0]); + DecodeIdentifierInfo(Record[0]); break; case pch::PP_TOKEN: // Ignore tokens. break; + + case pch::PP_MACRO_INSTANTIATION: + case pch::PP_MACRO_DEFINITION: + // Read the macro record. + ReadMacroRecord(Cursor.GetCurrentBitNo()); + break; } } } +MacroDefinition *PCHReader::getMacroDefinition(pch::IdentID ID) { + if (ID == 0 || ID >= MacroDefinitionsLoaded.size()) + return 0; + + if (!MacroDefinitionsLoaded[ID]) + ReadMacroRecord(MacroDefinitionOffsets[ID]); + + return MacroDefinitionsLoaded[ID]; +} + /// \brief If we are loading a relocatable PCH file, and the filename is /// not an absolute path, add the system root to the beginning of the file /// name. @@ -1431,6 +1517,19 @@ PCHReader::ReadPCHBlock() { } break; } + + case pch::MACRO_DEFINITION_OFFSETS: + MacroDefinitionOffsets = (const uint32_t *)BlobStart; + if (PP) { + if (!PP->getPreprocessingRecord()) + PP->createPreprocessingRecord(); + PP->getPreprocessingRecord()->SetExternalSource(*this, Record[0]); + } else { + NumPreallocatedPreprocessingEntities = Record[0]; + } + + MacroDefinitionsLoaded.resize(Record[1]); + break; } } Error("premature end of bitstream in PCH file"); @@ -1562,6 +1661,18 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { return Success; } +void PCHReader::setPreprocessor(Preprocessor &pp) { + PP = &pp; + + if (NumPreallocatedPreprocessingEntities) { + if (!PP->getPreprocessingRecord()) + PP->createPreprocessingRecord(); + PP->getPreprocessingRecord()->SetExternalSource(*this, + NumPreallocatedPreprocessingEntities); + NumPreallocatedPreprocessingEntities = 0; + } +} + void PCHReader::InitializeContext(ASTContext &Ctx) { Context = &Ctx; assert(Context && "Passed null context!"); @@ -1823,6 +1934,10 @@ bool PCHReader::ParseLanguageOptions( return false; } +void PCHReader::ReadPreprocessedEntities() { + ReadDefinedMacros(); +} + void PCHReader::ReadComments(std::vector &Comments) { Comments.resize(NumComments); std::copy(this->Comments, this->Comments + NumComments, diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index e55599b7ec..df41ca1e59 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -21,6 +21,7 @@ #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Basic/FileManager.h" @@ -565,7 +566,9 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(EXT_VECTOR_DECLS); RECORD(COMMENT_RANGES); RECORD(VERSION_CONTROL_BRANCH_REVISION); - + RECORD(UNUSED_STATIC_FUNCS); + RECORD(MACRO_DEFINITION_OFFSETS); + // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); RECORD(SM_SLOC_FILE_ENTRY); @@ -579,7 +582,9 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(PP_MACRO_OBJECT_LIKE); RECORD(PP_MACRO_FUNCTION_LIKE); RECORD(PP_TOKEN); - + RECORD(PP_MACRO_INSTANTIATION); + RECORD(PP_MACRO_DEFINITION); + // Decls and Types block. BLOCK(DECLTYPES_BLOCK); RECORD(TYPE_EXT_QUAL); @@ -1174,6 +1179,7 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { // Loop over all the macro definitions that are live at the end of the file, // emitting each to the PP section. + PreprocessingRecord *PPRec = PP.getPreprocessingRecord(); for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); I != E; ++I) { // FIXME: This emits macros in hash table order, we should do it in a stable @@ -1203,6 +1209,12 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { I != E; ++I) AddIdentifierRef(*I, Record); } + + // If we have a detailed preprocessing record, record the macro definition + // ID that corresponds to this macro. + if (PPRec) + Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI))); + Stream.EmitRecord(Code, Record); Record.clear(); @@ -1230,7 +1242,68 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { } ++NumMacros; } + + // If the preprocessor has a preprocessing record, emit it. + unsigned NumPreprocessingRecords = 0; + if (PPRec) { + for (PreprocessingRecord::iterator E = PPRec->begin(), EEnd = PPRec->end(); + E != EEnd; ++E) { + Record.clear(); + + if (MacroInstantiation *MI = dyn_cast(*E)) { + Record.push_back(NumPreprocessingRecords++); + AddSourceLocation(MI->getSourceRange().getBegin(), Record); + AddSourceLocation(MI->getSourceRange().getEnd(), Record); + AddIdentifierRef(MI->getName(), Record); + Record.push_back(getMacroDefinitionID(MI->getDefinition())); + Stream.EmitRecord(pch::PP_MACRO_INSTANTIATION, Record); + continue; + } + + if (MacroDefinition *MD = dyn_cast(*E)) { + // Record this macro definition's location. + pch::IdentID ID = getMacroDefinitionID(MD); + if (ID != MacroDefinitionOffsets.size()) { + if (ID > MacroDefinitionOffsets.size()) + MacroDefinitionOffsets.resize(ID + 1); + + MacroDefinitionOffsets[ID] = Stream.GetCurrentBitNo(); + } else + MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo()); + + Record.push_back(NumPreprocessingRecords++); + Record.push_back(ID); + AddSourceLocation(MD->getSourceRange().getBegin(), Record); + AddSourceLocation(MD->getSourceRange().getEnd(), Record); + AddIdentifierRef(MD->getName(), Record); + AddSourceLocation(MD->getLocation(), Record); + Stream.EmitRecord(pch::PP_MACRO_DEFINITION, Record); + continue; + } + } + } + Stream.ExitBlock(); + + // Write the offsets table for the preprocessing record. + if (NumPreprocessingRecords > 0) { + // Write the offsets table for identifier IDs. + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::MACRO_DEFINITION_OFFSETS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + + Record.clear(); + Record.push_back(pch::MACRO_DEFINITION_OFFSETS); + Record.push_back(NumPreprocessingRecords); + Record.push_back(MacroDefinitionOffsets.size()); + Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record, + (const char *)&MacroDefinitionOffsets.front(), + MacroDefinitionOffsets.size() * sizeof(uint32_t)); + } } void PCHWriter::WriteComments(ASTContext &Context) { @@ -2009,7 +2082,7 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Write the remaining PCH contents. RecordData Record; - Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4); + Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5); WriteMetadata(Context, isysroot); WriteLanguageOptions(Context.getLangOptions()); if (StatCalls && !isysroot) @@ -2149,6 +2222,16 @@ pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) { return ID; } +pch::IdentID PCHWriter::getMacroDefinitionID(MacroDefinition *MD) { + if (MD == 0) + return 0; + + pch::IdentID &ID = MacroDefinitions[MD]; + if (ID == 0) + ID = MacroDefinitions.size(); + return ID; +} + void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) { if (SelRef.getAsOpaquePtr() == 0) { Record.push_back(0); diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp index 6e0e28a1b8..4921a7fd90 100644 --- a/lib/Lex/PreprocessingRecord.cpp +++ b/lib/Lex/PreprocessingRecord.cpp @@ -17,10 +17,81 @@ using namespace clang; +ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { } + +void PreprocessingRecord::MaybeLoadPreallocatedEntities() const { + if (!ExternalSource || LoadedPreallocatedEntities) + return; + + LoadedPreallocatedEntities = true; + ExternalSource->ReadPreprocessedEntities(); +} + +PreprocessingRecord::PreprocessingRecord() + : ExternalSource(0), NumPreallocatedEntities(0), + LoadedPreallocatedEntities(false) +{ +} + +PreprocessingRecord::iterator +PreprocessingRecord::begin(bool OnlyLocalEntities) { + if (OnlyLocalEntities) + return PreprocessedEntities.begin() + NumPreallocatedEntities; + + MaybeLoadPreallocatedEntities(); + return PreprocessedEntities.begin(); +} + +PreprocessingRecord::iterator PreprocessingRecord::end(bool OnlyLocalEntities) { + if (!OnlyLocalEntities) + MaybeLoadPreallocatedEntities(); + + return PreprocessedEntities.end(); +} + +PreprocessingRecord::const_iterator +PreprocessingRecord::begin(bool OnlyLocalEntities) const { + if (OnlyLocalEntities) + return PreprocessedEntities.begin() + NumPreallocatedEntities; + + MaybeLoadPreallocatedEntities(); + return PreprocessedEntities.begin(); +} + +PreprocessingRecord::const_iterator +PreprocessingRecord::end(bool OnlyLocalEntities) const { + if (!OnlyLocalEntities) + MaybeLoadPreallocatedEntities(); + + return PreprocessedEntities.end(); +} + void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) { PreprocessedEntities.push_back(Entity); } +void PreprocessingRecord::SetExternalSource( + ExternalPreprocessingRecordSource &Source, + unsigned NumPreallocatedEntities) { + assert(!ExternalSource && + "Preprocessing record already has an external source"); + ExternalSource = &Source; + this->NumPreallocatedEntities = NumPreallocatedEntities; + PreprocessedEntities.insert(PreprocessedEntities.begin(), + NumPreallocatedEntities, 0); +} + +void PreprocessingRecord::SetPreallocatedEntity(unsigned Index, + PreprocessedEntity *Entity) { + assert(Index < NumPreallocatedEntities &&"Out-of-bounds preallocated entity"); + PreprocessedEntities[Index] = Entity; +} + +void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro, + MacroDefinition *MD) { + MacroDefinitions[Macro] = MD; +} + MacroDefinition *PreprocessingRecord::findMacroDefinition(MacroInfo *MI) { llvm::DenseMap::iterator Pos = MacroDefinitions.find(MI); @@ -45,3 +116,4 @@ void PreprocessingRecord::MacroDefined(const IdentifierInfo *II, MacroDefinitions[MI] = Def; PreprocessedEntities.push_back(Def); } + diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m index 62701dbc0c..52e19dffb3 100644 --- a/test/Index/c-index-getCursor-test.m +++ b/test/Index/c-index-getCursor-test.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -detailed-preprocessing-record -o %t.ast // RUN: c-index-test -test-file-scan %t.ast %s | FileCheck %s @interface Foo { @@ -161,3 +161,7 @@ void f() { // CHECK: [52:33 - 52:36] DeclRefExpr=bee:45:8 // CHECK: [52:36 - 52:37] CallExpr=main:44:5 // CHECK: [52:37 - 53:2] UnexposedStmt= +// CHECK: [55:9 - 55:26] macro definition=CONCAT +// CHECK: [57:6 - 57:10] FunctionDecl=f:57:6 (Definition) +// CHECK: [58:4 - 58:8] VarDecl=my_var:58:8 (Definition) +// CHECK: [58:8 - 58:14] macro instantiation=CONCAT:55:9 diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index f20595e356..7d63d26b92 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -158,31 +158,12 @@ static RangeComparisonResult RangeCompare(SourceManager &SM, CXSourceRange cxloc::translateSourceRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R) { - // FIXME: This is largely copy-paste from - // TextDiagnosticPrinter::HighlightRange. When it is clear that this is what - // we want the two routines should be refactored. - // We want the last character in this location, so we will adjust the - // instantiation location accordingly. - - // If the location is from a macro instantiation, get the end of the - // instantiation range. + // location accordingly. + // FIXME: How do do this with a macro instantiation location? SourceLocation EndLoc = R.getEnd(); - SourceLocation InstLoc = SM.getInstantiationLoc(EndLoc); - if (EndLoc.isMacroID()) - InstLoc = SM.getInstantiationRange(EndLoc).second; - - // Measure the length token we're pointing at, so we can adjust the physical - // location in the file to point at the last character. - // - // FIXME: This won't cope with trigraphs or escaped newlines well. For that, - // we actually need a preprocessor, which isn't currently available - // here. Eventually, we'll switch the pointer data of - // CXSourceLocation/CXSourceRange to a translation unit (CXXUnit), so that the - // preprocessor will be available here. At that point, we can use - // Preprocessor::getLocForEndOfToken(). - if (InstLoc.isValid()) { - unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM, LangOpts); + if (!EndLoc.isInvalid() && EndLoc.isFileID()) { + unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts); EndLoc = EndLoc.getFileLocWithOffset(Length); } @@ -434,7 +415,11 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { = CXXUnit->getPreprocessor().getPreprocessingRecord()) { // FIXME: Once we have the ability to deserialize a preprocessing record, // do so. - for (PreprocessingRecord::iterator E = PPRec->begin(),EEnd = PPRec->end(); + bool OnlyLocalDecls + = !CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls(); + for (PreprocessingRecord::iterator + E = PPRec->begin(OnlyLocalDecls), + EEnd = PPRec->end(OnlyLocalDecls); E != EEnd; ++E) { if (MacroInstantiation *MI = dyn_cast(*E)) { if (Visit(MakeMacroInstantiationCursor(MI, CXXUnit)))