//===--- SourceManager.cpp - Track and cache source files -----------------===//
//
// 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 SourceManager interface.
//
//===----------------------------------------------------------------------===//
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/FileManager.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
#include <algorithm>
using namespace clang;
using namespace SrcMgr;
using llvm::MemoryBuffer;
//===----------------------------------------------------------------------===//
// SourceManager Helper Classes
//===----------------------------------------------------------------------===//
ContentCache::~ContentCache() {
delete Buffer;
}
/// getSizeBytesMapped - Returns the number of bytes actually mapped for
/// this ContentCache. This can be 0 if the MemBuffer was not actually
/// instantiated.
unsigned ContentCache::getSizeBytesMapped() const {
return Buffer ? Buffer->getBufferSize() : 0;
}
/// getSize - Returns the size of the content encapsulated by this ContentCache.
/// This can be the size of the source file or the size of an arbitrary
/// scratch buffer. If the ContentCache encapsulates a source file, that
/// file is not lazily brought in from disk to satisfy this query.
unsigned ContentCache::getSize() const {
return Buffer ? (unsigned) Buffer->getBufferSize()
: (unsigned) Entry->getSize();
}
void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
assert(B != Buffer);
delete Buffer;
Buffer = B;
}
const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const {
// Lazily create the Buffer for ContentCaches that wrap files.
if (!Buffer && Entry) {
Buffer = MemoryBuffer::getFile(Entry->getName(), ErrorStr,Entry->getSize());
// If we were unable to open the file, then we are in an inconsistent
// situation where the content cache referenced a file which no longer
// exists. Most likely, we were using a stat cache with an invalid entry but
// the file could also have been removed during processing. Since we can't
// really deal with this situation, just create an empty buffer.
//
// FIXME: This is definitely not ideal, but our immediate clients can't
// currently handle returning a null entry here. Ideally we should detect
// that we are in an inconsistent situation and error out as quickly as
// possible.
if (!Buffer) {
const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
Buffer = MemoryBuffer::getNewMemBuffer(Entry->getSize(), "<invalid>");
char *Ptr = const_cast<char*>(Buffer->getBufferStart());
for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
Ptr[i] = FillStr[i % FillStr.size()];
}
}
return Buffer;
}
unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) {
// Look up the filename in the string table, returning the pre-existing value
// if it exists.
llvm::StringMapEntry<unsigned> &Entry =
FilenameIDs.GetOrCreateValue(Ptr, Ptr+Len, ~0U);
if (Entry.getValue() != ~0U)
return Entry.getValue();
// Otherwise, assign this the next available ID.
Entry.setValue(FilenamesByID.size());
FilenamesByID.push_back(&Entry);
return FilenamesByID.size()-1;
}
/// AddLineNote - Add a line note to the line table that indicates that there
/// is a #line at the specified FID/Offset location which changes the presumed
/// location to LineNo/FilenameID.
void LineTableInfo::AddLineNote(unsigned 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.