#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Capacity.h"
#include <algorithm>
#include <string>
#include <cstring>
#include <sys/stat.h>
using namespace clang;
using namespace SrcMgr;
using llvm::MemoryBuffer;
ContentCache::~ContentCache() {
if (shouldFreeBuffer())
delete Buffer.getPointer();
}
unsigned ContentCache::getSizeBytesMapped() const {
return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0;
}
llvm::MemoryBuffer::BufferKind ContentCache::getMemoryBufferKind() const {
assert(Buffer.getPointer());
if (!Buffer.getPointer())
return llvm::MemoryBuffer::MemoryBuffer_Malloc;
const llvm::MemoryBuffer *buf = Buffer.getPointer();
return buf->getBufferKind();
}
unsigned ContentCache::getSize() const {
return Buffer.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize()
: (unsigned) ContentsEntry->getSize();
}
void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B,
bool DoNotFree) {
if (B == Buffer.getPointer()) {
assert(0 && "Replacing with the same buffer");
Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
return;
}
if (shouldFreeBuffer())
delete Buffer.getPointer();
Buffer.setPointer(B);
Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
}
const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
const SourceManager &SM,
SourceLocation Loc,
bool *Invalid) const {
if (Buffer.getPointer() || ContentsEntry == 0) {
if (Invalid)
*Invalid = isBufferInvalid();
return Buffer.getPointer();
}
std::string ErrorStr;
Buffer.setPointer(SM.getFileManager().getBufferForFile(ContentsEntry, &ErrorStr));
if (!Buffer.getPointer()) {
const StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(),
"<invalid>"));
char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i)
Ptr[i] = FillStr[i % FillStr.size()];
if (Diag.isDiagnosticInFlight())
Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
ContentsEntry->getName(), ErrorStr);
else
Diag.Report(Loc, diag::err_cannot_open_file)
<< ContentsEntry->getName() << ErrorStr;
Buffer.setInt(Buffer.getInt() | InvalidFlag);
if (Invalid) *Invalid = true;
return Buffer.getPointer();
}
if (getRawBuffer()->getBufferSize() != (size_t)ContentsEntry->getSize()) {
if (Diag.isDiagnosticInFlight())
Diag.SetDelayedDiagnostic(diag::err_file_modified,
ContentsEntry->getName());
else
Diag.Report(Loc, diag::err_file_modified)
<< ContentsEntry->getName();
Buffer.setInt(Buffer.getInt() | InvalidFlag);
if (Invalid) *Invalid = true;
return Buffer.getPointer();
}
StringRef BufStr = Buffer.getPointer()->getBuffer();
const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr)
.StartsWith("\xFE\xFF", "UTF-16 (BE)")
.StartsWith("\xFF\xFE", "UTF-16 (LE)")
.StartsWith("\x00\x00\xFE\xFF", "UTF-32 (BE)")
.StartsWith("\xFF\xFE\x00\x00", "UTF-32 (LE)")
.StartsWith("\x2B\x2F\x76", "UTF-7")
.StartsWith("\xF7\x64\x4C", "UTF-1")
.StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC")
.StartsWith("\x0E\xFE\xFF", "SDSU")
.StartsWith("\xFB\xEE\x28", "BOCU-1")
.StartsWith("\x84\x31\x95\x33", "GB-18030")
.Default(0);
if (InvalidBOM) {
Diag.Report(Loc, diag::err_unsupported_bom)
<< InvalidBOM << ContentsEntry->getName();
Buffer.setInt(Buffer.getInt() | InvalidFlag);
}
if (Invalid)
*Invalid = isBufferInvalid();
return Buffer.getPointer();
}
unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) {
llvm::StringMapEntry<unsigned> &Entry =
FilenameIDs.GetOrCreateValue(Name, ~0U);
if (Entry.getValue() != ~0U)
return Entry.getValue();
Entry.setValue(FilenamesByID.size());
FilenamesByID.push_back(&Entry);
return FilenamesByID.size()-1;
}
void LineTableInfo::AddLineNote(int FID, unsigned Offset,
unsigned LineNo, int FilenameID) {
std::vector<LineEntry> &Entries = LineEntries[FID];
assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
"Adding line entries out of order!");
SrcMgr::CharacteristicKind Kind = SrcMgr::C_User;
unsigned IncludeOffset = 0;
if (!Entries.empty()) {
if (FilenameID == -1)
FilenameID = Entries.back().FilenameID;
Kind = Entries.back().FileKind;
IncludeOffset = Entries.back().IncludeOffset;
}
Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, Kind,
IncludeOffset));
}
void LineTableInfo::AddLineNote(int FID, unsigned Offset,
unsigned LineNo, int FilenameID,
unsigned EntryExit,
SrcMgr::CharacteristicKind FileKind) {
assert(FilenameID != -1 && "Unspecified filename should use other accessor");
std::vector<LineEntry> &Entries = LineEntries[FID];
assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
"Adding line entries out of order!");
unsigned IncludeOffset = 0;
if (EntryExit == 0) { IncludeOffset = Entries.empty() ? 0 : Entries.back().IncludeOffset;
} else if (EntryExit == 1) {
IncludeOffset = Offset-1;
} else if (EntryExit == 2) {
assert(!Entries.empty() && Entries.back().IncludeOffset &&
"PPDirectives should have caught case when popping empty include stack");
IncludeOffset = 0;
if (const LineEntry *PrevEntry =
FindNearestLineEntry(FID, Entries.back().IncludeOffset))
IncludeOffset = PrevEntry->IncludeOffset;
}
Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, FileKind,
IncludeOffset));
}
const LineEntry *LineTableInfo::FindNearestLineEntry(int FID,
unsigned Offset) {
const std::vector<LineEntry> &Entries = LineEntries[FID];
assert(!Entries.empty() && "No #line entries for this FID after all!");
if (Entries.back().FileOffset <= Offset)
return &Entries.back();
std::vector<LineEntry>::const_iterator I =
std::upper_bound(Entries.begin(), Entries.end(), Offset);
if (I == Entries.begin()) return 0;
return &*--I;
}
void LineTableInfo::AddEntry(int FID,
const std::vector<LineEntry> &Entries) {
LineEntries[FID] = Entries;
}
unsigned SourceManager::getLineTableFilenameID(StringRef Name) {
if (LineTable == 0)
LineTable = new LineTableInfo();
return LineTable->getLineTableFilenameID(Name);
}
void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
int FilenameID) {
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
bool Invalid = false;
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
if (!Entry.isFile() || Invalid)
return;
const SrcMgr::FileInfo &FileInfo = Entry.getFile();
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
if (LineTable == 0)
LineTable = new LineTableInfo();
LineTable->AddLineNote(LocInfo.first.ID, LocInfo.second, LineNo, FilenameID);
}
void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
int FilenameID, bool IsFileEntry,
bool IsFileExit, bool IsSystemHeader,
bool IsExternCHeader) {
if (FilenameID == -1) {
assert(!IsFileEntry && !IsFileExit && !IsSystemHeader && !IsExternCHeader &&
"Can't set flags without setting the filename!");
return AddLineNote(Loc, LineNo, FilenameID);
}
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
bool Invalid = false;
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
if (!Entry.isFile() || Invalid)
return;
const SrcMgr::FileInfo &FileInfo = Entry.getFile();
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
if (LineTable == 0)
LineTable = new LineTableInfo();
SrcMgr::CharacteristicKind FileKind;
if (IsExternCHeader)
FileKind = SrcMgr::C_ExternCSystem;
else if (IsSystemHeader)
FileKind = SrcMgr::C_System;
else
FileKind = SrcMgr::C_User;
unsigned EntryExit = 0;
if (IsFileEntry)
EntryExit = 1;
else if (IsFileExit)
EntryExit = 2;
LineTable->AddLineNote(LocInfo.first.ID, LocInfo.second, LineNo, FilenameID,
EntryExit, FileKind);
}
LineTableInfo &SourceManager::getLineTable() {
if (LineTable == 0)
LineTable = new LineTableInfo();
return *LineTable;
}
SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr)
: Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
NumBinaryProbes(0), FakeBufferForRecovery(0),
FakeContentCacheForRecovery(0) {
clearIDTables();
Diag.setSourceManager(this);
}
SourceManager::~SourceManager() {
delete LineTable;
for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) {
if (MemBufferInfos[i]) {
MemBufferInfos[i]->~ContentCache();
ContentCacheAlloc.Deallocate(MemBufferInfos[i]);
}
}
for (llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator
I = FileInfos.begin(), E = FileInfos.end(); I != E; ++I) {
if (I->second) {
I->second->~ContentCache();
ContentCacheAlloc.Deallocate(I->second);
}
}
delete FakeBufferForRecovery;
delete FakeContentCacheForRecovery;
for (llvm::DenseMap<FileID, MacroArgsMap *>::iterator
I = MacroArgsCacheMap.begin(),E = MacroArgsCacheMap.end(); I!=E; ++I) {
delete I->second;
}
}
void SourceManager::clearIDTables() {
MainFileID = FileID();
LocalSLocEntryTable.clear();
LoadedSLocEntryTable.clear();
SLocEntryLoaded.clear();
LastLineNoFileIDQuery = FileID();
LastLineNoContentCache = 0;
LastFileIDLookup = FileID();
if (LineTable)
LineTable->clear();
NextLocalOffset = 0;
CurrentLoadedOffset = MaxLoadedOffset;
createExpansionLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1);
}
const ContentCache *
SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) {
assert(FileEnt && "Didn't specify a file entry to use?");
ContentCache *&Entry = FileInfos[FileEnt];
if (Entry) return Entry;
unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment;
EntryAlign = std::max(8U, EntryAlign);
Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator
overI = OverriddenFiles.find(FileEnt);
if (overI == OverriddenFiles.end())
new (Entry) ContentCache(FileEnt);
else
new (Entry) ContentCache(OverridenFilesKeepOriginalName ? FileEnt
: overI->second,
overI->second);
return Entry;
}
const ContentCache*
SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment;
EntryAlign = std::max(8U, EntryAlign);
ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
new (Entry) ContentCache();
MemBufferInfos.push_back(Entry);
Entry->setBuffer(Buffer);
return Entry;
}
const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index,
bool *Invalid) const {
assert(!SLocEntryLoaded[Index]);
if (ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2))) {
if (Invalid)
*Invalid = true;
if (!SLocEntryLoaded[Index]) {
LoadedSLocEntryTable[Index] = SLocEntry::get(0,
FileInfo::get(SourceLocation(),
getFakeContentCacheForRecovery(),
SrcMgr::C_User));
}
}
return LoadedSLocEntryTable[Index];
}
std::pair<int, unsigned>
SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries,
unsigned TotalSize) {
assert(ExternalSLocEntries && "Don't have an external sloc source");
LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries);
SLocEntryLoaded.resize(LoadedSLocEntryTable.size());
CurrentLoadedOffset -= TotalSize;
assert(CurrentLoadedOffset >= NextLocalOffset && "Out of source locations");
int ID = LoadedSLocEntryTable.size();
return std::make_pair(-ID - 1, CurrentLoadedOffset);
}
const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
if (!FakeBufferForRecovery)
FakeBufferForRecovery
= llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>");
return FakeBufferForRecovery;
}
const SrcMgr::ContentCache *
SourceManager::getFakeContentCacheForRecovery() const {
if (!FakeContentCacheForRecovery) {
FakeContentCacheForRecovery = new ContentCache();
FakeContentCacheForRecovery->replaceBuffer(getFakeBufferForRecovery(),
true);
}
return FakeContentCacheForRecovery;
}
FileID SourceManager::createFileID(const ContentCache *File,
SourceLocation IncludePos,
SrcMgr::CharacteristicKind FileCharacter,
int LoadedID, unsigned LoadedOffset) {
if (LoadedID < 0) {
assert(LoadedID != -1 && "Loading sentinel FileID");
unsigned Index = unsigned(-LoadedID) - 2;
assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
assert(!SLocEntryLoaded[Index] && "FileID already loaded");
LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset,
FileInfo::get(IncludePos, File, FileCharacter));
SLocEntryLoaded[Index] = true;
return FileID::get(LoadedID);
}
LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset,
FileInfo::get(IncludePos, File,
FileCharacter)));
unsigned FileSize = File->getSize();
assert(NextLocalOffset + FileSize + 1 > NextLocalOffset &&
NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset &&
"Ran out of source locations!");
NextLocalOffset += FileSize + 1;
FileID FID = FileID::get(LocalSLocEntryTable.size()-1);
return LastFileIDLookup = FID;
}
SourceLocation
SourceManager::createMacroArgExpansionLoc(SourceLocation SpellingLoc,
SourceLocation ExpansionLoc,
unsigned TokLength) {
ExpansionInfo Info = ExpansionInfo::createForMacroArg(SpellingLoc,
ExpansionLoc);
return createExpansionLocImpl(Info, TokLength);
}
SourceLocation
SourceManager::createExpansionLoc(SourceLocation SpellingLoc,
SourceLocation ExpansionLocStart,
SourceLocation ExpansionLocEnd,
unsigned TokLength,
int LoadedID,
unsigned LoadedOffset) {
ExpansionInfo Info = ExpansionInfo::create(SpellingLoc, ExpansionLocStart,
ExpansionLocEnd);
return createExpansionLocImpl(Info, TokLength, LoadedID, LoadedOffset);
}
SourceLocation
SourceManager::createExpansionLocImpl(const ExpansionInfo &Info,
unsigned TokLength,
int LoadedID,
unsigned LoadedOffset) {
if (LoadedID < 0) {
assert(LoadedID != -1 && "Loading sentinel FileID");
unsigned Index = unsigned(-LoadedID) - 2;
assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
assert(!SLocEntryLoaded[Index] && "FileID already loaded");
LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, Info);
SLocEntryLoaded[Index] = true;
return SourceLocation::getMacroLoc(LoadedOffset);
}
LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, Info));
assert(NextLocalOffset + TokLength + 1 > NextLocalOffset &&
NextLocalOffset + TokLength + 1 <= CurrentLoadedOffset &&
"Ran out of source locations!");
NextLocalOffset += TokLength + 1;
return SourceLocation::getMacroLoc(NextLocalOffset - (TokLength + 1));
}
const llvm::MemoryBuffer *
SourceManager::getMemoryBufferForFile(const FileEntry *File,
bool *Invalid) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
assert(IR && "getOrCreateContentCache() cannot return NULL");
return IR->getBuffer(Diag, *this, SourceLocation(), Invalid);
}
void SourceManager::overrideFileContents(const FileEntry *SourceFile,
const llvm::MemoryBuffer *Buffer,
bool DoNotFree) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
assert(IR && "getOrCreateContentCache() cannot return NULL");
const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree);
const_cast<SrcMgr::ContentCache *>(IR)->BufferOverridden = true;
}
void SourceManager::overrideFileContents(const FileEntry *SourceFile,
const FileEntry *NewFile) {
assert(SourceFile->getSize() == NewFile->getSize() &&
"Different sizes, use the FileManager to create a virtual file with "
"the correct size");
assert(FileInfos.count(SourceFile) == 0 &&
"This function should be called at the initialization stage, before "
"any parsing occurs.");
OverriddenFiles[SourceFile] = NewFile;
}
StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
bool MyInvalid = false;
const SLocEntry &SLoc = getSLocEntry(FID, &MyInvalid);
if (!SLoc.isFile() || MyInvalid) {
if (Invalid)
*Invalid = true;
return "<<<<<INVALID SOURCE LOCATION>>>>>";
}
const llvm::MemoryBuffer *Buf
= SLoc.getFile().getContentCache()->getBuffer(Diag, *this, SourceLocation(),
&MyInvalid);
if (Invalid)
*Invalid = MyInvalid;
if (MyInvalid)
return "<<<<<INVALID SOURCE LOCATION>>>>>";
return Buf->getBuffer();
}
FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
if (!SLocOffset)
return FileID::get(0);
if (SLocOffset < NextLocalOffset)
return getFileIDLocal(SLocOffset);
return getFileIDLoaded(SLocOffset);
}
FileID SourceManager::getFileIDLocal(unsigned SLocOffset) const {
assert(SLocOffset < NextLocalOffset && "Bad function choice");
std::vector<SrcMgr::SLocEntry>::const_iterator I;
if (LastFileIDLookup.ID < 0 ||
LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) {
I = LocalSLocEntryTable.end();
} else {
I = LocalSLocEntryTable.begin()+LastFileIDLookup.ID;
}
unsigned NumProbes = 0;
while (1) {
--I;
if (I->getOffset() <= SLocOffset) {
FileID Res = FileID::get(int(I - LocalSLocEntryTable.begin()));
if (!I->isExpansion())
LastFileIDLookup = Res;
NumLinearScans += NumProbes+1;
return Res;
}
if (++NumProbes == 8)
break;
}
unsigned GreaterIndex = I - LocalSLocEntryTable.begin();
unsigned LessIndex = 0;
NumProbes = 0;
while (1) {
bool Invalid = false;
unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
unsigned MidOffset = getLocalSLocEntry(MiddleIndex, &Invalid).getOffset();
if (Invalid)
return FileID::get(0);
++NumProbes;
if (MidOffset > SLocOffset) {
GreaterIndex = MiddleIndex;
continue;
}
if (isOffsetInFileID(FileID::get(MiddleIndex), SLocOffset)) {
FileID Res = FileID::get(MiddleIndex);
if (!LocalSLocEntryTable[MiddleIndex].isExpansion())
LastFileIDLookup = Res;
NumBinaryProbes += NumProbes;
return Res;
}
LessIndex = MiddleIndex;
}
}
FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const {
if (SLocOffset < CurrentLoadedOffset) {
assert(0 && "Invalid SLocOffset or bad function choice");
return FileID();
}
unsigned I;
int LastID = LastFileIDLookup.ID;
if (LastID >= 0 || getLoadedSLocEntryByID(LastID).getOffset() < SLocOffset)
I = 0;
else
I = (-LastID - 2) + 1;
unsigned NumProbes;
for (NumProbes = 0; NumProbes < 8; ++NumProbes, ++I) {
const SrcMgr::SLocEntry &E = getLoadedSLocEntry(I);
if (E.getOffset() <= SLocOffset) {
FileID Res = FileID::get(-int(I) - 2);
if (!E.isExpansion())
LastFileIDLookup = Res;
NumLinearScans += NumProbes + 1;
return Res;
}
}
unsigned GreaterIndex = I;
unsigned LessIndex = LoadedSLocEntryTable.size();
NumProbes = 0;
while (1) {
++NumProbes;
unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex;
const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex);
++NumProbes;
if (E.getOffset() > SLocOffset) {
GreaterIndex = MiddleIndex;
continue;
}
if (isOffsetInFileID(FileID::get(-int(MiddleIndex) - 2), SLocOffset)) {
FileID Res = FileID::get(-int(MiddleIndex) - 2);
if (!E.isExpansion())
LastFileIDLookup = Res;
NumBinaryProbes += NumProbes;
return Res;
}
LessIndex = MiddleIndex;
}
}
SourceLocation SourceManager::
getExpansionLocSlowCase(SourceLocation Loc) const {
do {
Loc = getSLocEntry(getFileID(Loc)).getExpansion().getExpansionLocStart();
} while (!Loc.isFileID());
return Loc;
}
SourceLocation SourceManager::getSpellingLocSlowCase(SourceLocation Loc) const {
do {
std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc);
Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc();
Loc = Loc.getLocWithOffset(LocInfo.second);
} while (!Loc.isFileID());
return Loc;
}
SourceLocation SourceManager::getFileLocSlowCase(SourceLocation Loc) const {
do {
if (isMacroArgExpansion(Loc))
Loc = getImmediateSpellingLoc(Loc);
else
Loc = getImmediateExpansionRange(Loc).first;
} while (!Loc.isFileID());
return Loc;
}
std::pair<FileID, unsigned>
SourceManager::getDecomposedExpansionLocSlowCase(
const SrcMgr::SLocEntry *E) const {
FileID FID;
SourceLocation Loc;
unsigned Offset;
do {
Loc = E->getExpansion().getExpansionLocStart();
FID = getFileID(Loc);
E = &getSLocEntry(FID);
Offset = Loc.getOffset()-E->getOffset();
} while (!Loc.isFileID());
return std::make_pair(FID, Offset);
}
std::pair<FileID, unsigned>
SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
unsigned Offset) const {
FileID FID;
SourceLocation Loc;
do {
Loc = E->getExpansion().getSpellingLoc();
Loc = Loc.getLocWithOffset(Offset);
FID = getFileID(Loc);
E = &getSLocEntry(FID);
Offset = Loc.getOffset()-E->getOffset();
} while (!Loc.isFileID());
return std::make_pair(FID, Offset);
}
SourceLocation SourceManager::getImmediateSpellingLoc(SourceLocation Loc) const{
if (Loc.isFileID()) return Loc;
std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc);
Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc();
return Loc.getLocWithOffset(LocInfo.second);
}
std::pair<SourceLocation,SourceLocation>
SourceManager::getImmediateExpansionRange(SourceLocation Loc) const {
assert(Loc.isMacroID() && "Not a macro expansion loc!");
const ExpansionInfo &Expansion = getSLocEntry(getFileID(Loc)).getExpansion();
return Expansion.getExpansionLocRange();
}
std::pair<SourceLocation,SourceLocation>
SourceManager::getExpansionRange(SourceLocation Loc) const {
if (Loc.isFileID()) return std::make_pair(Loc, Loc);
std::pair<SourceLocation,SourceLocation> Res =
getImmediateExpansionRange(Loc);
while (!Res.first.isFileID())
Res.first = getImmediateExpansionRange(Res.first).first;
while (!Res.second.isFileID())
Res.second = getImmediateExpansionRange(Res.second).second;
return Res;
}
bool SourceManager::isMacroArgExpansion(SourceLocation Loc) const {
if (!Loc.isMacroID()) return false;
FileID FID = getFileID(Loc);
const SrcMgr::SLocEntry *E = &getSLocEntry(FID);
const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
return Expansion.isMacroArgExpansion();
}
const char *SourceManager::getCharacterData(SourceLocation SL,
bool *Invalid) const {
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(SL);
bool CharDataInvalid = false;
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid);
if (CharDataInvalid || !Entry.isFile()) {
if (Invalid)
*Invalid = true;
return "<<<<INVALID BUFFER>>>>";
}
const llvm::MemoryBuffer *Buffer
= Entry.getFile().getContentCache()
->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
}
unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
bool *Invalid) const {
bool MyInvalid = false;
const llvm::MemoryBuffer *MemBuf = getBuffer(FID, &MyInvalid);
if (Invalid)
*Invalid = MyInvalid;
if (MyInvalid)
return 1;
if (FilePos >= MemBuf->getBufferSize()) {
if (Invalid)
*Invalid = MyInvalid;
return 1;
}
const char *Buf = MemBuf->getBufferStart();
unsigned LineStart = FilePos;
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
--LineStart;
return FilePos-LineStart+1;
}
static bool isInvalid(SourceLocation Loc, bool *Invalid) {
bool MyInvalid = Loc.isInvalid();
if (Invalid)
*Invalid = MyInvalid;
return MyInvalid;
}
unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc,
bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
unsigned SourceManager::getExpansionColumnNumber(SourceLocation Loc,
bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
unsigned SourceManager::getPresumedColumnNumber(SourceLocation Loc,
bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return 0;
return getPresumedLoc(Loc).getColumn();
}
static LLVM_ATTRIBUTE_NOINLINE void
ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
llvm::BumpPtrAllocator &Alloc,
const SourceManager &SM, bool &Invalid);
static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
llvm::BumpPtrAllocator &Alloc,
const SourceManager &SM, bool &Invalid) {
const MemoryBuffer *Buffer = FI->getBuffer(Diag, SM, SourceLocation(),
&Invalid);
if (Invalid)
return;
SmallVector<unsigned, 256> LineOffsets;
LineOffsets.push_back(0);
const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart();
const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd();
unsigned Offs = 0;
while (1) {
const unsigned char *NextBuf = (const unsigned char *)Buf;
while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0')
++NextBuf;
Offs += NextBuf-Buf;
Buf = NextBuf;
if (Buf[0] == '\n' || Buf[0] == '\r') {
if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1])
++Offs, ++Buf;
++Offs, ++Buf;
LineOffsets.push_back(Offs);
} else {
if (Buf == End) break;
++Offs, ++Buf;
}
}
FI->NumLines = LineOffsets.size();
FI->SourceLineCache = Alloc.Allocate<unsigned>(LineOffsets.size());
std::copy(LineOffsets.begin(), LineOffsets.end(), FI->SourceLineCache);
}
unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
bool *Invalid) const {
if (FID.isInvalid()) {
if (Invalid)
*Invalid = true;
return 1;
}
ContentCache *Content;
if (LastLineNoFileIDQuery == FID)
Content = LastLineNoContentCache;
else {
bool MyInvalid = false;
const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
if (MyInvalid || !Entry.isFile()) {
if (Invalid)
*Invalid = true;
return 1;
}
Content = const_cast<ContentCache*>(Entry.getFile().getContentCache());
}
if (Content->SourceLineCache == 0) {
bool MyInvalid = false;
ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
if (Invalid)
*Invalid = MyInvalid;
if (MyInvalid)
return 1;
} else if (Invalid)
*Invalid = false;
unsigned *SourceLineCache = Content->SourceLineCache;
unsigned *SourceLineCacheStart = SourceLineCache;
unsigned *SourceLineCacheEnd = SourceLineCache + Content->NumLines;
unsigned QueriedFilePos = FilePos+1;
if (LastLineNoFileIDQuery == FID) {
if (QueriedFilePos >= LastLineNoFilePos) {
SourceLineCache = SourceLineCache+LastLineNoResult-1;
if (SourceLineCache+5 < SourceLineCacheEnd) {
if (SourceLineCache[5] > QueriedFilePos)
SourceLineCacheEnd = SourceLineCache+5;
else if (SourceLineCache+10 < SourceLineCacheEnd) {
if (SourceLineCache[10] > QueriedFilePos)
SourceLineCacheEnd = SourceLineCache+10;
else if (SourceLineCache+20 < SourceLineCacheEnd) {
if (SourceLineCache[20] > QueriedFilePos)
SourceLineCacheEnd = SourceLineCache+20;
}
}
}
} else {
if (LastLineNoResult < Content->NumLines)
SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1;
}
}
if (0 && SourceLineCacheEnd-SourceLineCache > 20) {
unsigned FileLen = Content->SourceLineCache[Content->NumLines-1];
unsigned ApproxPos = Content->NumLines*QueriedFilePos / FileLen;
unsigned LowerBound = std::max(int(ApproxPos-10), 0);
unsigned UpperBound = std::min(ApproxPos+10, FileLen);
if (SourceLineCache < SourceLineCacheStart+LowerBound &&
SourceLineCacheStart[LowerBound] < QueriedFilePos)
SourceLineCache = SourceLineCacheStart+LowerBound;
if (SourceLineCacheEnd > SourceLineCacheStart+UpperBound &&
SourceLineCacheStart[UpperBound] >= QueriedFilePos)
SourceLineCacheEnd = SourceLineCacheStart+UpperBound;
}
unsigned *Pos
= std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos);
unsigned LineNo = Pos-SourceLineCacheStart;
LastLineNoFileIDQuery = FID;
LastLineNoContentCache = Content;
LastLineNoFilePos = QueriedFilePos;
LastLineNoResult = LineNo;
return LineNo;
}
unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc,
bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
}
unsigned SourceManager::getExpansionLineNumber(SourceLocation Loc,
bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
}
unsigned SourceManager::getPresumedLineNumber(SourceLocation Loc,
bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return 0;
return getPresumedLoc(Loc).getLine();
}
SrcMgr::CharacteristicKind
SourceManager::getFileCharacteristic(SourceLocation Loc) const {
assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!");
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
bool Invalid = false;
const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid);
if (Invalid || !SEntry.isFile())
return C_User;
const SrcMgr::FileInfo &FI = SEntry.getFile();
if (!FI.hasLineDirectives())
return FI.getFileCharacteristic();
assert(LineTable && "Can't have linetable entries without a LineTable!");
const LineEntry *Entry =
LineTable->FindNearestLineEntry(LocInfo.first.ID, LocInfo.second);
if (!Entry)
return FI.getFileCharacteristic();
return Entry->FileKind;
}
const char *SourceManager::getBufferName(SourceLocation Loc,
bool *Invalid) const {
if (isInvalid(Loc, Invalid)) return "<invalid loc>";
return getBuffer(getFileID(Loc), Invalid)->getBufferIdentifier();
}
PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
if (Loc.isInvalid()) return PresumedLoc();
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
bool Invalid = false;
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
if (Invalid || !Entry.isFile())
return PresumedLoc();
const SrcMgr::FileInfo &FI = Entry.getFile();
const SrcMgr::ContentCache *C = FI.getContentCache();
const char *Filename;
if (C->OrigEntry)
Filename = C->OrigEntry->getName();
else
Filename = C->getBuffer(Diag, *this)->getBufferIdentifier();
unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid);
if (Invalid)
return PresumedLoc();
unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second, &Invalid);
if (Invalid)
return PresumedLoc();
SourceLocation IncludeLoc = FI.getIncludeLoc();
if (FI.hasLineDirectives()) {
assert(LineTable && "Can't have linetable entries without a LineTable!");
if (const LineEntry *Entry =
LineTable->FindNearestLineEntry(LocInfo.first.ID, LocInfo.second)) {
if (Entry->FilenameID != -1)
Filename = LineTable->getFilename(Entry->FilenameID);
unsigned MarkerLineNo = getLineNumber(LocInfo.first, Entry->FileOffset);
LineNo = Entry->LineNo + (LineNo-MarkerLineNo-1);
if (Entry->IncludeOffset) {
IncludeLoc = getLocForStartOfFile(LocInfo.first);
IncludeLoc = IncludeLoc.getLocWithOffset(Entry->IncludeOffset);
}
}
}
return PresumedLoc(Filename, LineNo, ColNo, IncludeLoc);
}
unsigned SourceManager::getFileIDSize(FileID FID) const {
bool Invalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
if (Invalid)
return 0;
int ID = FID.ID;
unsigned NextOffset;
if ((ID > 0 && unsigned(ID+1) == local_sloc_entry_size()))
NextOffset = getNextLocalOffset();
else if (ID+1 == -1)
NextOffset = MaxLoadedOffset;
else
NextOffset = getSLocEntry(FileID::get(ID+1)).getOffset();
return NextOffset - Entry.getOffset() - 1;
}
static llvm::Optional<ino_t> getActualFileInode(const FileEntry *File) {
if (!File)
return llvm::Optional<ino_t>();
struct stat StatBuf;
if (::stat(File->getName(), &StatBuf))
return llvm::Optional<ino_t>();
return StatBuf.st_ino;
}
SourceLocation SourceManager::translateFileLineCol(const FileEntry *SourceFile,
unsigned Line,
unsigned Col) const {
assert(SourceFile && "Null source file!");
assert(Line && Col && "Line and column should start from 1!");
FileID FirstFID = translateFile(SourceFile);
return translateLineCol(FirstFID, Line, Col);
}
FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
assert(SourceFile && "Null source file!");
FileID FirstFID;
llvm::Optional<ino_t> SourceFileInode;
llvm::Optional<StringRef> SourceFileName;
if (!MainFileID.isInvalid()) {
bool Invalid = false;
const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
if (Invalid)
return FileID();
if (MainSLoc.isFile()) {
const ContentCache *MainContentCache
= MainSLoc.getFile().getContentCache();
if (!MainContentCache) {
} else if (MainContentCache->OrigEntry == SourceFile) {
FirstFID = MainFileID;
} else {
const FileEntry *MainFile = MainContentCache->OrigEntry;
SourceFileName = llvm::sys::path::filename(SourceFile->getName());
if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) {
SourceFileInode = getActualFileInode(SourceFile);
if (SourceFileInode) {
if (llvm::Optional<ino_t> MainFileInode
= getActualFileInode(MainFile)) {
if (*SourceFileInode == *MainFileInode) {
FirstFID = MainFileID;
SourceFile = MainFile;
}
}
}
}
}
}
}
if (FirstFID.isInvalid()) {
for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) {
bool Invalid = false;
const SLocEntry &SLoc = getLocalSLocEntry(I, &Invalid);
if (Invalid)
return FileID();
if (SLoc.isFile() &&
SLoc.getFile().getContentCache() &&
SLoc.getFile().getContentCache()->OrigEntry == SourceFile) {
FirstFID = FileID::get(I);
break;
}
}
if (FirstFID.isInvalid()) {
for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) {
const SLocEntry &SLoc = getLoadedSLocEntry(I);
if (SLoc.isFile() &&
SLoc.getFile().getContentCache() &&
SLoc.getFile().getContentCache()->OrigEntry == SourceFile) {
FirstFID = FileID::get(-int(I) - 2);
break;
}
}
}
}
if (FirstFID.isInvalid() &&
(SourceFileName ||
(SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) &&
(SourceFileInode ||
(SourceFileInode = getActualFileInode(SourceFile)))) {
bool Invalid = false;
for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) {
FileID IFileID;
IFileID.ID = I;
const SLocEntry &SLoc = getSLocEntry(IFileID, &Invalid);
if (Invalid)
return FileID();
if (SLoc.isFile()) {
const ContentCache *FileContentCache
= SLoc.getFile().getContentCache();
const FileEntry *Entry =FileContentCache? FileContentCache->OrigEntry : 0;
if (Entry &&
*SourceFileName == llvm::sys::path::filename(Entry->getName())) {
if (llvm::Optional<ino_t> EntryInode = getActualFileInode(Entry)) {
if (*SourceFileInode == *EntryInode) {
FirstFID = FileID::get(I);
SourceFile = Entry;
break;
}
}
}
}
}
}
return FirstFID;
}
SourceLocation SourceManager::translateLineCol(FileID FID,
unsigned Line,
unsigned Col) const {
if (FID.isInvalid())
return SourceLocation();
bool Invalid = false;
const SLocEntry &Entry = getSLocEntry(FID, &Invalid);
if (Invalid)
return SourceLocation();
if (!Entry.isFile())
return SourceLocation();
SourceLocation FileLoc = SourceLocation::getFileLoc(Entry.getOffset());
if (Line == 1 && Col == 1)
return FileLoc;
ContentCache *Content
= const_cast<ContentCache *>(Entry.getFile().getContentCache());
if (!Content)
return SourceLocation();
if (Content->SourceLineCache == 0) {
bool MyInvalid = false;
ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
if (MyInvalid)
return SourceLocation();
}
if (Line > Content->NumLines) {
unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize();
if (Size > 0)
--Size;
return FileLoc.getLocWithOffset(Size);
}
const llvm::MemoryBuffer *Buffer = Content->getBuffer(Diag, *this);
unsigned FilePos = Content->SourceLineCache[Line - 1];
const char *Buf = Buffer->getBufferStart() + FilePos;
unsigned BufLength = Buffer->getBufferSize() - FilePos;
if (BufLength == 0)
return FileLoc.getLocWithOffset(FilePos);
unsigned i = 0;
while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r')
++i;
if (i < Col-1)
return FileLoc.getLocWithOffset(FilePos + i);
return FileLoc.getLocWithOffset(FilePos + Col - 1);
}
void SourceManager::computeMacroArgsCache(MacroArgsMap *&CachePtr,
FileID FID) const {
assert(!FID.isInvalid());
assert(!CachePtr);
CachePtr = new MacroArgsMap();
MacroArgsMap &MacroArgsCache = *CachePtr;
MacroArgsCache.insert(std::make_pair(0, SourceLocation()));
int ID = FID.ID;
while (1) {
++ID;
if (ID > 0) {
if (unsigned(ID) >= local_sloc_entry_size())
return;
} else if (ID == -1) {
return;
}
const SrcMgr::SLocEntry &Entry = getSLocEntryByID(ID);
if (Entry.isFile()) {
SourceLocation IncludeLoc = Entry.getFile().getIncludeLoc();
if (IncludeLoc.isInvalid())
continue;
if (!isInFileID(IncludeLoc, FID))
return;
if (Entry.getFile().NumCreatedFIDs)
ID += Entry.getFile().NumCreatedFIDs - 1;
continue;
}
const ExpansionInfo &ExpInfo = Entry.getExpansion();
if (ExpInfo.getExpansionLocStart().isFileID()) {
if (!isInFileID(ExpInfo.getExpansionLocStart(), FID))
return; }
if (!ExpInfo.isMacroArgExpansion())
continue;
SourceLocation SpellLoc = ExpInfo.getSpellingLoc();
while (!SpellLoc.isFileID()) {
std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(SpellLoc);
const ExpansionInfo &Info = getSLocEntry(LocInfo.first).getExpansion();
if (!Info.isMacroArgExpansion())
break;
SpellLoc = Info.getSpellingLoc().getLocWithOffset(LocInfo.second);
}
if (!SpellLoc.isFileID())
continue;
unsigned BeginOffs;
if (!isInFileID(SpellLoc, FID, &BeginOffs))
continue;
unsigned EndOffs = BeginOffs + getFileIDSize(FileID::get(ID));
MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs);
--I;
SourceLocation EndOffsMappedLoc = I->second;
MacroArgsCache[BeginOffs] = SourceLocation::getMacroLoc(Entry.getOffset());
MacroArgsCache[EndOffs] = EndOffsMappedLoc;
}
}
SourceLocation
SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const {
if (Loc.isInvalid() || !Loc.isFileID())
return Loc;
FileID FID;
unsigned Offset;
llvm::tie(FID, Offset) = getDecomposedLoc(Loc);
if (FID.isInvalid())
return Loc;
MacroArgsMap *&MacroArgsCache = MacroArgsCacheMap[FID];
if (!MacroArgsCache)
computeMacroArgsCache(MacroArgsCache, FID);
assert(!MacroArgsCache->empty());
MacroArgsMap::iterator I = MacroArgsCache->upper_bound(Offset);
--I;
unsigned MacroArgBeginOffs = I->first;
SourceLocation MacroArgExpandedLoc = I->second;
if (MacroArgExpandedLoc.isValid())
return MacroArgExpandedLoc.getLocWithOffset(Offset - MacroArgBeginOffs);
return Loc;
}
static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc,
const SourceManager &SM) {
SourceLocation UpperLoc;
const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(Loc.first);
if (Entry.isExpansion())
UpperLoc = Entry.getExpansion().getExpansionLocStart();
else
UpperLoc = Entry.getFile().getIncludeLoc();
if (UpperLoc.isInvalid())
return true;
Loc = SM.getDecomposedLoc(UpperLoc);
return false;
}
bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
SourceLocation RHS) const {
assert(LHS.isValid() && RHS.isValid() && "Passed invalid source location!");
if (LHS == RHS)
return false;
std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
if (LOffs.first == ROffs.first)
return LOffs.second < ROffs.second;
if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first))
return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first,
LOffs.first.ID < ROffs.first.ID);
typedef llvm::DenseMap<FileID, unsigned> LocSet;
LocSet LChain;
do {
LChain.insert(LOffs);
} while (LOffs.first != ROffs.first && !MoveUpIncludeHierarchy(LOffs, *this));
LocSet::iterator I;
while((I = LChain.find(ROffs.first)) == LChain.end()) {
if (MoveUpIncludeHierarchy(ROffs, *this))
break; }
if (I != LChain.end())
LOffs = *I;
if (LOffs.first == ROffs.first) {
IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second);
return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
}
IsBeforeInTUCache.clear();
bool LIsBuiltins = strcmp("<built-in>",
getBuffer(LOffs.first)->getBufferIdentifier()) == 0;
bool RIsBuiltins = strcmp("<built-in>",
getBuffer(ROffs.first)->getBufferIdentifier()) == 0;
if (LIsBuiltins != RIsBuiltins)
return LIsBuiltins;
assert(LIsBuiltins && RIsBuiltins &&
"Non-built-in locations must be rooted in the main file");
return LOffs.first < ROffs.first;
}
void SourceManager::PrintStats() const {
llvm::errs() << "\n*** Source Manager Stats:\n";
llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
<< " mem buffers mapped.\n";
llvm::errs() << LocalSLocEntryTable.size() << " local SLocEntry's allocated ("
<< llvm::capacity_in_bytes(LocalSLocEntryTable)
<< " bytes of capacity), "
<< NextLocalOffset << "B of Sloc address space used.\n";
llvm::errs() << LoadedSLocEntryTable.size()
<< " loaded SLocEntries allocated, "
<< MaxLoadedOffset - CurrentLoadedOffset
<< "B of Sloc address space used.\n";
unsigned NumLineNumsComputed = 0;
unsigned NumFileBytesMapped = 0;
for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){
NumLineNumsComputed += I->second->SourceLineCache != 0;
NumFileBytesMapped += I->second->getSizeBytesMapped();
}
unsigned NumMacroArgsComputed = MacroArgsCacheMap.size();
llvm::errs() << NumFileBytesMapped << " bytes of files mapped, "
<< NumLineNumsComputed << " files with line #'s computed, "
<< NumMacroArgsComputed << " files with macro args computed.\n";
llvm::errs() << "FileID scans: " << NumLinearScans << " linear, "
<< NumBinaryProbes << " binary.\n";
}
ExternalSLocEntrySource::~ExternalSLocEntrySource() { }
SourceManager::MemoryBufferSizes SourceManager::getMemoryBufferSizes() const {
size_t malloc_bytes = 0;
size_t mmap_bytes = 0;
for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i)
if (size_t sized_mapped = MemBufferInfos[i]->getSizeBytesMapped())
switch (MemBufferInfos[i]->getMemoryBufferKind()) {
case llvm::MemoryBuffer::MemoryBuffer_MMap:
mmap_bytes += sized_mapped;
break;
case llvm::MemoryBuffer::MemoryBuffer_Malloc:
malloc_bytes += sized_mapped;
break;
}
return MemoryBufferSizes(malloc_bytes, mmap_bytes);
}
size_t SourceManager::getDataStructureSizes() const {
return llvm::capacity_in_bytes(MemBufferInfos)
+ llvm::capacity_in_bytes(LocalSLocEntryTable)
+ llvm::capacity_in_bytes(LoadedSLocEntryTable)
+ llvm::capacity_in_bytes(SLocEntryLoaded)
+ llvm::capacity_in_bytes(FileInfos)
+ llvm::capacity_in_bytes(OverriddenFiles);
}