dexonsmith created this revision.
dexonsmith added reviewers: arphaman, JDevlieghere, jansvoboda11, akyrtzi.
Herald added a subscriber: ributzka.
dexonsmith requested review of this revision.

Re-implement the `RemappedFiles` parameter to various `ASTUnit` entry points by 
storing buffers in an `InMemoryFileSystem`. This parameter is commonly used by 
indexing tools to pass in source files that haven't been saved to disk (yet). 
This is the same strategy `ClangTool` switched to in 2015.

The previous implementation added them to 
`PreprocessorOptions::RemappedFileBuffers`, which eventually triggers calls to 
`FileManager::getVirtualFile` and `SourceManager::overrideFileContents`. That's 
one of the blockers for sinking the content cache from `SourceManager` down to 
`FileManager`. The new strategy is also a bit cleaner (the old one predates 
`llvm::vfs::FileSystem`).

Follow-ups will handle the other two uses of `RemappedFileBuffers` in 
`ASTUnit`. One is for the preamble's serialized AST. The other is for 
overriding the main file buffer, which is a bit tricky since we need the 
`ASTWriter` to save the preamble-only version.

WIP: I'm not totally happy with this patch yet, but tests are finally passing 
so I'm posting this for early review. In the meantime I'll continue peeling off 
what I can for prep patches (or there may be changes I can just delete). Among 
other things, I want to add a test (in a prep patch) for the handling of a file 
showing up twice in the same `RemappedFiles` vector, since it was pretty tough 
to discover I needed special logic for that.


https://reviews.llvm.org/D91300

Files:
  clang/include/clang/Frontend/ASTUnit.h
  clang/include/clang/Frontend/PrecompiledPreamble.h
  clang/lib/Frontend/ASTUnit.cpp
  clang/lib/Frontend/PrecompiledPreamble.cpp
  clang/tools/libclang/CIndex.cpp
  clang/tools/libclang/CIndexCodeCompletion.cpp
  clang/unittests/Frontend/PCHPreambleTest.cpp

Index: clang/unittests/Frontend/PCHPreambleTest.cpp
===================================================================
--- clang/unittests/Frontend/PCHPreambleTest.cpp
+++ clang/unittests/Frontend/PCHPreambleTest.cpp
@@ -85,11 +85,6 @@
 
     CI->getTargetOpts().Triple = "i386-unknown-linux-gnu";
 
-    CI->getPreprocessorOpts().RemappedFileBuffers = GetRemappedFiles();
-
-    PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
-    PPOpts.RemappedFilesKeepOriginalName = true;
-
     IntrusiveRefCntPtr<DiagnosticsEngine>
       Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions, new DiagnosticConsumer));
 
@@ -97,7 +92,8 @@
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
         CI, PCHContainerOpts, Diags, FileMgr,
-        /*PrecompilePreambleAfterNParses=*/1);
+        /*PrecompilePreambleAfterNParses=*/1, /*UserFilesAreVolatile=*/false,
+        GetRemappedFiles());
     return AST;
   }
 
@@ -111,9 +107,8 @@
   }
 
 private:
-  std::vector<std::pair<std::string, llvm::MemoryBuffer *>>
-  GetRemappedFiles() const {
-    std::vector<std::pair<std::string, llvm::MemoryBuffer *>> Remapped;
+  std::vector<ASTUnit::RemappedFile> GetRemappedFiles() const {
+    std::vector<ASTUnit::RemappedFile> Remapped;
     for (const auto &RemappedFile : RemappedFiles) {
       std::unique_ptr<MemoryBuffer> buf = MemoryBuffer::getMemBufferCopy(
         RemappedFile.second, RemappedFile.first());
Index: clang/tools/libclang/CIndexCodeCompletion.cpp
===================================================================
--- clang/tools/libclang/CIndexCodeCompletion.cpp
+++ clang/tools/libclang/CIndexCodeCompletion.cpp
@@ -247,7 +247,7 @@
 /// AllocatedCXCodeCompleteResults outlives the CXTranslationUnit, so we can
 /// not rely on the StringPool in the TU.
 struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
-  AllocatedCXCodeCompleteResults(IntrusiveRefCntPtr<FileManager> FileMgr);
+  AllocatedCXCodeCompleteResults();
   ~AllocatedCXCodeCompleteResults();
   
   /// Diagnostics produced while performing code completion.
@@ -354,8 +354,7 @@
 /// Used for debugging purposes only.
 static std::atomic<unsigned> CodeCompletionResultObjects;
 
-AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
-    IntrusiveRefCntPtr<FileManager> FileMgr)
+AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
     : CXCodeCompleteResults(), DiagOpts(new DiagnosticOptions),
       Diag(new DiagnosticsEngine(
           IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts)),
@@ -717,21 +716,19 @@
   ASTUnit::ConcurrencyCheck Check(*AST);
 
   // Perform the remapping of source files.
-  SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
+  std::vector<ASTUnit::RemappedFile> RemappedFiles;
 
-  for (auto &UF : unsaved_files) {
-    std::unique_ptr<llvm::MemoryBuffer> MB =
-        llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename);
-    RemappedFiles.push_back(std::make_pair(UF.Filename, MB.release()));
-  }
+  for (auto &UF : unsaved_files)
+    RemappedFiles.push_back(std::make_pair(
+        UF.Filename,
+        llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename)));
 
   if (EnableLogging) {
     // FIXME: Add logging.
   }
 
   // Parse the resulting source file to find code-completion results.
