From 426bfa0c4555cc2b415f1a607252c373a69f3197 Mon Sep 17 00:00:00 2001
From: Ben Langmuir <blangmuir@apple.com>
Date: Tue, 15 Apr 2014 18:16:25 +0000
Subject: [PATCH] Honour -ivfsoverlay in ASTUnit to match clang

This allows code indexing, etc. to use the VFS in the same way as the
compiler.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206309 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Frontend/ASTUnit.h            |  2 +-
 include/clang/Frontend/CompilerInvocation.h |  8 +++++
 lib/Frontend/ASTUnit.cpp                    | 35 ++++++++++++++++-----
 lib/Frontend/CompilerInvocation.cpp         | 29 ++++++++++++++++-
 lib/Frontend/FrontendAction.cpp             | 31 +++++-------------
 test/Index/Inputs/base_module_needs_vfs.h   |  1 +
 test/Index/Inputs/module.map                |  6 ++++
 test/Index/Inputs/module_needs_vfs.h        |  4 +++
 test/Index/Inputs/vfsoverlay.yaml           | 18 +++++++++++
 test/Index/index-module-with-vfs.m          | 26 +++++++++++++++
 tools/libclang/CIndexCodeCompletion.cpp     | 31 +++++++-----------
 tools/libclang/Indexing.cpp                 |  5 +++
 12 files changed, 143 insertions(+), 53 deletions(-)
 create mode 100644 test/Index/Inputs/base_module_needs_vfs.h
 create mode 100644 test/Index/Inputs/module.map
 create mode 100644 test/Index/Inputs/module_needs_vfs.h
 create mode 100644 test/Index/Inputs/vfsoverlay.yaml
 create mode 100644 test/Index/index-module-with-vfs.m

diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 3a26df3ef32..f8cb14e29d1 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -499,7 +499,7 @@ public:
   bool hasSema() const { return (bool)TheSema; }
   Sema &getSema() const { 
     assert(TheSema && "ASTUnit does not have a Sema object!");
-    return *TheSema; 
+    return *TheSema;
   }
   
   const FileManager &getFileManager() const { return *FileMgr; }
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index f64773c2c4b..7258dbeb2ab 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -204,6 +204,14 @@ public:
   /// @}
 };
 
+namespace vfs {
+  class FileSystem;
+}
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+                                DiagnosticsEngine &Diags);
+
 } // end namespace clang
 
 #endif
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index c4f7596e003..5035dac53cf 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -692,7 +692,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
   AST->Diagnostics = Diags;
-  AST->FileMgr = new FileManager(FileSystemOpts);
+  IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem();
+  AST->FileMgr = new FileManager(FileSystemOpts, VFS);
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
   AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
                                      AST->getFileManager(),
@@ -1093,10 +1094,9 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
          "IR inputs not support here!");
 
   // Configure the various subsystems.
-  // FIXME: Should we retain the previous file manager?
   LangOpts = &Clang->getLangOpts();
   FileSystemOpts = Clang->getFileSystemOpts();
-  FileMgr = new FileManager(FileSystemOpts);
+  // Re-use the existing FileManager
   SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
                                 UserFilesAreVolatile);
   TheSema.reset();
@@ -1598,9 +1598,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
   TopLevelDecls.clear();
   TopLevelDeclsInPreamble.clear();
   PreambleDiagnostics.clear();
-  
+
+  IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+      createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics());
+  if (!VFS)
+    return nullptr;
+
   // Create a file manager object to provide access to and cache the filesystem.
-  Clang->setFileManager(new FileManager(Clang->getFileSystemOpts()));
+  Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
   
   // Create the source manager.
   Clang->setSourceManager(new SourceManager(getDiagnostics(),
@@ -1758,7 +1763,11 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI,
   AST->Diagnostics = Diags;
   AST->Invocation = CI;
   AST->FileSystemOpts = CI->getFileSystemOpts();
-  AST->FileMgr = new FileManager(AST->FileSystemOpts);
+  IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+      createVFSFromCompilerInvocation(*CI, *Diags);
+  if (!VFS)
+    return nullptr;
+  AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
   AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr,
                                      UserFilesAreVolatile);
@@ -1781,6 +1790,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
     // Create the AST unit.
     OwnAST.reset(create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile));
     AST = OwnAST.get();
