diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp | 265 |
1 files changed, 225 insertions, 40 deletions
diff --git a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp index 2816609..89d19fd 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp @@ -38,10 +38,13 @@ InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec, } PreprocessingRecord::PreprocessingRecord(SourceManager &SM, - bool IncludeNestedMacroExpansions) - : SourceMgr(SM), IncludeNestedMacroExpansions(IncludeNestedMacroExpansions), + bool RecordConditionalDirectives) + : SourceMgr(SM), + RecordCondDirectives(RecordConditionalDirectives), CondDirectiveNextIdx(0), ExternalSource(0) { + if (RecordCondDirectives) + CondDirectiveStack.push_back(CondDirectiveNextIdx++); } /// \brief Returns a pair of [Begin, End) iterators of preprocessed entities @@ -49,35 +52,108 @@ PreprocessingRecord::PreprocessingRecord(SourceManager &SM, std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) { if (Range.isInvalid()) - return std::make_pair(iterator(this, 0), iterator(this, 0)); - assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); + return std::make_pair(iterator(), iterator()); + + if (CachedRangeQuery.Range == Range) { + return std::make_pair(iterator(this, CachedRangeQuery.Result.first), + iterator(this, CachedRangeQuery.Result.second)); + } + + std::pair<PPEntityID, PPEntityID> + Res = getPreprocessedEntitiesInRangeSlow(Range); + + CachedRangeQuery.Range = Range; + CachedRangeQuery.Result = Res; + + return std::make_pair(iterator(this, Res.first), iterator(this, Res.second)); +} + +static bool isPreprocessedEntityIfInFileID(PreprocessedEntity *PPE, FileID FID, + SourceManager &SM) { + assert(!FID.isInvalid()); + if (!PPE) + return false; + + SourceLocation Loc = PPE->getSourceRange().getBegin(); + if (Loc.isInvalid()) + return false; + + if (SM.isInFileID(SM.getFileLoc(Loc), FID)) + return true; + else + return false; +} + +/// \brief Returns true if the preprocessed entity that \arg PPEI iterator +/// points to is coming from the file \arg FID. +/// +/// Can be used to avoid implicit deserializations of preallocated +/// preprocessed entities if we only care about entities of a specific file +/// and not from files #included in the range given at +/// \see getPreprocessedEntitiesInRange. +bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) { + if (FID.isInvalid()) + return false; + + PPEntityID PPID = PPEI.Position; + if (PPID < 0) { + assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() && + "Out-of bounds loaded preprocessed entity"); + assert(ExternalSource && "No external source to load from"); + unsigned LoadedIndex = LoadedPreprocessedEntities.size()+PPID; + if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex]) + return isPreprocessedEntityIfInFileID(PPE, FID, SourceMgr); + + // See if the external source can see if the entity is in the file without + // deserializing it. + llvm::Optional<bool> + IsInFile = ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID); + if (IsInFile.hasValue()) + return IsInFile.getValue(); + + // The external source did not provide a definite answer, go and deserialize + // the entity to check it. + return isPreprocessedEntityIfInFileID( + getLoadedPreprocessedEntity(LoadedIndex), + FID, SourceMgr); + } + + assert(unsigned(PPID) < PreprocessedEntities.size() && + "Out-of bounds local preprocessed entity"); + return isPreprocessedEntityIfInFileID(PreprocessedEntities[PPID], + FID, SourceMgr); +} +/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities +/// that source range \arg R encompasses. +std::pair<PreprocessingRecord::PPEntityID, PreprocessingRecord::PPEntityID> +PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range) { + assert(Range.isValid()); + assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); + std::pair<unsigned, unsigned> 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)); - + return std::make_pair(Local.first, Local.second); + std::pair<unsigned, unsigned> 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)); - + return std::make_pair(Local.first, 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)); - + return std::make_pair(int(Loaded.first)-TotalLoaded, + int(Loaded.second)-TotalLoaded); + // Range spands loaded and local entities. - return std::make_pair(iterator(this, int(Loaded.first)-TotalLoaded), - iterator(this, Local.second)); + return std::make_pair(int(Loaded.first)-TotalLoaded, Local.second); } std::pair<unsigned, unsigned> @@ -168,33 +244,58 @@ unsigned PreprocessingRecord::findEndLocalPreprocessedEntity( return I - PreprocessedEntities.begin(); } -void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) { +PreprocessingRecord::PPEntityID +PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) { assert(Entity); SourceLocation BeginLoc = Entity->getSourceRange().getBegin(); - + + if (!isa<class InclusionDirective>(Entity)) { + assert((PreprocessedEntities.empty() || + !SourceMgr.isBeforeInTranslationUnit(BeginLoc, + PreprocessedEntities.back()->getSourceRange().getBegin())) && + "a macro directive was encountered out-of-order"); + PreprocessedEntities.push_back(Entity); + return getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false); + } + // Check normal case, this entity begin location is after the previous one. if (PreprocessedEntities.empty() || !SourceMgr.isBeforeInTranslationUnit(BeginLoc, PreprocessedEntities.back()->getSourceRange().getBegin())) { PreprocessedEntities.push_back(Entity); - return; + return getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false); } - // The entity's location is not after the previous one; this can happen rarely - // e.g. with "#include MACRO". - // Iterate the entities vector in reverse until we find the right place to - // insert the new entity. - for (std::vector<PreprocessedEntity *>::iterator - RI = PreprocessedEntities.end(), Begin = PreprocessedEntities.begin(); - RI != Begin; --RI) { - std::vector<PreprocessedEntity *>::iterator I = RI; + // The entity's location is not after the previous one; this can happen with + // include directives that form the filename using macros, e.g: + // "#include MACRO(STUFF)". + + typedef std::vector<PreprocessedEntity *>::iterator pp_iter; + + // Usually there are few macro expansions when defining the filename, do a + // linear search for a few entities. + unsigned count = 0; + for (pp_iter RI = PreprocessedEntities.end(), + Begin = PreprocessedEntities.begin(); + RI != Begin && count < 4; --RI, ++count) { + pp_iter I = RI; --I; if (!SourceMgr.isBeforeInTranslationUnit(BeginLoc, (*I)->getSourceRange().getBegin())) { - PreprocessedEntities.insert(RI, Entity); - return; + pp_iter insertI = PreprocessedEntities.insert(RI, Entity); + return getPPEntityID(insertI - PreprocessedEntities.begin(), + /*isLoaded=*/false); } } + + // Linear search unsuccessful. Do a binary search. + pp_iter I = std::upper_bound(PreprocessedEntities.begin(), + PreprocessedEntities.end(), + BeginLoc, + PPEntityComp<&SourceRange::getBegin>(SourceMgr)); + pp_iter insertI = PreprocessedEntities.insert(I, Entity); + return getPPEntityID(insertI - PreprocessedEntities.begin(), + /*isLoaded=*/false); } void PreprocessingRecord::SetExternalSource( @@ -258,7 +359,8 @@ MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) { void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI, SourceRange Range) { - if (!IncludeNestedMacroExpansions && Id.getLocation().isMacroID()) + // We don't record nested macro expansions. + if (Id.getLocation().isMacroID()) return; if (MI->isBuiltinMacro()) @@ -274,17 +376,12 @@ void PreprocessingRecord::MacroDefined(const Token &Id, SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc()); MacroDefinition *Def = new (*this) MacroDefinition(Id.getIdentifierInfo(), R); - addPreprocessedEntity(Def); - MacroDefinitions[MI] = getPPEntityID(PreprocessedEntities.size()-1, - /*isLoaded=*/false); + MacroDefinitions[MI] = addPreprocessedEntity(Def); } void PreprocessingRecord::MacroUndefined(const Token &Id, const MacroInfo *MI) { - llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos - = MacroDefinitions.find(MI); - if (Pos != MacroDefinitions.end()) - MacroDefinitions.erase(Pos); + MacroDefinitions.erase(MI); } void PreprocessingRecord::InclusionDirective( @@ -317,7 +414,6 @@ void PreprocessingRecord::InclusionDirective( default: llvm_unreachable("Unknown include directive kind"); - return; } clang::InclusionDirective *ID @@ -326,6 +422,95 @@ void PreprocessingRecord::InclusionDirective( addPreprocessedEntity(ID); } +bool PreprocessingRecord::rangeIntersectsConditionalDirective( + SourceRange Range) const { + if (Range.isInvalid()) + return false; + + CondDirectiveLocsTy::const_iterator + low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(), + Range.getBegin(), CondDirectiveLoc::Comp(SourceMgr)); + if (low == CondDirectiveLocs.end()) + return false; + + if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), low->getLoc())) + return false; + + CondDirectiveLocsTy::const_iterator + upp = std::upper_bound(low, CondDirectiveLocs.end(), + Range.getEnd(), CondDirectiveLoc::Comp(SourceMgr)); + unsigned uppIdx; + if (upp != CondDirectiveLocs.end()) + uppIdx = upp->getIdx(); + else + uppIdx = 0; + + return low->getIdx() != uppIdx; +} + +unsigned PreprocessingRecord::findCondDirectiveIdx(SourceLocation Loc) const { + if (Loc.isInvalid()) + return 0; + + CondDirectiveLocsTy::const_iterator + low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(), + Loc, CondDirectiveLoc::Comp(SourceMgr)); + if (low == CondDirectiveLocs.end()) + return 0; + return low->getIdx(); +} + +void PreprocessingRecord::addCondDirectiveLoc(CondDirectiveLoc DirLoc) { + // Ignore directives in system headers. + if (SourceMgr.isInSystemHeader(DirLoc.getLoc())) + return; + + assert(CondDirectiveLocs.empty() || + SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(), + DirLoc.getLoc())); + CondDirectiveLocs.push_back(DirLoc); +} + +void PreprocessingRecord::If(SourceLocation Loc, SourceRange ConditionRange) { + if (RecordCondDirectives) { + addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back())); + CondDirectiveStack.push_back(CondDirectiveNextIdx++); + } +} + +void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok) { + if (RecordCondDirectives) { + addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back())); + CondDirectiveStack.push_back(CondDirectiveNextIdx++); + } +} + +void PreprocessingRecord::Ifndef(SourceLocation Loc,const Token &MacroNameTok) { + if (RecordCondDirectives) { + addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back())); + CondDirectiveStack.push_back(CondDirectiveNextIdx++); + } +} + +void PreprocessingRecord::Elif(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) { + if (RecordCondDirectives) + addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back())); +} + +void PreprocessingRecord::Else(SourceLocation Loc, SourceLocation IfLoc) { + if (RecordCondDirectives) + addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back())); +} + +void PreprocessingRecord::Endif(SourceLocation Loc, SourceLocation IfLoc) { + if (RecordCondDirectives) { + addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back())); + assert(!CondDirectiveStack.empty()); + CondDirectiveStack.pop_back(); + } +} + size_t PreprocessingRecord::getTotalMemory() const { return BumpAlloc.getTotalMemory() + llvm::capacity_in_bytes(MacroDefinitions) |