-  AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults(
-      &AST->getFileManager());
+  AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
   Results->Results = nullptr;
   Results->NumResults = 0;
   
@@ -754,8 +751,8 @@
       *CXXIdx, LibclangInvocationReporter::OperationKind::CompletionOperation,
       TU->ParsingOptions, CArgs, CompletionInvocation, unsaved_files);
   AST->CodeComplete(
-      complete_filename, complete_line, complete_column, RemappedFiles,
-      (options & CXCodeComplete_IncludeMacros),
+      complete_filename, complete_line, complete_column,
+      std::move(RemappedFiles), (options & CXCodeComplete_IncludeMacros),
       (options & CXCodeComplete_IncludeCodePatterns), IncludeBriefComments,
       Capture, CXXIdx->getPCHContainerOperations(), *Results->Diag,
       Results->LangOpts, Results->Diagnostics, Results->TemporaryBuffers);
Index: clang/tools/libclang/CIndex.cpp
===================================================================
--- clang/tools/libclang/CIndex.cpp
+++ clang/tools/libclang/CIndex.cpp
@@ -3564,11 +3564,10 @@
   llvm::CrashRecoveryContextCleanupRegistrar<std::vector<ASTUnit::RemappedFile>>
       RemappedCleanup(RemappedFiles.get());
 
-  for (auto &UF : unsaved_files) {
-    std::unique_ptr<llvm::MemoryBuffer> MB =
-        llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename);
-    RemappedFiles->push_back(std::make_pair(UF.Filename, MB.release()));
-  }
+  for (auto &UF : unsaved_files)
+    RemappedFiles->push_back(std::make_pair(
+        UF.Filename,
+        llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename)));
 
   std::unique_ptr<std::vector<const char *>> Args(
       new std::vector<const char *>());
@@ -3629,8 +3628,9 @@
       Args->data(), Args->data() + Args->size(),
       CXXIdx->getPCHContainerOperations(), Diags,
       CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(),
-      CaptureDiagnostics, *RemappedFiles.get(), PrecompilePreambleAfterNParses,
-      TUKind, CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion,
+      CaptureDiagnostics, std::move(*RemappedFiles),
+      PrecompilePreambleAfterNParses, TUKind, CacheCodeCompletionResults,
+      IncludeBriefCommentsInCodeCompletion,
       /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies, SingleFileParse,
       /*UserFilesAreVolatile=*/true, ForSerialization, RetainExcludedCB,
       CXXIdx->getPCHContainerOperations()->getRawReader().getFormat(),
@@ -4214,14 +4214,13 @@
   llvm::CrashRecoveryContextCleanupRegistrar<std::vector<ASTUnit::RemappedFile>>
       RemappedCleanup(RemappedFiles.get());
 
-  for (auto &UF : unsaved_files) {
-    std::unique_ptr<llvm::MemoryBuffer> MB =
-        llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename);
-    RemappedFiles->push_back(std::make_pair(UF.Filename, MB.release()));
-  }
+  for (auto &UF : unsaved_files)
+    RemappedFiles->push_back(std::make_pair(
+        UF.Filename,
+        llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename)));
 
   if (!CXXUnit->Reparse(CXXIdx->getPCHContainerOperations(),
-                        *RemappedFiles.get()))
+                        std::move(*RemappedFiles)))
     return CXError_Success;
   if (isASTReadError(CXXUnit))
     return CXError_ASTReadError;
