summaryrefslogtreecommitdiffstats
path: root/lib/Basic
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Basic')
-rw-r--r--lib/Basic/Diagnostic.cpp6
-rw-r--r--lib/Basic/FileManager.cpp114
-rw-r--r--lib/Basic/SourceManager.cpp196
3 files changed, 171 insertions, 145 deletions
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index fbc7313..8d0d813 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -163,7 +163,7 @@ namespace clang {
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
}
- unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message,
+ unsigned getOrCreateDiagID(Diagnostic::Level L, llvm::StringRef Message,
Diagnostic &Diags) {
DiagDesc D(L, Message);
// Check to see if it already exists.
@@ -210,7 +210,7 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ErrorOccurred = false;
FatalErrorOccurred = false;
NumDiagnostics = 0;
-
+
NumErrors = 0;
CustomDiagInfo = 0;
CurDiagID = ~0U;
@@ -246,7 +246,7 @@ bool Diagnostic::popMappings() {
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
/// and level. If this is the first request for this diagnosic, it is
/// registered and created, otherwise the existing ID is returned.
-unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) {
+unsigned Diagnostic::getCustomDiagID(Level L, llvm::StringRef Message) {
if (CustomDiagInfo == 0)
CustomDiagInfo = new diag::CustomDiagInfo();
return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index ee4309d..434ff39 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -147,6 +147,12 @@ FileManager::FileManager()
FileManager::~FileManager() {
delete &UniqueDirs;
delete &UniqueFiles;
+ for (llvm::SmallVectorImpl<FileEntry *>::iterator
+ V = VirtualFileEntries.begin(),
+ VEnd = VirtualFileEntries.end();
+ V != VEnd;
+ ++V)
+ delete *V;
}
void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) {
@@ -184,6 +190,30 @@ void FileManager::removeStatCache(StatSysCallCache *statCache) {
assert(false && "Stat cache not found for removal");
}
+/// \brief Retrieve the directory that the given file name resides in.
+static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
+ const char *NameStart,
+ const char *NameEnd) {
+ // Figure out what directory it is in. If the string contains a / in it,
+ // strip off everything after it.
+ // FIXME: this logic should be in sys::Path.
+ const char *SlashPos = NameEnd-1;
+ while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
+ --SlashPos;
+ // Ignore duplicate //'s.
+ while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1]))
+ --SlashPos;
+
+ if (SlashPos < NameStart) {
+ // Use the current directory if file has no path component.
+ const char *Name = ".";
+ return FileMgr.getDirectory(Name, Name+1);
+ } else if (SlashPos == NameEnd-1)
+ return 0; // If filename ends with a /, it's a directory.
+ else
+ return FileMgr.getDirectory(NameStart, SlashPos);
+}
+
/// getDirectory - Lookup, cache, and verify the specified directory. This
/// returns null if the directory doesn't exist.
///
@@ -252,33 +282,16 @@ const FileEntry *FileManager::getFile(const char *NameStart,
// By default, initialize it to invalid.
NamedFileEnt.setValue(NON_EXISTENT_FILE);
- // Figure out what directory it is in. If the string contains a / in it,
- // strip off everything after it.
- // FIXME: this logic should be in sys::Path.
- const char *SlashPos = NameEnd-1;
- while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
- --SlashPos;
- // Ignore duplicate //'s.
- while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1]))
- --SlashPos;
-
- const DirectoryEntry *DirInfo;
- if (SlashPos < NameStart) {
- // Use the current directory if file has no path component.
- const char *Name = ".";
- DirInfo = getDirectory(Name, Name+1);
- } else if (SlashPos == NameEnd-1)
- return 0; // If filename ends with a /, it's a directory.
- else
- DirInfo = getDirectory(NameStart, SlashPos);
-
- if (DirInfo == 0) // Directory doesn't exist, file can't exist.
- return 0;
// Get the null-terminated file name as stored as the key of the
// FileEntries map.
const char *InterndFileName = NamedFileEnt.getKeyData();
+ const DirectoryEntry *DirInfo
+ = getDirectoryFromFile(*this, NameStart, NameEnd);
+ if (DirInfo == 0) // Directory doesn't exist, file can't exist.
+ return 0;
+
// FIXME: Use the directory info to prune this, before doing the stat syscall.
// FIXME: This will reduce the # syscalls.
@@ -312,6 +325,44 @@ const FileEntry *FileManager::getFile(const char *NameStart,
return &UFE;
}
+const FileEntry *
+FileManager::getVirtualFile(const llvm::StringRef &Filename,
+ off_t Size, time_t ModificationTime) {
+ const char *NameStart = Filename.begin(), *NameEnd = Filename.end();
+
+ ++NumFileLookups;
+
+ // See if there is already an entry in the map.
+ llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
+ FileEntries.GetOrCreateValue(NameStart, NameEnd);
+
+ // See if there is already an entry in the map.
+ if (NamedFileEnt.getValue())
+ return NamedFileEnt.getValue() == NON_EXISTENT_FILE
+ ? 0 : NamedFileEnt.getValue();
+
+ ++NumFileCacheMisses;
+
+ // By default, initialize it to invalid.
+ NamedFileEnt.setValue(NON_EXISTENT_FILE);
+
+ const DirectoryEntry *DirInfo
+ = getDirectoryFromFile(*this, NameStart, NameEnd);
+ if (DirInfo == 0) // Directory doesn't exist, file can't exist.
+ return 0;
+
+ FileEntry *UFE = new FileEntry();
+ VirtualFileEntries.push_back(UFE);
+ NamedFileEnt.setValue(UFE);
+
+ UFE->Name = NamedFileEnt.getKeyData();
+ UFE->Size = Size;
+ UFE->ModTime = ModificationTime;
+ UFE->Dir = DirInfo;
+ UFE->UID = NextFileUID++;
+ return UFE;
+}
+
void FileManager::PrintStats() const {
llvm::errs() << "\n*** File Manager Stats:\n";
llvm::errs() << UniqueFiles.size() << " files found, "
@@ -327,17 +378,16 @@ void FileManager::PrintStats() const {
int MemorizeStatCalls::stat(const char *path, struct stat *buf) {
int result = StatSysCallCache::stat(path, buf);
- if (result != 0) {
- // Cache failed 'stat' results.
- struct stat empty;
- memset(&empty, 0, sizeof(empty));
- StatCalls[path] = StatResult(result, empty);
- }
- else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) {
- // Cache file 'stat' results and directories with absolutely
- // paths.
+ // Do not cache failed stats, it is easy to construct common inconsistent
+ // situations if we do, and they are not important for PCH performance (which
+ // currently only needs the stats to construct the initial FileManager
+ // entries).
+ if (result != 0)
+ return result;
+
+ // Cache file 'stat' results and directories with absolutely paths.
+ if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute())
StatCalls[path] = StatResult(result, *buf);
- }
return result;
}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index a85bef0..354bf7b 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -41,64 +41,42 @@ unsigned ContentCache::getSizeBytesMapped() const {
/// 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 unless it
-/// needs to be truncated due to a truncateAt() call.
+/// file is not lazily brought in from disk to satisfy this query.
unsigned ContentCache::getSize() const {
return Buffer ? Buffer->getBufferSize() : Entry->getSize();
}
-const llvm::MemoryBuffer *ContentCache::getBuffer() const {
- // Lazily create the Buffer for ContentCaches that wrap files.
- if (!Buffer && Entry) {
- // FIXME: Should we support a way to not have to do this check over
- // and over if we cannot open the file?
- Buffer = MemoryBuffer::getFile(Entry->getName(), 0, Entry->getSize());
- if (isTruncated())
- const_cast<ContentCache *>(this)->truncateAt(TruncateAtLine,
- TruncateAtColumn);
- }
- return Buffer;
+void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
+ assert(B != Buffer);
+
+ delete Buffer;
+ Buffer = B;
}
-void ContentCache::truncateAt(unsigned Line, unsigned Column) {
- TruncateAtLine = Line;
- TruncateAtColumn = Column;
-
- if (!isTruncated() || !Buffer)
- return;
-
- // Find the byte position of the truncation point.
- const char *Position = Buffer->getBufferStart();
- for (unsigned Line = 1; Line < TruncateAtLine; ++Line) {
- for (; *Position; ++Position) {
- if (*Position != '\r' && *Position != '\n')
- continue;
-
- // Eat \r\n or \n\r as a single line.
- if ((Position[1] == '\r' || Position[1] == '\n') &&
- Position[0] != Position[1])
- ++Position;
- ++Position;
- break;
+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()];
}
}
-
- for (unsigned Column = 1; Column < TruncateAtColumn; ++Column, ++Position) {
- if (!*Position)
- break;
-
- if (*Position == '\t')
- Column += 7;
- }
-
- // Truncate the buffer.
- if (Position != Buffer->getBufferEnd()) {
- MemoryBuffer *TruncatedBuffer
- = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position,
- Buffer->getBufferIdentifier());
- delete Buffer;
- Buffer = TruncatedBuffer;
- }
+ return Buffer;
}
unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) {
@@ -332,16 +310,6 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) {
EntryAlign = std::max(8U, EntryAlign);
Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
new (Entry) ContentCache(FileEnt);
-
- if (FileEnt == TruncateFile) {
- // If we had queued up a file truncation request, perform the truncation
- // now.
- Entry->truncateAt(TruncateAtLine, TruncateAtColumn);
- TruncateFile = 0;
- TruncateAtLine = 0;
- TruncateAtColumn = 0;
- }
-
return Entry;
}
@@ -413,8 +381,6 @@ FileID SourceManager::createFileID(const ContentCache *File,
= SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter));
SLocEntryLoaded[PreallocatedID] = true;
FileID FID = FileID::get(PreallocatedID);
- if (File->FirstFID.isInvalid())
- File->FirstFID = FID;
return LastFileIDLookup = FID;
}
@@ -428,8 +394,6 @@ FileID SourceManager::createFileID(const ContentCache *File,
// Set LastFileIDLookup to the newly created file. The next getFileID call is
// almost guaranteed to be from that file.
FileID FID = FileID::get(SLocEntryTable.size()-1);
- if (File->FirstFID.isInvalid())
- File->FirstFID = FID;
return LastFileIDLookup = FID;
}
@@ -461,6 +425,25 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc,
return SourceLocation::getMacroLoc(NextOffset-(TokLength+1));
}
+const llvm::MemoryBuffer *
+SourceManager::getMemoryBufferForFile(const FileEntry *File) {
+ const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
+ if (IR == 0)
+ return 0;
+
+ return IR->getBuffer();
+}
+
+bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
+ const llvm::MemoryBuffer *Buffer) {
+ const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
+ if (IR == 0)
+ return true;
+
+ const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer);
+ return false;
+}
+
/// getBufferData - Return a pointer to the start and end of the source buffer
/// data for the specified FileID.
std::pair<const char*, const char*>
@@ -1007,8 +990,33 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
if (i < Col-1)
return SourceLocation();
- return getLocForStartOfFile(Content->FirstFID).
- getFileLocWithOffset(FilePos + Col - 1);
+ // Find the first file ID that corresponds to the given file.
+ FileID FirstFID;
+
+ // First, check the main file ID, since it is common to look for a
+ // location in the main file.
+ if (!MainFileID.isInvalid()) {
+ const SLocEntry &MainSLoc = getSLocEntry(MainFileID);
+ if (MainSLoc.isFile() && MainSLoc.getFile().getContentCache() == Content)
+ FirstFID = MainFileID;
+ }
+
+ if (FirstFID.isInvalid()) {
+ // The location we're looking for isn't in the main file; look
+ // through all of the source locations.
+ for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
+ const SLocEntry &SLoc = getSLocEntry(I);
+ if (SLoc.isFile() && SLoc.getFile().getContentCache() == Content) {
+ FirstFID = FileID::get(I);
+ break;
+ }
+ }
+ }
+
+ if (FirstFID.isInvalid())
+ return SourceLocation();
+
+ return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1);
}
/// \brief Determines the order of 2 source locations in the translation unit.
@@ -1087,52 +1095,20 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
return LastResForBeforeTUCheck = LOffs.second < I->second;
}
- // No common ancestor.
- // Now we are getting into murky waters. Most probably this is because one
- // location is in the predefines buffer.
-
- const FileEntry *LEntry =
- getSLocEntry(LOffs.first).getFile().getContentCache()->Entry;
- const FileEntry *REntry =
- getSLocEntry(ROffs.first).getFile().getContentCache()->Entry;
-
- // If the locations are in two memory buffers we give up, we can't answer
- // which one should be considered first.
- // FIXME: Should there be a way to "include" memory buffers in the translation
- // unit ?
- assert((LEntry != 0 || REntry != 0) && "Locations in memory buffers.");
- (void) REntry;
-
- // Consider the memory buffer as coming before the file in the translation
- // unit.
- if (LEntry == 0)
- return LastResForBeforeTUCheck = true;
- else {
- assert(REntry == 0 && "Locations in not #included files ?");
- return LastResForBeforeTUCheck = false;
- }
-}
+ // There is no common ancestor, most probably because one location is in the
+ // predefines buffer.
+ //
+ // FIXME: We should rearrange the external interface so this simply never
+ // happens; it can't conceptually happen. Also see PR5662.
-void SourceManager::truncateFileAt(const FileEntry *Entry, unsigned Line,
- unsigned Column) {
- llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator FI
- = FileInfos.find(Entry);
- if (FI != FileInfos.end()) {
- FI->second->truncateAt(Line, Column);
- return;
- }
-
- // We cannot perform the truncation until we actually see the file, so
- // save the truncation information.
- assert(TruncateFile == 0 && "Can't queue up multiple file truncations!");
- TruncateFile = Entry;
- TruncateAtLine = Line;
- TruncateAtColumn = Column;
-}
+ // If exactly one location is a memory buffer, assume it preceeds the other.
+ bool LIsMB = !getSLocEntry(LOffs.first).getFile().getContentCache()->Entry;
+ bool RIsMB = !getSLocEntry(ROffs.first).getFile().getContentCache()->Entry;
+ if (LIsMB != RIsMB)
+ return LastResForBeforeTUCheck = LIsMB;
-/// \brief Determine whether this file was truncated.
-bool SourceManager::isTruncatedFile(FileID FID) const {
- return getSLocEntry(FID).getFile().getContentCache()->isTruncated();
+ // Otherwise, just assume FileIDs were created in order.
+ return LastResForBeforeTUCheck = (LOffs.first < ROffs.first);
}
/// PrintStats - Print statistics to stderr.
OpenPOWER on IntegriCloud