From: Argyrios Kyrtzidis Date: Mon, 19 Sep 2011 20:40:25 +0000 (+0000) Subject: Introduce PreprocessingRecord::getPreprocessedEntitiesInRange() X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2dbaca748bc3eb6539f417bd8354c930bdf88fa4;p=clang Introduce PreprocessingRecord::getPreprocessedEntitiesInRange() which will do a binary search and return a pair of iterators for preprocessed entities in the given source range. Source ranges of preprocessed entities are stored twice currently in the PCH/Module file but this will be fixed in a subsequent commit. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140058 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h index 0cc6cc5377..b348c4e7c7 100644 --- a/include/clang/Lex/PreprocessingRecord.h +++ b/include/clang/Lex/PreprocessingRecord.h @@ -271,6 +271,11 @@ namespace clang { /// entity from being loaded. virtual PreprocessedEntity *ReadPreprocessedEntity(unsigned Index) = 0; + /// \brief Returns a pair of [Begin, End) indices of preallocated + /// preprocessed entities that \arg Range encompasses. + virtual std::pair + findPreprocessedEntitiesInRange(SourceRange Range) = 0; + /// \brief Read the preprocessed entity at the given offset. virtual PreprocessedEntity * ReadPreprocessedEntityAtOffset(uint64_t Offset) = 0; @@ -280,6 +285,8 @@ namespace clang { /// including the various preprocessing directives processed, macros /// expanded, etc. class PreprocessingRecord : public PPCallbacks { + SourceManager &SourceMgr; + /// \brief Whether we should include nested macro expansions in /// the preprocessing record. bool IncludeNestedMacroExpansions; @@ -329,7 +336,14 @@ namespace clang { unsigned getNumLoadedPreprocessedEntities() const { return LoadedPreprocessedEntities.size(); } - + + /// \brief Returns a pair of [Begin, End) indices of local preprocessed + /// entities that \arg Range encompasses. + std::pair + findLocalPreprocessedEntitiesInRange(SourceRange Range) const; + unsigned findBeginLocalPreprocessedEntity(SourceLocation Loc) const; + unsigned findEndLocalPreprocessedEntity(SourceLocation Loc) const; + /// \brief Allocate space for a new set of loaded preprocessed entities. /// /// \returns The index into the set of loaded preprocessed entities, which @@ -341,7 +355,7 @@ namespace clang { public: /// \brief Construct a new preprocessing record. - explicit PreprocessingRecord(bool IncludeNestedMacroExpansions); + PreprocessingRecord(SourceManager &SM, bool IncludeNestedMacroExpansions); /// \brief Allocate memory in the preprocessing record. void *Allocate(unsigned Size, unsigned Align = 8) { @@ -353,6 +367,8 @@ namespace clang { size_t getTotalMemory() const; + SourceManager &getSourceManager() const { return SourceMgr; } + // Iteration over the preprocessed entities. class iterator { PreprocessingRecord *Self; @@ -471,6 +487,10 @@ namespace clang { iterator begin(bool OnlyLocalEntities = false); iterator end(bool OnlyLocalEntities = false); + /// \brief Returns a pair of [Begin, End) iterators of preprocessed entities + /// that source range \arg R encompasses. + std::pair getPreprocessedEntitiesInRange(SourceRange R); + /// \brief Add a new preprocessed entity to this record. void addPreprocessedEntity(PreprocessedEntity *Entity); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index f3dd8dc860..b8db49e76a 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -141,6 +141,21 @@ namespace clang { /// preprocessing record. typedef uint32_t PreprocessedEntityID; + /// \brief Source range/offset of a preprocessed entity. + struct PPEntityOffset { + /// \brief Raw source location of beginning of range. + unsigned Begin; + /// \brief Raw source location of end of range. + unsigned End; + /// \brief Offset in the AST file. + uint32_t BitOffset; + + PPEntityOffset(SourceRange R, uint32_t BitOffset) + : Begin(R.getBegin().getRawEncoding()), + End(R.getEnd().getRawEncoding()), + BitOffset(BitOffset) { } + }; + /// \brief The number of predefined preprocessed entity IDs. const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1; diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index cc5c1d76e0..96b5e5835c 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -248,6 +248,12 @@ private: /// \brief A map of negated SLocEntryIDs to the modules containing them. ContinuousRangeMap GlobalSLocEntryMap; + typedef ContinuousRangeMap GlobalSLocOffsetMapType; + + /// \brief A map of negated SourceLocation offsets to the modules containing + /// them. + GlobalSLocOffsetMapType GlobalSLocOffsetMap; + /// \brief Types that have already been loaded from the chain. /// /// When the pointer at index I is non-NULL, the type with @@ -680,7 +686,23 @@ private: RecordLocation getLocalBitOffset(uint64_t GlobalOffset); uint64_t getGlobalBitOffset(Module &M, uint32_t LocalOffset); - + + /// \brief Returns the first preprocessed entity ID that ends after \arg BLoc. + serialization::PreprocessedEntityID + findBeginPreprocessedEntity(SourceLocation BLoc) const; + + /// \brief Returns the first preprocessed entity ID that begins after \arg ELoc. + serialization::PreprocessedEntityID + findEndPreprocessedEntity(SourceLocation ELoc) const; + + /// \brief \arg SLocMapI points at a chunk of a module that contains no + /// preprocessed entities or the entities it contains are not the ones we are + /// looking for. Find the next module that contains entities and return the ID + /// of the first entry. + serialization::PreprocessedEntityID + findNextPreprocessedEntity( + GlobalSLocOffsetMapType::const_iterator SLocMapI) const; + void PassInterestingDeclsToConsumer(); /// \brief Produce an error diagnostic and return true. @@ -723,6 +745,8 @@ public: ~ASTReader(); + SourceManager &getSourceManager() const { return SourceMgr; } + /// \brief Load the AST file designated by the given file name. ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type); @@ -772,6 +796,11 @@ public: /// entity from being loaded. virtual PreprocessedEntity *ReadPreprocessedEntity(unsigned Index); + /// \brief Returns a pair of [Begin, End) indices of preallocated + /// preprocessed entities that \arg Range encompasses. + virtual std::pair + findPreprocessedEntitiesInRange(SourceRange Range); + /// \brief Read the preprocessed entity at the given offset. virtual PreprocessedEntity *ReadPreprocessedEntityAtOffset(uint64_t Offset); diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h index 9f063316c1..42b5a58e08 100644 --- a/include/clang/Serialization/Module.h +++ b/include/clang/Serialization/Module.h @@ -177,7 +177,7 @@ public: /// \brief Remapping table for preprocessed entity IDs in this module. ContinuousRangeMap PreprocessedEntityRemap; - const uint32_t *PreprocessedEntityOffsets; + const PPEntityOffset *PreprocessedEntityOffsets; unsigned NumPreprocessedEntities; // === Header search information === diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp index 8d96fb00ca..1fc8230763 100644 --- a/lib/Lex/PreprocessingRecord.cpp +++ b/lib/Lex/PreprocessingRecord.cpp @@ -37,8 +37,9 @@ InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec, this->FileName = StringRef(Memory, FileName.size()); } -PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroExpansions) - : IncludeNestedMacroExpansions(IncludeNestedMacroExpansions), +PreprocessingRecord::PreprocessingRecord(SourceManager &SM, + bool IncludeNestedMacroExpansions) + : SourceMgr(SM), IncludeNestedMacroExpansions(IncludeNestedMacroExpansions), ExternalSource(0) { } @@ -55,7 +56,111 @@ PreprocessingRecord::iterator PreprocessingRecord::end(bool OnlyLocalEntities) { return iterator(this, PreprocessedEntities.size()); } +/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities +/// that source range \arg R encompasses. +std::pair +PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) { + if (Range.isInvalid()) + return std::make_pair(iterator(this, 0), iterator(this, 0)); + assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); + + std::pair + Local = findLocalPreprocessedEntitiesInRange(Range); + + // Check if range spans local entities. + if (!ExternalSource || SourceMgr.isLocalSourceLocation(Range.getBegin())) + return std::make_pair(iterator(this, Local.first), + iterator(this, Local.second)); + + std::pair + Loaded = ExternalSource->findPreprocessedEntitiesInRange(Range); + + // Check if range spans local entities. + if (Loaded.first == Loaded.second) + return std::make_pair(iterator(this, Local.first), + iterator(this, Local.second)); + + unsigned TotalLoaded = LoadedPreprocessedEntities.size(); + + // Check if range spans loaded entities. + if (Local.first == Local.second) + return std::make_pair(iterator(this, int(Loaded.first)-TotalLoaded), + iterator(this, int(Loaded.second)-TotalLoaded)); + + // Range spands loaded and local entities. + return std::make_pair(iterator(this, int(Loaded.first)-TotalLoaded), + iterator(this, Local.second)); +} + +std::pair +PreprocessingRecord::findLocalPreprocessedEntitiesInRange( + SourceRange Range) const { + if (Range.isInvalid()) + return std::make_pair(0,0); + assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); + + unsigned Begin = findBeginLocalPreprocessedEntity(Range.getBegin()); + unsigned End = findEndLocalPreprocessedEntity(Range.getEnd()); + return std::make_pair(Begin, End); +} + +namespace { + +template +struct PPEntityComp { + const SourceManager &SM; + + explicit PPEntityComp(const SourceManager &SM) : SM(SM) { } + + bool operator()(PreprocessedEntity *L, SourceLocation RHS) { + SourceLocation LHS = getLoc(L); + return SM.isBeforeInTranslationUnit(LHS, RHS); + } + + bool operator()(SourceLocation LHS, PreprocessedEntity *R) { + SourceLocation RHS = getLoc(R); + return SM.isBeforeInTranslationUnit(LHS, RHS); + } + + SourceLocation getLoc(PreprocessedEntity *PPE) const { + return (PPE->getSourceRange().*getRangeLoc)(); + } +}; + +} + +unsigned PreprocessingRecord::findBeginLocalPreprocessedEntity( + SourceLocation Loc) const { + if (SourceMgr.isLoadedSourceLocation(Loc)) + return 0; + + std::vector::const_iterator + I = std::lower_bound(PreprocessedEntities.begin(), + PreprocessedEntities.end(), + Loc, + PPEntityComp<&SourceRange::getEnd>(SourceMgr)); + return I - PreprocessedEntities.begin(); +} + +unsigned PreprocessingRecord::findEndLocalPreprocessedEntity( + SourceLocation Loc) const { + if (SourceMgr.isLoadedSourceLocation(Loc)) + return 0; + + std::vector::const_iterator + I = std::upper_bound(PreprocessedEntities.begin(), + PreprocessedEntities.end(), + Loc, + PPEntityComp<&SourceRange::getBegin>(SourceMgr)); + return I - PreprocessedEntities.begin(); +} + void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) { + SourceLocation Loc = Entity->getSourceRange().getBegin(); + assert((PreprocessedEntities.empty() || + !SourceMgr.isBeforeInTranslationUnit(Loc, + PreprocessedEntities.back()->getSourceRange().getEnd())) && + "Adding a preprocessed entity that is before the previous one in TU"); PreprocessedEntities.push_back(Entity); } @@ -124,10 +229,10 @@ void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI, return; if (MI->isBuiltinMacro()) - PreprocessedEntities.push_back( + addPreprocessedEntity( new (*this) MacroExpansion(Id.getIdentifierInfo(),Range)); else if (MacroDefinition *Def = findMacroDefinition(MI)) - PreprocessedEntities.push_back( + addPreprocessedEntity( new (*this) MacroExpansion(Def, Range)); } @@ -138,7 +243,7 @@ void PreprocessingRecord::MacroDefined(const Token &Id, = new (*this) MacroDefinition(Id.getIdentifierInfo(), MI->getDefinitionLoc(), R); - PreprocessedEntities.push_back(Def); + addPreprocessedEntity(Def); MacroDefinitions[MI] = getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false); } @@ -187,7 +292,7 @@ void PreprocessingRecord::InclusionDirective( clang::InclusionDirective *ID = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled, File, SourceRange(HashLoc, EndLoc)); - PreprocessedEntities.push_back(ID); + addPreprocessedEntity(ID); } size_t PreprocessingRecord::getTotalMemory() const { diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index cf63e270aa..8c1004b5f5 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -602,6 +602,7 @@ void Preprocessor::createPreprocessingRecord( if (Record) return; - Record = new PreprocessingRecord(IncludeNestedMacroExpansions); + Record = new PreprocessingRecord(getSourceManager(), + IncludeNestedMacroExpansions); addPPCallbacks(Record); } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 0c23431b94..0f3cad5513 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2011,8 +2011,10 @@ ASTReader::ReadASTBlock(Module &F) { case SOURCE_LOCATION_OFFSETS: { F.SLocEntryOffsets = (const uint32_t *)BlobStart; F.LocalNumSLocEntries = Record[0]; + unsigned SLocSpaceSize = Record[1]; llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) = - SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries, Record[1]); + SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries, + SLocSpaceSize); // Make our entry in the range map. BaseID is negative and growing, so // we invert it. Because we invert it, though, we need the other end of // the range. @@ -2021,6 +2023,12 @@ ASTReader::ReadASTBlock(Module &F) { GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F)); F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset); + // SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing. + assert((F.SLocEntryBaseOffset & (1U << 31U)) == 0); + GlobalSLocOffsetMap.insert( + std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset + - SLocSpaceSize,&F)); + // Initialize the remapping table. // Invalid stays invalid. F.SLocRemap.insert(std::make_pair(0U, 0)); @@ -2201,9 +2209,9 @@ ASTReader::ReadASTBlock(Module &F) { } case PPD_ENTITIES_OFFSETS: { - F.PreprocessedEntityOffsets = (const uint32_t *)BlobStart; - assert(BlobLen % sizeof(uint32_t) == 0); - F.NumPreprocessedEntities = BlobLen / sizeof(uint32_t); + F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart; + assert(BlobLen % sizeof(PPEntityOffset) == 0); + F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset); unsigned LocalBasePreprocessedEntityID = Record[0]; @@ -2878,10 +2886,127 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { unsigned LocalIndex = Index - M.BasePreprocessedEntityID; SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor); - M.PreprocessorDetailCursor.JumpToBit(M.PreprocessedEntityOffsets[LocalIndex]); + M.PreprocessorDetailCursor.JumpToBit( + M.PreprocessedEntityOffsets[LocalIndex].BitOffset); return LoadPreprocessedEntity(M); } +/// \brief \arg SLocMapI points at a chunk of a module that contains no +/// preprocessed entities or the entities it contains are not the ones we are +/// looking for. Find the next module that contains entities and return the ID +/// of the first entry. +PreprocessedEntityID ASTReader::findNextPreprocessedEntity( + GlobalSLocOffsetMapType::const_iterator SLocMapI) const { + ++SLocMapI; + for (GlobalSLocOffsetMapType::const_iterator + EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) { + Module &M = *SLocMapI->second; + if (M.NumPreprocessedEntities) + return getGlobalPreprocessedEntityID(M, M.BasePreprocessedEntityID); + } + + return getTotalNumPreprocessedEntities(); +} + +namespace { + +template +struct PPEntityComp { + const ASTReader &Reader; + Module &M; + + PPEntityComp(const ASTReader &Reader, Module &M) : Reader(Reader), M(M) { } + + bool operator()(const PPEntityOffset &L, SourceLocation RHS) { + SourceLocation LHS = getLoc(L); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + bool operator()(SourceLocation LHS, const PPEntityOffset &R) { + SourceLocation RHS = getLoc(R); + return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); + } + + SourceLocation getLoc(const PPEntityOffset &PPE) const { + return Reader.ReadSourceLocation(M, PPE.*PPLoc); + } +}; + +} + +/// \brief Returns the first preprocessed entity ID that ends after \arg BLoc. +PreprocessedEntityID +ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const { + if (SourceMgr.isLocalSourceLocation(BLoc)) + return getTotalNumPreprocessedEntities(); + + GlobalSLocOffsetMapType::const_iterator + SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - + BLoc.getOffset()); + assert(SLocMapI != GlobalSLocOffsetMap.end() && + "Corrupted global sloc offset map"); + + if (SLocMapI->second->NumPreprocessedEntities == 0) + return findNextPreprocessedEntity(SLocMapI); + + Module &M = *SLocMapI->second; + typedef const PPEntityOffset *pp_iterator; + pp_iterator pp_begin = M.PreprocessedEntityOffsets; + pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; + pp_iterator PPI = + std::lower_bound(pp_begin, pp_end, BLoc, + PPEntityComp<&PPEntityOffset::End>(*this, M)); + + if (PPI == pp_end) + return findNextPreprocessedEntity(SLocMapI); + + return getGlobalPreprocessedEntityID(M, + M.BasePreprocessedEntityID + (PPI - pp_begin)); +} + +/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc. +PreprocessedEntityID +ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const { + if (SourceMgr.isLocalSourceLocation(ELoc)) + return getTotalNumPreprocessedEntities(); + + GlobalSLocOffsetMapType::const_iterator + SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - + ELoc.getOffset()); + assert(SLocMapI != GlobalSLocOffsetMap.end() && + "Corrupted global sloc offset map"); + + if (SLocMapI->second->NumPreprocessedEntities == 0) + return findNextPreprocessedEntity(SLocMapI); + + Module &M = *SLocMapI->second; + typedef const PPEntityOffset *pp_iterator; + pp_iterator pp_begin = M.PreprocessedEntityOffsets; + pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; + pp_iterator PPI = + std::upper_bound(pp_begin, pp_end, ELoc, + PPEntityComp<&PPEntityOffset::Begin>(*this, M)); + + if (PPI == pp_end) + return findNextPreprocessedEntity(SLocMapI); + + return getGlobalPreprocessedEntityID(M, + M.BasePreprocessedEntityID + (PPI - pp_begin)); +} + +/// \brief Returns a pair of [Begin, End) indices of preallocated +/// preprocessed entities that \arg Range encompasses. +std::pair + ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) { + if (Range.isInvalid()) + return std::make_pair(0,0); + assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); + + PreprocessedEntityID BeginID = findBeginPreprocessedEntity(Range.getBegin()); + PreprocessedEntityID EndID = findEndPreprocessedEntity(Range.getEnd()); + return std::make_pair(BeginID, EndID); +} + PreprocessedEntity *ASTReader::ReadPreprocessedEntityAtOffset(uint64_t Offset) { RecordLocation Loc = getLocalBitOffset(Offset); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 335ac3f07a..3227476ee9 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1714,7 +1714,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { if (PPRec.begin(Chain) == PPRec.end(Chain)) return; - SmallVector PreprocessedEntityOffsets; + SmallVector PreprocessedEntityOffsets; // Enter the preprocessor block. Stream.EnterSubblock(PREPROCESSOR_DETAIL_BLOCK_ID, 3); @@ -1750,7 +1750,8 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { (void)++E, ++NumPreprocessingRecords, ++NextPreprocessorEntityID) { Record.clear(); - PreprocessedEntityOffsets.push_back(Stream.GetCurrentBitNo()); + PreprocessedEntityOffsets.push_back(PPEntityOffset((*E)->getSourceRange(), + Stream.GetCurrentBitNo())); if (MacroDefinition *MD = dyn_cast(*E)) { // Record this macro definition's ID.