Index: clang/lib/Frontend/PrecompiledPreamble.cpp
===================================================================
--- clang/lib/Frontend/PrecompiledPreamble.cpp
+++ clang/lib/Frontend/PrecompiledPreamble.cpp
@@ -388,6 +388,7 @@
   Diagnostics.Reset();
   ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
 
+  // FIXME: should this be deleted? Can we trust that the caller has done this?
   VFS =
       createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
 
@@ -404,6 +405,9 @@
   Clang->getLangOpts().CompilingPCH = true;
 
   // Remap the main source file to the preamble buffer.
+  //
+  // Note: the buffer needs to be overridden in the SourceManager so that the
+  // preamble is serialized the AST file.
   StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
   auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
       MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
@@ -500,11 +504,11 @@
   llvm_unreachable("Unhandled storage kind");
 }
 
-bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation,
-                                   const llvm::MemoryBufferRef &MainFileBuffer,
-                                   PreambleBounds Bounds,
-                                   llvm::vfs::FileSystem &VFS) const {
-
+bool PrecompiledPreamble::CanReuse(
+    const CompilerInvocation &Invocation,
+    const llvm::MemoryBufferRef &MainFileBuffer, PreambleBounds Bounds,
+    llvm::vfs::FileSystem &VFS,
+    llvm::vfs::FileSystem *OverriddenFilesFS) const {
   assert(
       Bounds.Size <= MainFileBuffer.getBufferSize() &&
       "Buffer is too large. Bounds were calculated from a different buffer?");
@@ -564,6 +568,15 @@
 
   // Check whether anything has changed.
   for (const auto &F : FilesInPreamble) {
+    if (OverriddenFilesFS) {
+      std::unique_ptr<llvm::MemoryBuffer> Buffer;
+      if (moveOnNoError(OverriddenFilesFS->getBufferForFile(F.first()),
+                        Buffer)) {
+        if (PreambleFileHash::createForMemoryBuffer(*Buffer) != F.second)
+          return false;
+        continue;
+      }
+    }
     auto OverridenFileBuffer = OverridenFileBuffers.find(F.first());
     if (OverridenFileBuffer != OverridenFileBuffers.end()) {
       // The file's buffer was remapped and the file was not found in VFS.
@@ -804,7 +817,7 @@
 
   auto &PreprocessorOpts = CI.getPreprocessorOpts();
 
-  // Remap main file to point to MainFileBuffer.
+  // Remap main file to point to MainFileBuffer (instead of the preamble).
   auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
   PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
 
Index: clang/lib/Frontend/ASTUnit.cpp
===================================================================
--- clang/lib/Frontend/ASTUnit.cpp
+++ clang/lib/Frontend/ASTUnit.cpp
@@ -775,9 +775,8 @@
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
   AST->Diagnostics = Diags;
-  IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
-      llvm::vfs::getRealFileSystem();
-  AST->FileMgr = new FileManager(FileSystemOpts, VFS);
+  AST->initializeBaseFS(llvm::vfs::getRealFileSystem());
+  AST->FileMgr = new FileManager(FileSystemOpts, AST->FS);
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
   AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
                                      AST->getFileManager(),
@@ -1094,21 +1093,21 @@
 /// \returns True if a failure occurred that causes the ASTUnit not to
 /// contain any translation-unit information, false otherwise.
 bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-                    std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
-                    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
+                    std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer) {
   if (!Invocation)
     return true;
 
-  if (VFS && FileMgr)
-    assert(VFS == &FileMgr->getVirtualFileSystem() &&
-           "VFS passed to Parse and VFS in FileMgr are different");
+  assert((!FileMgr || &FileMgr->getVirtualFileSystem() == FS) &&
+         "ASTUnit has a FileManager without initializing FS");
 
   auto CCInvocation = std::make_shared<CompilerInvocation>(*Invocation);
   if (OverrideMainBuffer) {
     assert(Preamble &&
            "No preamble was built, but OverrideMainBuffer is not null");
-    Preamble->AddImplicitPreamble(*CCInvocation, VFS, OverrideMainBuffer.get());
+    Preamble->AddImplicitPreamble(*CCInvocation, FS, OverrideMainBuffer.get());
     // VFS may have changed...
+    if (FileMgr && &FileMgr->getVirtualFileSystem() != FS)
+      FileMgr->setVirtualFileSystem(FS);
   }
 
   // Create the compiler instance to use for building the AST.
@@ -1131,10 +1130,10 @@
   // Ensure that Clang has a FileManager with the right VFS, which may have
   // changed above in AddImplicitPreamble.  If VFS is nullptr, rely on
   // createFileManager to create one.
-  if (VFS && FileMgr && &FileMgr->getVirtualFileSystem() == VFS)
+  if (FileMgr && &FileMgr->getVirtualFileSystem() == FS)
     Clang->setFileManager(&*FileMgr);
   else
-    FileMgr = Clang->createFileManager(std::move(VFS));
+    FileMgr = Clang->createFileManager(FS);
 
   // Recover resources if we crash before exiting this method.
   llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
@@ -1299,13 +1298,12 @@
 std::unique_ptr<llvm::MemoryBuffer>
 ASTUnit::getMainBufferWithPrecompiledPreamble(
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    CompilerInvocation &PreambleInvocationIn,
-    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, bool AllowRebuild,
+    CompilerInvocation &PreambleInvocationIn, bool AllowRebuild,
     unsigned MaxLines) {
   auto MainFilePath =
       PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile();
   std::unique_ptr<llvm::MemoryBuffer> MainFileBuffer =
-      getBufferForFileHandlingRemapping(PreambleInvocationIn, VFS.get(),
+      getBufferForFileHandlingRemapping(PreambleInvocationIn, FS.get(),
                                         MainFilePath, UserFilesAreVolatile);
   if (!MainFileBuffer)
     return nullptr;
@@ -1317,7 +1315,7 @@
 
   if (Preamble) {
     if (Preamble->CanReuse(PreambleInvocationIn, *MainFileBuffer, Bounds,
-                           *VFS)) {
+                           *FS, &*RemappedFilesFS)) {
       // Okay! We can re-use the precompiled preamble.
 
       // Set the state of the diagnostic object to mimic its state
@@ -1373,8 +1371,8 @@
       PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies = true;
 
     llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build(
-        PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS,
-        PCHContainerOps, /*StoreInMemory=*/false, Callbacks);
+        PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics,
+        FS.get(), PCHContainerOps, /*StoreInMemory=*/false, Callbacks);
 
     PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies =
         PreviousSkipFunctionBodies;
@@ -1492,12 +1490,11 @@
                 bool UserFilesAreVolatile) {
   std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
-  IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
-      createVFSFromCompilerInvocation(*CI, *Diags);
   AST->Diagnostics = Diags;
   AST->FileSystemOpts = CI->getFileSystemOpts();
   AST->Invocation = std::move(CI);
-  AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
+  AST->computeAndInitializeFS(*AST->Invocation, *Diags);
+  AST->FileMgr = new FileManager(AST->FileSystemOpts, AST->FS);
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
   AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr,
                                      UserFilesAreVolatile);
@@ -1653,13 +1650,10 @@
 
 bool ASTUnit::LoadFromCompilerInvocation(
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    unsigned PrecompilePreambleAfterNParses,
-    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
+    unsigned PrecompilePreambleAfterNParses) {
   if (!Invocation)
     return true;
 
-  assert(VFS && "VFS is null");
-
   // We'll manage file buffers ourselves.
   Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
   Invocation->getFrontendOpts().DisableFree = false;
@@ -1670,7 +1664,7 @@
   if (PrecompilePreambleAfterNParses > 0) {
     PreambleRebuildCountdown = PrecompilePreambleAfterNParses;
     OverrideMainBuffer =
-        getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
+        getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
     getDiagnostics().Reset();
     ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
   }
@@ -1682,15 +1676,15 @@
   llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer>
     MemBufferCleanup(OverrideMainBuffer.get());
 
-  return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
+  return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer));
 }
 
 std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
     std::shared_ptr<CompilerInvocation> CI,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
-    unsigned PrecompilePreambleAfterNParses,
-    bool UserFilesAreVolatile) {
+    unsigned PrecompilePreambleAfterNParses, bool UserFilesAreVolatile,
+    Optional<std::vector<RemappedFile>> RemappedFiles) {
   // Create the AST unit.
   std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
   ConfigureDiags(Diags, *AST, CaptureDiagsKind::None);
@@ -1705,6 +1699,12 @@
   AST->FileMgr = FileMgr;
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
 
+  // If we have a file manager, this will update its VFS.
+  AST->computeAndInitializeFS(*AST->Invocation, *Diags);
+
+  // Override any files that need remapping.
+  AST->remapFiles(std::move(RemappedFiles));
+
   // Recover resources if we crash before exiting this method.
   llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
     ASTUnitCleanup(AST.get());
@@ -1713,8 +1713,7 @@
     DiagCleanup(Diags.get());
 
   if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
-                                      PrecompilePreambleAfterNParses,
-                                      &AST->FileMgr->getVirtualFileSystem()))
+                                      PrecompilePreambleAfterNParses))
     return nullptr;
   return AST;
 }
