diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-03-05 01:03:53 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-03-05 01:03:53 +0000 |
commit | b1c86492f9a9bef01a4567408c22f961bbd604fe (patch) | |
tree | 379b4af3319f280c1a1f938a6f39a21d97f896ec | |
parent | 15727ddb11405c45372150b5bfb07dbfa4c9960b (diff) |
Currently we can only remap a file by creating a MemoryBuffer and replacing the file contents with it.
Allow remapping a file by specifying another filename whose contents should be loaded if the original
file gets loaded. This allows to override files without having to create & load buffers in advance.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127052 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/SourceManager.h | 36 | ||||
-rw-r--r-- | include/clang/Frontend/ASTUnit.h | 4 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 4 | ||||
-rw-r--r-- | lib/Basic/SourceManager.cpp | 56 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 100 | ||||
-rw-r--r-- | lib/Frontend/CacheTokens.cpp | 2 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 13 | ||||
-rw-r--r-- | tools/libclang/CIndexInclusionStack.cpp | 4 |
8 files changed, 159 insertions, 60 deletions
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index b1443dad09..dea0884042 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -66,10 +66,16 @@ namespace SrcMgr { mutable llvm::PointerIntPair<const llvm::MemoryBuffer *, 2> Buffer; public: - /// Reference to the file entry. This reference does not own - /// the FileEntry object. It is possible for this to be NULL if + /// Reference to the file entry representing this ContentCache. + /// This reference does not own the FileEntry object. + /// It is possible for this to be NULL if /// the ContentCache encapsulates an imaginary text buffer. - const FileEntry *Entry; + const FileEntry *OrigEntry; + + /// \brief References the file which the contents were actually loaded from. + /// Can be different from 'Entry' if we overridden the contents of one file + /// with the contents of another file. + const FileEntry *ContentsEntry; /// SourceLineCache - A bump pointer allocated array of offsets for each /// source line. This is lazily computed. This is owned by the @@ -132,7 +138,12 @@ namespace SrcMgr { } ContentCache(const FileEntry *Ent = 0) - : Buffer(0, false), Entry(Ent), SourceLineCache(0), NumLines(0) {} + : Buffer(0, false), OrigEntry(Ent), ContentsEntry(Ent), + SourceLineCache(0), NumLines(0) {} + + ContentCache(const FileEntry *Ent, const FileEntry *contentEnt) + : Buffer(0, false), OrigEntry(Ent), ContentsEntry(contentEnt), + SourceLineCache(0), NumLines(0) {} ~ContentCache(); @@ -142,7 +153,8 @@ namespace SrcMgr { ContentCache(const ContentCache &RHS) : Buffer(0, false), SourceLineCache(0) { - Entry = RHS.Entry; + OrigEntry = RHS.OrigEntry; + ContentsEntry = RHS.ContentsEntry; assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0 && "Passed ContentCache object cannot own a buffer."); @@ -380,6 +392,9 @@ class SourceManager { /// non-null, FileEntry pointers. llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> FileInfos; + /// \brief Files that have been overriden with the contents from another file. + llvm::DenseMap<const FileEntry *, const FileEntry *> OverriddenFiles; + /// MemBufferInfos - Information about various memory buffers that we have /// read in. All FileEntry* within the stored ContentCache objects are NULL, /// as they do not refer to a file. @@ -527,6 +542,15 @@ public: const llvm::MemoryBuffer *Buffer, bool DoNotFree = false); + /// \brief Override the the given source file with another one. + /// + /// \param SourceFile the source file which will be overriden. + /// + /// \param NewFile the file whose contents will be used as the + /// data instead of the contents of the given source file. + void overrideFileContents(const FileEntry *SourceFile, + const FileEntry *NewFile); + //===--------------------------------------------------------------------===// // FileID manipulation methods. //===--------------------------------------------------------------------===// @@ -547,7 +571,7 @@ public: /// getFileEntryForID - Returns the FileEntry record for the provided FileID. const FileEntry *getFileEntryForID(FileID FID) const { - return getSLocEntry(FID).getFile().getContentCache()->Entry; + return getSLocEntry(FID).getFile().getContentCache()->OrigEntry; } /// getBufferData - Return a StringRef to the source buffer data for the diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 07df7f31cd..e73d7fb687 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -535,9 +535,11 @@ public: /// that might still be used as a precompiled header or preamble. bool isCompleteTranslationUnit() const { return CompleteTranslationUnit; } + typedef llvm::PointerUnion<const char *, const llvm::MemoryBuffer *> + FilenameOrMemBuf; /// \brief A mapping from a file name to the memory buffer that stores the /// remapped contents of that file. - typedef std::pair<std::string, const llvm::MemoryBuffer *> RemappedFile; + typedef std::pair<std::string, FilenameOrMemBuf> RemappedFile; /// \brief Create a ASTUnit from an AST file. /// diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index f4b0ff6aab..baccdde568 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -4156,12 +4156,12 @@ FileID ASTImporter::Import(FileID FromID) { // Map the FileID for to the "to" source manager. FileID ToID; const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); - if (Cache->Entry) { + if (Cache->OrigEntry) { // FIXME: We probably want to use getVirtualFile(), so we don't hit the // disk again // FIXME: We definitely want to re-use the existing MemoryBuffer, rather // than mmap the files several times. - const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName()); + const FileEntry *Entry = ToFileManager.getFile(Cache->OrigEntry->getName()); ToID = ToSM.createFileID(Entry, ToIncludeLoc, FromSLoc.getFile().getFileCharacteristic()); } else { diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index e2783ba6fd..cffdb937bf 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -52,7 +52,7 @@ unsigned ContentCache::getSizeBytesMapped() const { /// file is not lazily brought in from disk to satisfy this query. unsigned ContentCache::getSize() const { return Buffer.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize() - : (unsigned) Entry->getSize(); + : (unsigned) ContentsEntry->getSize(); } void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B, @@ -71,7 +71,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, bool *Invalid) const { // Lazily create the Buffer for ContentCaches that wrap files. If we already // computed it, jsut return what we have. - if (Buffer.getPointer() || Entry == 0) { + if (Buffer.getPointer() || ContentsEntry == 0) { if (Invalid) *Invalid = isBufferInvalid(); @@ -79,7 +79,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, } std::string ErrorStr; - Buffer.setPointer(SM.getFileManager().getBufferForFile(Entry, &ErrorStr)); + Buffer.setPointer(SM.getFileManager().getBufferForFile(ContentsEntry, &ErrorStr)); // 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 @@ -93,18 +93,18 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, // possible. if (!Buffer.getPointer()) { const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n"); - Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(), + Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(), "<invalid>")); char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart()); - for (unsigned i = 0, e = Entry->getSize(); i != e; ++i) + 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, - Entry->getName(), ErrorStr); + ContentsEntry->getName(), ErrorStr); else Diag.Report(Loc, diag::err_cannot_open_file) - << Entry->getName() << ErrorStr; + << ContentsEntry->getName() << ErrorStr; Buffer.setInt(Buffer.getInt() | InvalidFlag); @@ -114,13 +114,13 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, // Check that the file's size is the same as in the file entry (which may // have come from a stat cache). - if (getRawBuffer()->getBufferSize() != (size_t)Entry->getSize()) { + if (getRawBuffer()->getBufferSize() != (size_t)ContentsEntry->getSize()) { if (Diag.isDiagnosticInFlight()) Diag.SetDelayedDiagnostic(diag::err_file_modified, - Entry->getName()); + ContentsEntry->getName()); else Diag.Report(Loc, diag::err_file_modified) - << Entry->getName(); + << ContentsEntry->getName(); Buffer.setInt(Buffer.getInt() | InvalidFlag); if (Invalid) *Invalid = true; @@ -147,7 +147,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, if (BOM) { Diag.Report(Loc, diag::err_unsupported_bom) - << BOM << Entry->getName(); + << BOM << ContentsEntry->getName(); Buffer.setInt(Buffer.getInt() | InvalidFlag); } @@ -395,7 +395,16 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) { unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment; EntryAlign = std::max(8U, EntryAlign); Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign); - new (Entry) ContentCache(FileEnt); + + // If the file contents are overridden with contents from another file, + // pass that file to ContentCache. + llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator + overI = OverriddenFiles.find(FileEnt); + if (overI == OverriddenFiles.end()) + new (Entry) ContentCache(FileEnt); + else + new (Entry) ContentCache(FileEnt, overI->second); + return Entry; } @@ -531,6 +540,17 @@ void SourceManager::overrideFileContents(const FileEntry *SourceFile, const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree); } +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; +} + llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { bool MyInvalid = false; const SLocEntry &SLoc = getSLocEntry(FID.ID); @@ -1071,8 +1091,8 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { // before the MemBuffer as this will avoid unnecessarily paging in the // MemBuffer. const char *Filename; - if (C->Entry) - Filename = C->Entry->getName(); + if (C->OrigEntry) + Filename = C->OrigEntry->getName(); else Filename = C->getBuffer(Diag, *this)->getBufferIdentifier(); bool Invalid = false; @@ -1158,12 +1178,12 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, = MainSLoc.getFile().getContentCache(); if (!MainContentCache) { // Can't do anything - } else if (MainContentCache->Entry == SourceFile) { + } else if (MainContentCache->OrigEntry == SourceFile) { FirstFID = MainFileID; } else { // Fall back: check whether we have the same base name and inode // as the main file. - const FileEntry *MainFile = MainContentCache->Entry; + const FileEntry *MainFile = MainContentCache->OrigEntry; SourceFileName = llvm::sys::path::filename(SourceFile->getName()); if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) { SourceFileInode = getActualFileInode(SourceFile); @@ -1188,7 +1208,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, const SLocEntry &SLoc = getSLocEntry(I); if (SLoc.isFile() && SLoc.getFile().getContentCache() && - SLoc.getFile().getContentCache()->Entry == SourceFile) { + SLoc.getFile().getContentCache()->OrigEntry == SourceFile) { FirstFID = FileID::get(I); break; } @@ -1208,7 +1228,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, if (SLoc.isFile()) { const ContentCache *FileContentCache = SLoc.getFile().getContentCache(); - const FileEntry *Entry =FileContentCache? FileContentCache->Entry : 0; + const FileEntry *Entry =FileContentCache? FileContentCache->OrigEntry : 0; if (Entry && *SourceFileName == llvm::sys::path::filename(Entry->getName())) { if (llvm::Optional<ino_t> EntryInode = getActualFileInode(Entry)) { diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 401ddf87e3..6644206766 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -508,22 +508,50 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); for (unsigned I = 0; I != NumRemappedFiles; ++I) { - // Create the file entry for the file that we're mapping from. - const FileEntry *FromFile - = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, - RemappedFiles[I].second->getBufferSize(), - 0); - if (!FromFile) { - AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file) - << RemappedFiles[I].first; - delete RemappedFiles[I].second; - continue; + FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; + if (const llvm::MemoryBuffer * + memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile + = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, + memBuf->getBufferSize(), + 0); + if (!FromFile) { + AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file) + << RemappedFiles[I].first; + delete memBuf; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + AST->getSourceManager().overrideFileContents(FromFile, memBuf); + + } else { + const char *fname = fileOrBuf.get<const char *>(); + const FileEntry *ToFile = AST->FileMgr->getFile(fname); + if (!ToFile) { + AST->getDiagnostics().Report(diag::err_fe_remap_missing_to_file) + << RemappedFiles[I].first << fname; + continue; + } + + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile + = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, + ToFile->getSize(), + 0); + if (!FromFile) { + AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file) + << RemappedFiles[I].first; + delete memBuf; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + AST->getSourceManager().overrideFileContents(FromFile, ToFile); } - - // Override the contents of the "from" file with the contents of - // the "to" file. - AST->getSourceManager().overrideFileContents(FromFile, - RemappedFiles[I].second); } // Gather Info for preprocessor construction later on. @@ -1391,7 +1419,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( FEnd = SourceMgr.fileinfo_end(); F != FEnd; ++F) { - const FileEntry *File = F->second->Entry; + const FileEntry *File = F->second->OrigEntry; if (!File || F->second->getRawBuffer() == MainFileBuffer) continue; @@ -1612,9 +1640,16 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, } // Override any files that need remapping - for (unsigned I = 0; I != NumRemappedFiles; ++I) - CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, - RemappedFiles[I].second); + for (unsigned I = 0; I != NumRemappedFiles; ++I) { + FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; + if (const llvm::MemoryBuffer * + memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { + CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, memBuf); + } else { + const char *fname = fileOrBuf.get<const char *>(); + CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, fname); + } + } // Override the resources path. CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; @@ -1665,9 +1700,18 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { delete R->second; } Invocation->getPreprocessorOpts().clearRemappedFiles(); - for (unsigned I = 0; I != NumRemappedFiles; ++I) - Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, - RemappedFiles[I].second); + for (unsigned I = 0; I != NumRemappedFiles; ++I) { + FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; + if (const llvm::MemoryBuffer * + memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { + Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, + memBuf); + } else { + const char *fname = fileOrBuf.get<const char *>(); + Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, + fname); + } + } // If we have a preamble file lying around, or if we might try to // build a precompiled preamble, do so now. @@ -2000,9 +2044,15 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, PreprocessorOpts.clearRemappedFiles(); PreprocessorOpts.RetainRemappedFileBuffers = true; for (unsigned I = 0; I != NumRemappedFiles; ++I) { - PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, - RemappedFiles[I].second); - OwnedBuffers.push_back(RemappedFiles[I].second); + FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; + if (const llvm::MemoryBuffer * + memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { + PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, memBuf); + OwnedBuffers.push_back(memBuf); + } else { + const char *fname = fileOrBuf.get<const char *>(); + PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, fname); + } } // Use the code completion consumer we were given, but adding any cached diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index 50182247fc..06a1fd2983 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -473,7 +473,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) { for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(), E = SM.fileinfo_end(); I != E; ++I) { const SrcMgr::ContentCache &C = *I->second; - const FileEntry *FE = C.Entry; + const FileEntry *FE = C.OrigEntry; // FIXME: Handle files with non-absolute paths. if (llvm::sys::path::is_relative(FE->getName())) diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 90849d77fa..78a01e29b7 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1428,7 +1428,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Figure out which record code to use. unsigned Code; if (SLoc->isFile()) { - if (SLoc->getFile().getContentCache()->Entry) + if (SLoc->getFile().getContentCache()->OrigEntry) Code = SM_SLOC_FILE_ENTRY; else Code = SM_SLOC_BUFFER_ENTRY; @@ -1445,16 +1445,19 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Record.push_back(File.hasLineDirectives()); const SrcMgr::ContentCache *Content = File.getContentCache(); - if (Content->Entry) { + if (Content->OrigEntry) { + assert(Content->OrigEntry == Content->ContentsEntry && + "Writing to AST an overriden file is not supported"); + // The source location entry is a file. The blob associated // with this entry is the file name. // Emit size/modification time for this file. - Record.push_back(Content->Entry->getSize()); - Record.push_back(Content->Entry->getModificationTime()); + Record.push_back(Content->OrigEntry->getSize()); + Record.push_back(Content->OrigEntry->getModificationTime()); // Turn the file name into an absolute path, if it isn't already. - const char *Filename = Content->Entry->getName(); + const char *Filename = Content->OrigEntry->getName(); llvm::SmallString<128> FilePath(Filename); llvm::sys::fs::make_absolute(FilePath); Filename = FilePath.c_str(); diff --git a/tools/libclang/CIndexInclusionStack.cpp b/tools/libclang/CIndexInclusionStack.cpp index e0f4d42def..9ea901927f 100644 --- a/tools/libclang/CIndexInclusionStack.cpp +++ b/tools/libclang/CIndexInclusionStack.cpp @@ -47,7 +47,7 @@ void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB, continue; const SrcMgr::FileInfo &FI = SL.getFile(); - if (!FI.getContentCache()->Entry) + if (!FI.getContentCache()->OrigEntry) continue; // Build the inclusion stack. @@ -61,7 +61,7 @@ void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB, // Callback to the client. // FIXME: We should have a function to construct CXFiles. - CB((CXFile) FI.getContentCache()->Entry, + CB((CXFile) FI.getContentCache()->OrigEntry, InclusionStack.data(), InclusionStack.size(), clientData); } } |