diff options
-rw-r--r-- | include/clang/Frontend/PCHBitCodes.h | 14 | ||||
-rw-r--r-- | include/clang/Frontend/PCHReader.h | 24 | ||||
-rw-r--r-- | include/clang/Frontend/PCHWriter.h | 13 | ||||
-rw-r--r-- | include/clang/Lex/PreprocessingRecord.h | 51 | ||||
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 125 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 89 | ||||
-rw-r--r-- | lib/Lex/PreprocessingRecord.cpp | 72 | ||||
-rw-r--r-- | test/Index/c-index-getCursor-test.m | 6 | ||||
-rw-r--r-- | tools/CIndex/CIndex.cpp | 33 |
9 files changed, 385 insertions, 42 deletions
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<Selector, 16> 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<MacroDefinition *, 16> 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<const IdentifierInfo *, uint64_t> MacroOffsets; + /// \brief Mapping from macro definitions (as they occur in the preprocessing + /// record) to the index into the macro definitions table. + llvm::DenseMap<const MacroDefinition *, pch::IdentID> MacroDefinitions; + + /// \brief Mapping from the macro definition indices in \c MacroDefinitions + /// to the corresponding offsets within the preprocessor block. + std::vector<uint32_t> 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<const MacroInfo *, MacroDefinition *> 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<PreprocessedEntity *>::iterator iterator; typedef std::vector<PreprocessedEntity *>::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<SourceRange> &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<MacroInstantiation>(*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<MacroDefinition>(*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<const MacroInfo *, MacroDefinition *>::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<MacroInstantiation>(*E)) { if (Visit(MakeMacroInstantiationCursor(MI, CXXUnit))) |