@@ -1724,7 +1723,7 @@
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
     bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
-    ArrayRef<RemappedFile> RemappedFiles,
+    Optional<std::vector<RemappedFile>> RemappedFiles,
     unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
     bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
     bool AllowPCHWithCompilerErrors, SkipFunctionBodiesScope SkipFunctionBodies,
@@ -1747,11 +1746,6 @@
       return nullptr;
   }
 
-  // Override any files that need remapping
-  for (const auto &RemappedFile : RemappedFiles) {
-    CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first,
-                                              RemappedFile.second);
-  }
   PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
   PPOpts.RemappedFilesKeepOriginalName = true;
   PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
@@ -1771,15 +1765,17 @@
   // Create the AST unit.
   std::unique_ptr<ASTUnit> AST;
   AST.reset(new ASTUnit(false));
+
+  // Override any files that need remapping
+  AST->initializeBaseFS(createVFSFromCompilerInvocation(*CI, *Diags));
+  AST->remapFiles(std::move(RemappedFiles));
+
   AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
   AST->StoredDiagnostics.swap(StoredDiagnostics);
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
   AST->Diagnostics = Diags;
   AST->FileSystemOpts = CI->getFileSystemOpts();
-  IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
-      llvm::vfs::getRealFileSystem();
-  VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
-  AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
+  AST->FileMgr = new FileManager(AST->FileSystemOpts, AST->FS);
   AST->ModuleCache = new InMemoryModuleCache;
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
@@ -1801,8 +1797,7 @@
     ASTUnitCleanup(AST.get());
 
   if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