+    if (!AST)
+      return nullptr;
   }
   
   if (!ResourceFilesPath.empty()) {
@@ -1950,7 +1961,11 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
     = IncludeBriefCommentsInCodeCompletion;
   AST->Invocation = CI;
   AST->FileSystemOpts = CI->getFileSystemOpts();
-  AST->FileMgr = new FileManager(AST->FileSystemOpts);
+  IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+      createVFSFromCompilerInvocation(*CI, *Diags);
+  if (!VFS)
+    return nullptr;
+  AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
   
   // Recover resources if we crash before exiting this method.
@@ -2017,7 +2032,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
   AST->Diagnostics = Diags;
   Diags = 0; // Zero out now to ease cleanup during crash recovery.
   AST->FileSystemOpts = CI->getFileSystemOpts();
-  AST->FileMgr = new FileManager(AST->FileSystemOpts);
+  IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+      createVFSFromCompilerInvocation(*CI, *Diags);
+  if (!VFS)
+    return nullptr;
+  AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
   AST->TUKind = TUKind;
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b22ea9a07f6..6177a96fa7b 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -8,12 +8,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Frontend/CompilerInvocation.h"
-#include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/Version.h"
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/Util.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/LangStandard.h"
 #include "clang/Frontend/Utils.h"
 #include "clang/Lex/HeaderSearchOptions.h"
@@ -1907,4 +1907,31 @@ void BuryPointer(const void *Ptr) {
     return;
   GraveYard[Idx] = Ptr;
 }
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+                                DiagnosticsEngine &Diags) {
+  if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
+    return vfs::getRealFileSystem();
+
+  IntrusiveRefCntPtr<vfs::OverlayFileSystem>
+    Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
+  // earlier vfs files are on the bottom
+  for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) {
+    std::unique_ptr<llvm::MemoryBuffer> Buffer;
+    if (llvm::errc::success != llvm::MemoryBuffer::getFile(File, Buffer)) {
+      Diags.Report(diag::err_missing_vfs_overlay_file) << File;
+      return IntrusiveRefCntPtr<vfs::FileSystem>();
+    }
+
+    IntrusiveRefCntPtr<vfs::FileSystem> FS =
+        vfs::getVFSFromYAML(Buffer.release(), /*DiagHandler*/0);
+    if (!FS.getPtr()) {
+      Diags.Report(diag::err_invalid_vfs_overlay) << File;
+      return IntrusiveRefCntPtr<vfs::FileSystem>();
+    }
+    Overlay->pushOverlay(FS);
+  }
+  return Overlay;
 }
+} // end namespace clang
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index dc4dd89371a..dfe3d85ba73 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -211,30 +211,13 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     return true;
   }
 
