llvm-project/clang/lib/Lex/PreprocessingRecord.cpp

408 lines
14 KiB
C++

//===--- 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 IncludeNestedMacroExpansions)
: SourceMgr(SM), IncludeNestedMacroExpansions(IncludeNestedMacroExpansions),
ExternalSource(0)
{
}
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
/// that source range \arg R 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();
}
void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
assert(Entity);
SourceLocation BeginLoc = Entity->getSourceRange().getBegin();
// 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;
}
// 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;
--I;
if (!SourceMgr.isBeforeInTranslationUnit(BeginLoc,
(*I)->getSourceRange().getBegin())) {
PreprocessedEntities.insert(RI, Entity);
return;
}
}
}
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) {
if (!IncludeNestedMacroExpansions && 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);
addPreprocessedEntity(Def);
MacroDefinitions[MI] = getPPEntityID(PreprocessedEntities.size()-1,
/*isLoaded=*/false);
}
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);
}
void PreprocessingRecord::InclusionDirective(
SourceLocation HashLoc,
const clang::Token &IncludeTok,
StringRef FileName,
bool IsAngled,
const FileEntry *File,
clang::SourceLocation EndLoc,
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");
return;
}
clang::InclusionDirective *ID
= new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
File, SourceRange(HashLoc, EndLoc));
addPreprocessedEntity(ID);
}
size_t PreprocessingRecord::getTotalMemory() const {
return BumpAlloc.getTotalMemory()
+ llvm::capacity_in_bytes(MacroDefinitions)
+ llvm::capacity_in_bytes(PreprocessedEntities)
+ llvm::capacity_in_bytes(LoadedPreprocessedEntities);
}