-                                      PrecompilePreambleAfterNParses,
-                                      VFS)) {
+                                      PrecompilePreambleAfterNParses)) {
     // Some error occurred, if caller wants to examine diagnostics, pass it the
     // ASTUnit.
     if (ErrAST) {
@@ -1816,38 +1811,33 @@
 }
 
 bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-                      ArrayRef<RemappedFile> RemappedFiles,
+                      Optional<std::vector<RemappedFile>> RemappedFiles,
                       IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
   if (!Invocation)
     return true;
 
-  if (!VFS) {
-    assert(FileMgr && "FileMgr is null on Reparse call");
-    VFS = &FileMgr->getVirtualFileSystem();
-  }
-
   clearFileLevelDecls();
 
   SimpleTimer ParsingTimer(WantTiming);
   ParsingTimer.setOutput("Reparsing " + getMainFileName());
 
   // Remap files.
+  reinitializeBaseFS(std::move(VFS));
+  remapFiles(std::move(RemappedFiles));
+
+  // Clear out buffers in the Invocation.
   PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
   for (const auto &RB : PPOpts.RemappedFileBuffers)
     delete RB.second;
 
   Invocation->getPreprocessorOpts().clearRemappedFiles();
-  for (const auto &RemappedFile : RemappedFiles) {
-    Invocation->getPreprocessorOpts().addRemappedFile(RemappedFile.first,
-                                                      RemappedFile.second);
-  }
 
   // If we have a preamble file lying around, or if we might try to
   // build a precompiled preamble, do so now.
   std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
   if (Preamble || PreambleRebuildCountdown > 0)
     OverrideMainBuffer =
-        getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
+        getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
 
   // Clear out the diagnostics state.
   FileMgr.reset();
@@ -1858,7 +1848,7 @@
 
   // Parse the sources
   bool Result =
-      Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
+      Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer));
 
   // If we're caching global code-completion results, and the top-level
   // declarations have changed, clear out the code-completion cache.
@@ -2128,7 +2118,7 @@
 
 void ASTUnit::CodeComplete(
     StringRef File, unsigned Line, unsigned Column,
-    ArrayRef<RemappedFile> RemappedFiles, bool IncludeMacros,
+    Optional<std::vector<RemappedFile>> RemappedFiles, bool IncludeMacros,
     bool IncludeCodePatterns, bool IncludeBriefComments,
     CodeCompleteConsumer &Consumer,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
@@ -2211,20 +2201,21 @@
              Language::LLVM_IR &&
          "IR inputs not support here!");
 