-  if (!CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) {
-    IntrusiveRefCntPtr<vfs::OverlayFileSystem>
-        Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
-    // earlier vfs files are on the bottom
-    const std::vector<std::string> &Files =
-        CI.getHeaderSearchOpts().VFSOverlayFiles;
-    for (std::vector<std::string>::const_iterator I = Files.begin(),
-                                                  E = Files.end();
-         I != E; ++I) {
-      std::unique_ptr<llvm::MemoryBuffer> Buffer;
-      if (llvm::errc::success != llvm::MemoryBuffer::getFile(*I, Buffer)) {
-        CI.getDiagnostics().Report(diag::err_missing_vfs_overlay_file) << *I;
-        goto failure;
-      }
-
-      IntrusiveRefCntPtr<vfs::FileSystem> FS =
-          vfs::getVFSFromYAML(Buffer.release(), /*DiagHandler*/ 0);
-      if (!FS.getPtr()) {
-        CI.getDiagnostics().Report(diag::err_invalid_vfs_overlay) << *I;
-        goto failure;
-      }
-      Overlay->pushOverlay(FS);
-    }
-    CI.setVirtualFileSystem(Overlay);
+  if (!CI.hasVirtualFileSystem()) {
+    if (IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+          createVFSFromCompilerInvocation(CI.getInvocation(),
+                                          CI.getDiagnostics()))
+      CI.setVirtualFileSystem(VFS);
+    else
+      goto failure;
   }
 
   // Set up the file and source managers, if needed.
diff --git a/test/Index/Inputs/base_module_needs_vfs.h b/test/Index/Inputs/base_module_needs_vfs.h
new file mode 100644
index 00000000000..9a7a2445a86
--- /dev/null
+++ b/test/Index/Inputs/base_module_needs_vfs.h
@@ -0,0 +1 @@
+void base_module_needs_vfs(void);
diff --git a/test/Index/Inputs/module.map b/test/Index/Inputs/module.map
new file mode 100644
index 00000000000..8f24840c81f
--- /dev/null
+++ b/test/Index/Inputs/module.map
@@ -0,0 +1,6 @@
+// See vfsoverlay.yaml
+module ModuleNeedsVFS {
+  header "ModuleNeedsVFS.h"
+  export *
+}
+framework module * { }
diff --git a/test/Index/Inputs/module_needs_vfs.h b/test/Index/Inputs/module_needs_vfs.h
new file mode 100644
index 00000000000..d79cc3f0d3a
--- /dev/null
+++ b/test/Index/Inputs/module_needs_vfs.h
@@ -0,0 +1,4 @@
+@import BaseModuleNeedsVFS;
+inline void module_needs_vfs(void) {
+  base_module_needs_vfs();
+}
diff --git a/test/Index/Inputs/vfsoverlay.yaml b/test/Index/Inputs/vfsoverlay.yaml
new file mode 100644
index 00000000000..95b00bef7d0
--- /dev/null
+++ b/test/Index/Inputs/vfsoverlay.yaml
@@ -0,0 +1,18 @@
+{
+  'version': 0,
+  'roots': [
+    { 'name': 'OUT_DIR', 'type': 'directory',
+      'contents': [
+        { 'name': 'module.map', 'type': 'file',
+          'external-contents': 'INPUT_DIR/module.map'
+        },
+        { 'name': 'ModuleNeedsVFS.h', 'type': 'file',
+          'external-contents': 'INPUT_DIR/module_needs_vfs.h'
+        },
+        { 'name': 'BaseModuleNeedsVFS.framework/Headers/BaseModuleNeedsVFS.h', 'type': 'file',
+          'external-contents': 'INPUT_DIR/base_module_needs_vfs.h'
+        },
+      ]
+    }
+  ]
+}
diff --git a/test/Index/index-module-with-vfs.m b/test/Index/index-module-with-vfs.m
new file mode 100644
index 00000000000..f3ca60cf941
--- /dev/null
+++ b/test/Index/index-module-with-vfs.m
@@ -0,0 +1,26 @@
+// REQUIRES: shell
+@import ModuleNeedsVFS;
+
+void foo() {
+  module_needs_vfs();
+  base_module_needs_vfs();
+}
+
+// RUN: rm -rf %t.cache
+// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml
+// RUN: c-index-test -index-file %s -fmodules-cache-path=%t.cache -fmodules -F %t -I %t \
+// RUN:              -ivfsoverlay %t.yaml -Xclang -fdisable-module-hash | FileCheck %s
+
+// CHECK: [importedASTFile]: {{.*}}ModuleNeedsVFS.pcm | loc: 2:1 | name: "ModuleNeedsVFS" | isImplicit: 0
+// CHECK: [indexEntityReference]: kind: function | name: module_needs_vfs
+// CHECK: [indexEntityReference]: kind: function | name: base_module_needs_vfs
+
+// RUN: c-index-test -index-tu %t.cache/ModuleNeedsVFS.pcm | FileCheck %s -check-prefix=CHECK-MOD
+
+// CHECK-MOD: [ppIncludedFile]: {{.*}}module_needs_vfs.h 
+// CHECK-MOD: [importedASTFile]: {{.*}}BaseModuleNeedsVFS.pcm
+// CHECK-MOD: [indexEntityReference]: kind: function | name: base_module_needs_vfs
+
+// RUN: c-index-test -index-tu %t.cache/BaseModuleNeedsVFS.pcm | FileCheck %s -check-prefix=CHECK-MOD2
+
+// CHECK-MOD2: [ppIncludedFile]: {{.*}}base_module_needs_vfs.h
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 591294599dc..23fdf93b76f 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -249,7 +249,7 @@ namespace {
 /// AllocatedCXCodeCompleteResults outlives the CXTranslationUnit, so we can
 /// not rely on the StringPool in the TU.
 struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
-  AllocatedCXCodeCompleteResults(const FileSystemOptions& FileSystemOpts);
+  AllocatedCXCodeCompleteResults(IntrusiveRefCntPtr<FileManager> FileMgr);
   ~AllocatedCXCodeCompleteResults();
   
   /// \brief Diagnostics produced while performing code completion.
@@ -263,8 +263,6 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
   /// \brief Language options used to adjust source locations.
   LangOptions LangOpts;
 
-  FileSystemOptions FileSystemOpts;
-
   /// \brief File manager, used for diagnostics.
   IntrusiveRefCntPtr<FileManager> FileMgr;
 
@@ -318,20 +316,15 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
 static std::atomic<unsigned> CodeCompletionResultObjects;
   
 AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
-                                      const FileSystemOptions& FileSystemOpts)
-  : CXCodeCompleteResults(),
-    DiagOpts(new DiagnosticOptions),
-    Diag(new DiagnosticsEngine(
-                   IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-                   &*DiagOpts)),
-    FileSystemOpts(FileSystemOpts),
-    FileMgr(new FileManager(FileSystemOpts)),
-    SourceMgr(new SourceManager(*Diag, *FileMgr)),
-    CodeCompletionAllocator(new clang::GlobalCodeCompletionAllocator),
-    Contexts(CXCompletionContext_Unknown),
-    ContainerKind(CXCursor_InvalidCode),
-    ContainerIsIncomplete(1)
-{ 
+    IntrusiveRefCntPtr<FileManager> FileMgr)
+    : CXCodeCompleteResults(),
+      DiagOpts(new DiagnosticOptions),
+      Diag(new DiagnosticsEngine(
+          IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts)),
+      FileMgr(FileMgr), SourceMgr(new SourceManager(*Diag, *FileMgr)),
+      CodeCompletionAllocator(new clang::GlobalCodeCompletionAllocator),
+      Contexts(CXCompletionContext_Unknown),
+      ContainerKind(CXCursor_InvalidCode), ContainerIsIncomplete(1) {
   if (getenv("LIBCLANG_OBJTRACKING"))
     fprintf(stderr, "+++ %u completion results\n",
             ++CodeCompletionResultObjects);
@@ -709,8 +702,8 @@ void clang_codeCompleteAt_Impl(void *UserData) {
   }
 
   // Parse the resulting source file to find code-completion results.
-  AllocatedCXCodeCompleteResults *Results = 
-        new AllocatedCXCodeCompleteResults(AST->getFileSystemOpts());
+  AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults(
+      &AST->getFileManager());
   Results->Results = 0;
   Results->NumResults = 0;
   
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index 55e6e798737..47ba97bd9a6 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -610,6 +610,11 @@ static void clang_indexSourceFile_Impl(void *UserData) {
   ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags,
                                   CaptureDiagnostics,
                                   /*UserFilesAreVolatile=*/true);
+  if (!Unit) {
+    ITUI->result = CXError_InvalidArguments;
+    return;
+  }
+
   std::unique_ptr<CXTUOwner> CXTU(
       new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit)));
 
-- 
GitLab