//===--- 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/Diagnostic.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>
#include <string>
#include <cstring>
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(Diagnostic &Diag,
bool *Invalid) const {
if (Invalid)
*Invalid = false;
// Lazily create the Buffer for ContentCaches that wrap files.
if (!Buffer && Entry) {
std::string ErrorStr;
struct stat FileInfo;
Buffer = MemoryBuffer::getFile(Entry->getName(), &ErrorStr,
Entry->getSize(), &FileInfo);
// 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()];
Diag.Report(diag::err_cannot_open_file)
<< Entry->getName() << ErrorStr;
if (Invalid)
*Invalid = true;
} else {
// Check that the file's size and modification time is the same as
// in the file entry (which may have come from a stat cache).
if (FileInfo.st_size != Entry->getSize()) {
Diag.Report(diag::err_file_size_changed)
<< Entry->getName() << (unsigned)Entry->getSize()
<< (unsigned)FileInfo.st_size;
if (Invalid)
*Invalid = true;
} else if