+  // Remap files.
+  reinitializeBaseFS();
+  remapFiles(std::move(RemappedFiles));
+
   // Initialize file and source managers up front so that the caller can access
   // them after.
   Clang->createFileManager(FS);
+  Clang->createSourceManager(Clang->getFileManager());
   FileMgr = &Clang->getFileManager();
-  Clang->createSourceManager(*FileMgr);
   SourceMgr = &Clang->getSourceManager();
 
-  // Remap files.
-  PreprocessorOpts.clearRemappedFiles();
+  // Clear out buffers in the invocation and prepare for any overridden buffers
+  // there by requesting they be retained.
   PreprocessorOpts.RetainRemappedFileBuffers = true;
-  for (const auto &RemappedFile : RemappedFiles) {
-    PreprocessorOpts.addRemappedFile(RemappedFile.first, RemappedFile.second);
-    OwnedBuffers.push_back(RemappedFile.second);
-  }
+  PreprocessorOpts.clearRemappedFiles();
 
   // Use the code completion consumer we were given, but adding any cached
   // code-completion results.
@@ -2233,8 +2224,8 @@
   Clang->setCodeCompletionConsumer(AugmentedConsumer);
 
   auto getUniqueID =
-      [&FileMgr](StringRef Filename) -> Optional<llvm::sys::fs::UniqueID> {
-    if (auto Status = FileMgr.getVirtualFileSystem().status(Filename))
+      [this](StringRef Filename) -> Optional<llvm::sys::fs::UniqueID> {
+    if (auto Status = BaseFS->status(Filename))
       return Status->getUniqueID();
     return None;
   };
@@ -2255,7 +2246,7 @@
   std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
   if (Preamble && Line > 1 && hasSameUniqueID(File, OriginalSourceFile)) {
     OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
-        PCHContainerOps, Inv, &FileMgr.getVirtualFileSystem(), false, Line - 1);
+        PCHContainerOps, Inv, false, Line - 1);
   }
 
   // If the main file has been overridden due to the use of a preamble,
@@ -2264,9 +2255,7 @@
     assert(Preamble &&
            "No preamble was built, but OverrideMainBuffer is not null");
 
-    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
-        &FileMgr.getVirtualFileSystem();
-    Preamble->AddImplicitPreamble(Clang->getInvocation(), VFS,
+    Preamble->AddImplicitPreamble(Clang->getInvocation(), FS,
                                   OverrideMainBuffer.get());
     // FIXME: there is no way to update VFS if it was changed by
     // AddImplicitPreamble as FileMgr is accepted as a parameter by this method.
@@ -2288,6 +2277,9 @@
     if (llvm::Error Err = Act->Execute()) {
       consumeError(std::move(Err)); // FIXME this drops errors on the floor.
     }
+
+    transferASTDataFromCompilerInstance(*Clang);
+
     Act->EndSourceFile();
   }
 }
@@ -2711,3 +2703,64 @@
 void ASTUnit::ConcurrencyState::finish() {}
 
 #endif // NDEBUG
