123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 |
- //===--- PreprocessingRecord.cpp - Record of Preprocessing ------*- C++ -*-===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements the PreprocessingRecord class, which maintains a record
- // of what occurred during preprocessing, and its helpers.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Lex/PreprocessingRecord.h"
- #include "clang/Lex/MacroInfo.h"
- #include "clang/Lex/Token.h"
- #include "llvm/Support/ErrorHandling.h"
- #include "llvm/Support/Capacity.h"
- using namespace clang;
- ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { }
- InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
- InclusionKind Kind,
- StringRef FileName,
- bool InQuotes, const FileEntry *File,
- SourceRange Range)
- : PreprocessingDirective(InclusionDirectiveKind, Range),
- InQuotes(InQuotes), Kind(Kind), File(File)
- {
- char *Memory
- = (char*)PPRec.Allocate(FileName.size() + 1, llvm::alignOf<char>());
- memcpy(Memory, FileName.data(), FileName.size());
- Memory[FileName.size()] = 0;
- this->FileName = StringRef(Memory, FileName.size());
- }
- PreprocessingRecord::PreprocessingRecord(SourceManager &SM,
- 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
- /// that source range \p Range encompasses.
- std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
- PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) {
- if (Range.isInvalid())
- 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(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(Local.first, Local.second);
-
- unsigned TotalLoaded = LoadedPreprocessedEntities.size();
-
- // Check if range spans loaded entities.
- if (Local.first == Local.second)
- return std::make_pair(int(Loaded.first)-TotalLoaded,
- int(Loaded.second)-TotalLoaded);
-
- // Range spands loaded and local entities.
- return std::make_pair(int(Loaded.first)-TotalLoaded, Local.second);
- }
- std::pair<unsigned, unsigned>
- 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 <SourceLocation (SourceRange::*getRangeLoc)() const>
- struct PPEntityComp {
- const SourceManager &SM;
- explicit PPEntityComp(const SourceManager &SM) : SM(SM) { }
- bool operator()(PreprocessedEntity *L, PreprocessedEntity *R) const {
- SourceLocation LHS = getLoc(L);
- SourceLocation RHS = getLoc(R);
- return SM.isBeforeInTranslationUnit(LHS, RHS);
- }
- bool operator()(PreprocessedEntity *L, SourceLocation RHS) const {
- SourceLocation LHS = getLoc(L);
- return SM.isBeforeInTranslationUnit(LHS, RHS);
- }
- bool operator()(SourceLocation LHS, PreprocessedEntity *R) const {
- SourceLocation RHS = getLoc(R);
- return SM.isBeforeInTranslationUnit(LHS, RHS);
- }
- SourceLocation getLoc(PreprocessedEntity *PPE) const {
- SourceRange Range = PPE->getSourceRange();
- return (Range.*getRangeLoc)();
- }
- };
- }
- unsigned PreprocessingRecord::findBeginLocalPreprocessedEntity(
- SourceLocation Loc) const {
- if (SourceMgr.isLoadedSourceLocation(Loc))
- return 0;
- size_t Count = PreprocessedEntities.size();
- size_t Half;
- std::vector<PreprocessedEntity *>::const_iterator
- First = PreprocessedEntities.begin();
- std::vector<PreprocessedEntity *>::const_iterator I;
- // Do a binary search manually instead of using std::lower_bound because
- // The end locations of entities may be unordered (when a macro expansion
- // is inside another macro argument), but for this case it is not important
- // whether we get the first macro expansion or its containing macro.
- while (Count > 0) {
- Half = Count/2;
- I = First;
- std::advance(I, Half);
- if (SourceMgr.isBeforeInTranslationUnit((*I)->getSourceRange().getEnd(),
- Loc)){
- First = I;
- ++First;
- Count = Count - Half - 1;
- } else
- Count = Half;
- }
- return First - PreprocessedEntities.begin();
- }
- unsigned PreprocessingRecord::findEndLocalPreprocessedEntity(
- SourceLocation Loc) const {
- if (SourceMgr.isLoadedSourceLocation(Loc))
- return 0;
- std::vector<PreprocessedEntity *>::const_iterator
- I = std::upper_bound(PreprocessedEntities.begin(),
- PreprocessedEntities.end(),
- Loc,
- PPEntityComp<&SourceRange::getBegin>(SourceMgr));
- return I - PreprocessedEntities.begin();
- }
- 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 getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false);
- }
- // 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())) {
- 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(
- ExternalPreprocessingRecordSource &Source) {
- assert(!ExternalSource &&
- "Preprocessing record already has an external source");
- ExternalSource = &Source;
- }
- unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) {
- unsigned Result = LoadedPreprocessedEntities.size();
- LoadedPreprocessedEntities.resize(LoadedPreprocessedEntities.size()
- + NumEntities);
- return Result;
- }
- void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
- PPEntityID PPID) {
- MacroDefinitions[Macro] = PPID;
- }
- /// \brief Retrieve the preprocessed entity at the given ID.
- PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){
- if (PPID < 0) {
- assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() &&
- "Out-of bounds loaded preprocessed entity");
- return getLoadedPreprocessedEntity(LoadedPreprocessedEntities.size()+PPID);
- }
- assert(unsigned(PPID) < PreprocessedEntities.size() &&
- "Out-of bounds local preprocessed entity");
- return PreprocessedEntities[PPID];
- }
- /// \brief Retrieve the loaded preprocessed entity at the given index.
- PreprocessedEntity *
- PreprocessingRecord::getLoadedPreprocessedEntity(unsigned Index) {
- assert(Index < LoadedPreprocessedEntities.size() &&
- "Out-of bounds loaded preprocessed entity");
- assert(ExternalSource && "No external source to load from");
- PreprocessedEntity *&Entity = LoadedPreprocessedEntities[Index];
- if (!Entity) {
- Entity = ExternalSource->ReadPreprocessedEntity(Index);
- if (!Entity) // Failed to load.
- Entity = new (*this)
- PreprocessedEntity(PreprocessedEntity::InvalidKind, SourceRange());
- }
- return Entity;
- }
- MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
- llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos
- = MacroDefinitions.find(MI);
- if (Pos == MacroDefinitions.end())
- return 0;
-
- PreprocessedEntity *Entity = getPreprocessedEntity(Pos->second);
- if (Entity->isInvalid())
- return 0;
- return cast<MacroDefinition>(Entity);
- }
- void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI,
- SourceRange Range) {
- // We don't record nested macro expansions.
- if (Id.getLocation().isMacroID())
- return;
- if (MI->isBuiltinMacro())
- addPreprocessedEntity(
- new (*this) MacroExpansion(Id.getIdentifierInfo(),Range));
- else if (MacroDefinition *Def = findMacroDefinition(MI))
- addPreprocessedEntity(
- new (*this) MacroExpansion(Def, Range));
- }
- void PreprocessingRecord::MacroDefined(const Token &Id,
- const MacroInfo *MI) {
- SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
- MacroDefinition *Def
- = new (*this) MacroDefinition(Id.getIdentifierInfo(), R);
- MacroDefinitions[MI] = addPreprocessedEntity(Def);
- }
- void PreprocessingRecord::MacroUndefined(const Token &Id,
- const MacroInfo *MI) {
- MacroDefinitions.erase(MI);
- }
- void PreprocessingRecord::InclusionDirective(
- SourceLocation HashLoc,
- const clang::Token &IncludeTok,
- StringRef FileName,
- bool IsAngled,
- CharSourceRange FilenameRange,
- const FileEntry *File,
- StringRef SearchPath,
- StringRef RelativePath) {
- InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
-
- switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
- case tok::pp_include:
- Kind = InclusionDirective::Include;
- break;
-
- case tok::pp_import:
- Kind = InclusionDirective::Import;
- break;
-
- case tok::pp_include_next:
- Kind = InclusionDirective::IncludeNext;
- break;
-
- case tok::pp___include_macros:
- Kind = InclusionDirective::IncludeMacros;
- break;
-
- default:
- llvm_unreachable("Unknown include directive kind");
- }
- SourceLocation EndLoc;
- if (!IsAngled) {
- EndLoc = FilenameRange.getBegin();
- } else {
- EndLoc = FilenameRange.getEnd();
- if (FilenameRange.isCharRange())
- EndLoc = EndLoc.getLocWithOffset(-1); // the InclusionDirective expects
- // a token range.
- }
- clang::InclusionDirective *ID
- = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
- File, SourceRange(HashLoc, EndLoc));
- 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)
- + llvm::capacity_in_bytes(PreprocessedEntities)
- + llvm::capacity_in_bytes(LoadedPreprocessedEntities);
- }
|