+
+void ASTUnit::initializeBaseFS(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) {
+  assert(BaseFS && "Given empty base filesystem?");
+  if (this->BaseFS == BaseFS || this->FS == BaseFS)
+    return;
+
+  llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS(
+      new llvm::vfs::OverlayFileSystem(BaseFS));
+  RemappedFilesFS = new llvm::vfs::InMemoryFileSystem;
+  OverlayFS->pushOverlay(RemappedFilesFS);
+  FS = std::move(OverlayFS);
+  this->BaseFS = std::move(BaseFS);
+  if (FileMgr)
+    FileMgr->setVirtualFileSystem(FS);
+}
+
+void ASTUnit::reinitializeBaseFS(
+    IntrusiveRefCntPtr<llvm::vfs::FileSystem> MaybeFS) {
+  assert(FS && "Resetting without initializing?");
+  assert(BaseFS && "Resetting without initializing?");
+  assert(RemappedFilesFS && "Resetting without initializing?");
+  if (!MaybeFS)
+    MaybeFS = std::move(BaseFS);
+  else
+    BaseFS.reset();
+
+  RemappedFilesFS.reset();
+  FS.reset();
+
+  // Reinitialize.
+  initializeBaseFS(std::move(MaybeFS));
+}
+
+IntrusiveRefCntPtr<llvm::vfs::FileSystem> ASTUnit::computeBaseFS(
+    const CompilerInvocation &CI, DiagnosticsEngine &Diags,
+    IntrusiveRefCntPtr<llvm::vfs::FileSystem> MaybeFS) const {
+  if (MaybeFS)
+    return FS == MaybeFS ? BaseFS : MaybeFS;
+  if (!FileMgr)
+    return FS ? BaseFS : createVFSFromCompilerInvocation(CI, Diags);
+
+  llvm::vfs::FileSystem &FMFS = FileMgr->getVirtualFileSystem();
+  return FS == &FMFS ? BaseFS : &FMFS;
+}
+
+void ASTUnit::computeAndInitializeFS(
+    const CompilerInvocation &CI, DiagnosticsEngine &Diags,
+    IntrusiveRefCntPtr<llvm::vfs::FileSystem> MaybeFS) {
+  initializeBaseFS(computeBaseFS(CI, Diags, std::move(MaybeFS)));
+}
+
+void ASTUnit::remapFiles(Optional<std::vector<RemappedFile>> RemappedFiles) {
+  if (!RemappedFiles || RemappedFiles->empty())
+    return;
+
+  // Add files to the in-memory filesystem in reverse order to ensure the last
+  // mapping "wins". This works because InMemoryFileSystem::addFile ignores
+  // subsequent calls.
+  for (auto &File : llvm::reverse(*RemappedFiles))
+    RemappedFilesFS->addFile(File.first, 0, std::move(File.second));
+}
Index: clang/include/clang/Frontend/PrecompiledPreamble.h
===================================================================
--- clang/include/clang/Frontend/PrecompiledPreamble.h
+++ clang/include/clang/Frontend/PrecompiledPreamble.h
@@ -106,7 +106,8 @@
   /// MainFileBuffer) of the main file.
   bool CanReuse(const CompilerInvocation &Invocation,
                 const llvm::MemoryBufferRef &MainFileBuffer,
-                PreambleBounds Bounds, llvm::vfs::FileSystem &VFS) const;
+                PreambleBounds Bounds, llvm::vfs::FileSystem &VFS,
+                llvm::vfs::FileSystem *OverriddenFilesFS = nullptr) const;
 
   /// Changes options inside \p CI to use PCH from this preamble. Also remaps
   /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble
Index: clang/include/clang/Frontend/ASTUnit.h
===================================================================
--- clang/include/clang/Frontend/ASTUnit.h
+++ clang/include/clang/Frontend/ASTUnit.h
@@ -53,6 +53,7 @@
 namespace vfs {
 
 class FileSystem;
+class InMemoryFileSystem;
 
 } // namespace vfs
 } // namespace llvm
@@ -108,6 +109,16 @@
 private:
   std::shared_ptr<LangOptions>            LangOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine>   Diagnostics;
+
+  /// The top-level filesystem.
+  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
+
+  /// Filesystem for remapped file buffers.
+  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> RemappedFilesFS;
+
+  /// The base filesystem from the CompilerInvocation.
+  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS;
+
   IntrusiveRefCntPtr<FileManager>         FileMgr;
   IntrusiveRefCntPtr<SourceManager>       SourceMgr;
   IntrusiveRefCntPtr<InMemoryModuleCache> ModuleCache;
@@ -368,13 +379,11 @@
   explicit ASTUnit(bool MainFileIsAST);
 
   bool Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-             std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
-             IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS);
+             std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer);
 
   std::unique_ptr<llvm::MemoryBuffer> getMainBufferWithPrecompiledPreamble(
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-      CompilerInvocation &PreambleInvocationIn,
-      IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, bool AllowRebuild = true,
+      CompilerInvocation &PreambleInvocationIn, bool AllowRebuild = true,
       unsigned MaxLines = 0);
   void RealizeTopLevelDeclsFromPreamble();
 
@@ -659,7 +668,8 @@
 
   /// A mapping from a file name to the memory buffer that stores the
   /// remapped contents of that file.
-  using RemappedFile = std::pair<std::string, llvm::MemoryBuffer *>;
+  using RemappedFile =
+      std::pair<std::string, std::unique_ptr<llvm::MemoryBuffer>>;
 
   /// Create a ASTUnit. Gets ownership of the passed CompilerInvocation.
   static std::unique_ptr<ASTUnit>
@@ -706,17 +716,11 @@
   /// of this translation unit should be precompiled, to improve the performance
   /// of reparsing. Set to zero to disable preambles.
   ///
-  /// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses.
-  /// Note that preamble is saved to a temporary directory on a RealFileSystem,
-  /// so in order for it to be loaded correctly, VFS should have access to
-  /// it(i.e., be an overlay over RealFileSystem).
-  ///
   /// \returns \c true if a catastrophic failure occurred (which means that the
   /// \c ASTUnit itself is invalid), or \c false otherwise.
   bool LoadFromCompilerInvocation(
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-      unsigned PrecompilePreambleAfterNParses,
-      IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS);
+      unsigned PrecompilePreambleAfterNParses);
 
 public:
   /// Create an ASTUnit from a source file, via a CompilerInvocation
@@ -779,7 +783,8 @@
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
       unsigned PrecompilePreambleAfterNParses = 0,
-      bool UserFilesAreVolatile = false);
+      bool UserFilesAreVolatile = false,
+      Optional<std::vector<RemappedFile>> RemappedFiles = None);
 
   /// LoadFromCommandLine - Create an ASTUnit from a vector of command line
   /// arguments, which must specify exactly one source file.
@@ -802,12 +807,6 @@
   /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
   /// mainly to allow the caller to see the diagnostics.
   ///
-  /// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses.
-  /// Note that preamble is saved to a temporary directory on a RealFileSystem,
-  /// so in order for it to be loaded correctly, VFS should have access to
-  /// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used
-  /// if \p VFS is nullptr.
-  ///
   // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
   // shouldn't need to specify them at construction time.
   static ASTUnit *LoadFromCommandLine(
@@ -816,7 +815,7 @@
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
       bool OnlyLocalDecls = false,
       CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None,
-      ArrayRef<RemappedFile> RemappedFiles = None,
+      Optional<std::vector<RemappedFile>> RemappedFiles = None,
       unsigned PrecompilePreambleAfterNParses = 0,
       TranslationUnitKind TUKind = TU_Complete,
       bool CacheCodeCompletionResults = false,
@@ -842,7 +841,7 @@
   /// \returns True if a failure occurred that causes the ASTUnit not to
   /// contain any translation-unit information, false otherwise.
   bool Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-               ArrayRef<RemappedFile> RemappedFiles = None,
+               Optional<std::vector<RemappedFile>> RemappedFiles = None,
                IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr);
 
   /// Free data that will be re-generated on the next parse.
@@ -871,9 +870,9 @@
   /// FIXME: The Diag, LangOpts, SourceMgr, FileMgr, StoredDiagnostics, and
   /// OwnedBuffers parameters are all disgusting hacks. They will go away.
   void CodeComplete(StringRef File, unsigned Line, unsigned Column,
-                    ArrayRef<RemappedFile> RemappedFiles, bool IncludeMacros,
-                    bool IncludeCodePatterns, bool IncludeBriefComments,
-                    CodeCompleteConsumer &Consumer,
+                    Optional<std::vector<RemappedFile>> RemappedFiles,
+                    bool IncludeMacros, bool IncludeCodePatterns,
+                    bool IncludeBriefComments, CodeCompleteConsumer &Consumer,
                     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
                     DiagnosticsEngine &Diag, LangOptions &LangOpts,
                     SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics,
@@ -889,6 +888,18 @@
   ///
   /// \returns True if an error occurred, false otherwise.
   bool serialize(raw_ostream &OS);
+
+private:
+  IntrusiveRefCntPtr<llvm::vfs::FileSystem> computeBaseFS(
+      const CompilerInvocation &CI, DiagnosticsEngine &Diags,
+      IntrusiveRefCntPtr<llvm::vfs::FileSystem> MaybeFS = nullptr) const;
+  void initializeBaseFS(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS);
+  void computeAndInitializeFS(
+      const CompilerInvocation &CI, DiagnosticsEngine &Diags,
+      IntrusiveRefCntPtr<llvm::vfs::FileSystem> MaybeFS = nullptr);
+  void reinitializeBaseFS(
+      IntrusiveRefCntPtr<llvm::vfs::FileSystem> MaybeFS = nullptr);
+  void remapFiles(Optional<std::vector<RemappedFile>> RemappedFiles);
 };
 
 } // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D91300: WI... Duncan P. N. Exon Smith via Phabricator via cfe-commits

Reply via email to