]> granicus.if.org Git - clang/commitdiff
Use the same SourceManager for ModuleMaps and compilations.
authorManuel Klimek <klimek@google.com>
Thu, 24 Oct 2013 07:51:24 +0000 (07:51 +0000)
committerManuel Klimek <klimek@google.com>
Thu, 24 Oct 2013 07:51:24 +0000 (07:51 +0000)
This allows using virtual file mappings on the original SourceManager to
map in virtual module.map files. Without this patch, the ModuleMap
search will find a module.map file (as the FileEntry exists in the
FileManager), but will be unable to get the content from the
SourceManager (as ModuleMap previously created its own SourceManager).

Two problems needed to be fixed which this patch exposed:

1. Storing the inferred module map
When writing out a module, the ASTWriter stores the names of the files
in the main source manager; when loading the AST again, the ASTReader
errs out if such a file is found missing, unless it is overridden.
Previously CompilerInstance's compileModule method would store the
inferred module map to a temporary file; the problem with this approach
is that now that the module map is handled by the main source manager,
the ASTWriter stores the name of the temporary module map as source to
the compilation; later, when the module is loaded, the temporary file
has already been deleted, which leads to a compilation error. This patch
changes the inferred module map to instead inject a virtual file into
the source manager. This both saves some disk IO, and works with how the
ASTWriter/ASTReader handle overridden source files.

2. Changing test input in test/Modules/Inputs/*
Now that the module map file is handled by the main source manager, the
VerifyDiagnosticConsumer will not ignore diagnostics created while
parsing the module map file. The module test test/Modules/renamed.m uses
-I test/Modules/Inputs and triggers recursive loading of all module maps
in test/Modules/Inputs, some of which had conflicting names, thus
leading errors while parsing the module maps. Those diagnostics already
occur on trunk, but before this patch they would not break the test, as
they were ignored by the VerifyDiagnosticConsumer. This patch thus
changes the module maps that have been recently introduced which broke
the invariant of compatible modules maps in test/Modules/Inputs.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193314 91177308-0d34-0410-b5e6-96231b3b80d8

17 files changed:
include/clang/Lex/HeaderSearch.h
include/clang/Lex/ModuleMap.h
lib/Frontend/ASTUnit.cpp
lib/Frontend/CompilerInstance.cpp
lib/Lex/HeaderSearch.cpp
lib/Lex/ModuleMap.cpp
test/Modules/Inputs/declare-use/module.map
test/Modules/Inputs/private1/module.map
test/Modules/Inputs/private2/module.map
test/Modules/declare-use1.cpp
test/Modules/declare-use2.cpp
test/Modules/private1.cpp
unittests/Basic/SourceManagerTest.cpp
unittests/Lex/LexerTest.cpp
unittests/Lex/PPCallbacksTest.cpp
unittests/Lex/PPConditionalDirectiveRecordTest.cpp
unittests/Tooling/ToolingTest.cpp

index 84dd6eb44117d4cb4022d3ea7e6e11570d563320..fb1a862063540b18333152e9d37d9b2b30d106e2 100644 (file)
@@ -240,7 +240,7 @@ class HeaderSearch {
   
 public:
   HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
-               FileManager &FM, DiagnosticsEngine &Diags,
+               SourceManager &SourceMgr, DiagnosticsEngine &Diags,
                const LangOptions &LangOpts, const TargetInfo *Target);
   ~HeaderSearch();
 
index b7982a17aa5608c429e63d9868cad43b6ffbc577..3a17157f94d5a01fab6c66fc40bfa447195b6363 100644 (file)
@@ -37,7 +37,7 @@ class HeaderSearch;
 class ModuleMapParser;
   
 class ModuleMap {
-  SourceManager *SourceMgr;
+  SourceManager &SourceMgr;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   const LangOptions &LangOpts;
   const TargetInfo *Target;
@@ -178,9 +178,9 @@ private:
 public:
   /// \brief Construct a new module map.
   ///
-  /// \param FileMgr The file manager used to find module files and headers.
-  /// This file manager should be shared with the header-search mechanism, since
-  /// they will refer to the same headers.
+  /// \param SourceMgr The source manager used to find module files and headers.
+  /// This source manager should be shared with the header-search mechanism,
+  /// since they will refer to the same headers.
   ///
   /// \param DC A diagnostic consumer that will be cloned for use in generating
   /// diagnostics.
@@ -188,7 +188,7 @@ public:
   /// \param LangOpts Language options for this translation unit.
   ///
   /// \param Target The target for this translation unit.
-  ModuleMap(FileManager &FileMgr, DiagnosticConsumer &DC,
+  ModuleMap(SourceManager &SourceMgr, DiagnosticConsumer &DC,
             const LangOptions &LangOpts, const TargetInfo *Target,
             HeaderSearch &HeaderInfo);
 
index 610c20d9fb14f3c8bef8a568aa3490f545958cc7..a8c587638a286c19b4a7c0f7fbf6d09d8947bf04 100644 (file)
@@ -707,7 +707,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
   AST->HSOpts = new HeaderSearchOptions();
   
   AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts,
-                                         AST->getFileManager(),
+                                         AST->getSourceManager(),
                                          AST->getDiagnostics(),
                                          AST->ASTFileLangOpts,
                                          /*Target=*/0));
index 9f0ca3b31e92d7ebdf215b0dc3844c7c3dfec69e..5d3fd456c44bf5fcd32819a2bf0b319c4f66cedd 100644 (file)
@@ -218,7 +218,7 @@ void CompilerInstance::createPreprocessor() {
 
   // Create the Preprocessor.
   HeaderSearch *HeaderInfo = new HeaderSearch(&getHeaderSearchOpts(),
-                                              getFileManager(),
+                                              getSourceManager(),
                                               getDiagnostics(),
                                               getLangOpts(),
                                               &getTarget());
@@ -851,29 +851,6 @@ static void compileModule(CompilerInstance &ImportingInstance,
   FrontendOpts.Inputs.clear();
   InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts());
 
-  // Get or create the module map that we'll use to build this module.
-  SmallString<128> TempModuleMapFileName;
-  if (const FileEntry *ModuleMapFile
-                                  = ModMap.getContainingModuleMapFile(Module)) {
-    // Use the module map where this module resides.
-    FrontendOpts.Inputs.push_back(FrontendInputFile(ModuleMapFile->getName(), 
-                                                    IK));
-  } else {
-    // Create a temporary module map file.
-    int FD;
-    if (llvm::sys::fs::createTemporaryFile(Module->Name, "map", FD,
-                                           TempModuleMapFileName)) {
-      ImportingInstance.getDiagnostics().Report(diag::err_module_map_temp_file)
-        << TempModuleMapFileName;
-      return;
-    }
-    // Print the module map to this file.
-    llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true);
-    Module->print(OS);
-    FrontendOpts.Inputs.push_back(
-      FrontendInputFile(TempModuleMapFileName.str().str(), IK));
-  }
-
   // Don't free the remapped file buffers; they are owned by our caller.
   PPOpts.RetainRemappedFileBuffers = true;
     
@@ -900,6 +877,26 @@ static void compileModule(CompilerInstance &ImportingInstance,
   SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(),
     FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
 
+  // Get or create the module map that we'll use to build this module.
+  std::string InferredModuleMapContent;
+  if (const FileEntry *ModuleMapFile =
+          ModMap.getContainingModuleMapFile(Module)) {
+    // Use the module map where this module resides.
+    FrontendOpts.Inputs.push_back(
+        FrontendInputFile(ModuleMapFile->getName(), IK));
+  } else {
+    llvm::raw_string_ostream OS(InferredModuleMapContent);
+    Module->print(OS);
+    OS.flush();
+    FrontendOpts.Inputs.push_back(
+        FrontendInputFile("__inferred_module.map", IK));
+
+    const llvm::MemoryBuffer *ModuleMapBuffer =
+        llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
+    ModuleMapFile = Instance.getFileManager().getVirtualFile(
+        "__inferred_module.map", InferredModuleMapContent.size(), 0);
+    SourceMgr.overrideFileContents(ModuleMapFile, ModuleMapBuffer);
+  }
 
   // Construct a module-generating action.
   GenerateModuleAction CreateModuleAction(Module->IsSystem);
@@ -917,8 +914,6 @@ static void compileModule(CompilerInstance &ImportingInstance,
   // be nice to do this with RemoveFileOnSignal when we can. However, that
   // doesn't make sense for all clients, so clean this up manually.
   Instance.clearOutputFiles(/*EraseFiles=*/true);
-  if (!TempModuleMapFileName.empty())
-    llvm::sys::fs::remove(TempModuleMapFileName.str());
 
   // We've rebuilt a module. If we're allowed to generate or update the global
   // module index, record that fact in the importing compiler instance.
index 84d205acdaeccd94a7f0f5ddf35fe8f9f8e637f9..2da2c9efba9e3254802eed39b2d1e168aef8da98 100644 (file)
@@ -44,11 +44,11 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
 ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
 
 HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
-                           FileManager &FM, DiagnosticsEngine &Diags,
+                           SourceManager &SourceMgr, DiagnosticsEngine &Diags,
                            const LangOptions &LangOpts, 
                            const TargetInfo *Target)
-  : HSOpts(HSOpts), FileMgr(FM), FrameworkMap(64),
-    ModMap(FileMgr, *Diags.getClient(), LangOpts, Target, *this)
+  : HSOpts(HSOpts), FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
+    ModMap(SourceMgr, *Diags.getClient(), LangOpts, Target, *this)
 {
   AngledDirIdx = 0;
   SystemDirIdx = 0;
index 25d68ace0f199871a262a5ad03ec4f477bc5b2b7..54007c78d839fec5d6d05efd40e1b39b12a95dd8 100644 (file)
@@ -83,18 +83,18 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
   return Context;
 }
 
-ModuleMap::ModuleMap(FileManager &FileMgr, DiagnosticConsumer &DC,
+ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticConsumer &DC,
                      const LangOptions &LangOpts, const TargetInfo *Target,
                      HeaderSearch &HeaderInfo)
-  : LangOpts(LangOpts), Target(Target), HeaderInfo(HeaderInfo),
-    BuiltinIncludeDir(0), CompilingModule(0), SourceModule(0)
-{
+    : SourceMgr(SourceMgr), LangOpts(LangOpts), Target(Target),
+      HeaderInfo(HeaderInfo), BuiltinIncludeDir(0), CompilingModule(0),
+      SourceModule(0) {
   IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
   Diags = IntrusiveRefCntPtr<DiagnosticsEngine>(
             new DiagnosticsEngine(DiagIDs, new DiagnosticOptions));
   Diags->setClient(new ForwardingDiagnosticConsumer(DC),
                    /*ShouldOwnClient=*/true);
-  SourceMgr = new SourceManager(*Diags, FileMgr);
+  Diags->setSourceManager(&SourceMgr);
 }
 
 ModuleMap::~ModuleMap() {
@@ -103,8 +103,6 @@ ModuleMap::~ModuleMap() {
        I != IEnd; ++I) {
     delete I->getValue();
   }
-  
-  delete SourceMgr;
 }
 
 void ModuleMap::setTarget(const TargetInfo &Target) {
@@ -224,7 +222,7 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
   // frameworks moving from top-level frameworks to embedded frameworks tend
   // to be symlinked from the top-level location to the embedded location,
   // and we need to resolve lookups as if we had found the embedded location.
-  StringRef DirName = SourceMgr->getFileManager().getCanonicalName(Dir);
+  StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir);
 
   // Keep walking up the directory hierarchy, looking for a directory with
   // an umbrella header.
@@ -301,7 +299,7 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
       break;
     
     // Resolve the parent path to a directory entry.
-    Dir = SourceMgr->getFileManager().getDirectory(DirName);
+    Dir = SourceMgr.getFileManager().getDirectory(DirName);
   } while (Dir);
   
   return KnownHeader();
@@ -375,7 +373,7 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
       break;
     
     // Resolve the parent path to a directory entry.
-    Dir = SourceMgr->getFileManager().getDirectory(DirName);
+    Dir = SourceMgr.getFileManager().getDirectory(DirName);
   } while (Dir);
   
   return false;
@@ -480,7 +478,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
   if (Module *Mod = lookupModuleQualified(ModuleName, Parent))
     return Mod;
   
-  FileManager &FileMgr = SourceMgr->getFileManager();
+  FileManager &FileMgr = SourceMgr.getFileManager();
 
   // If the framework has a parent path from which we're allowed to infer
   // a framework module, do so.
@@ -492,7 +490,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
     // top-level framework, and we need to infer as if we were naming the
     // top-level framework.
     StringRef FrameworkDirName
-      = SourceMgr->getFileManager().getCanonicalName(FrameworkDir);
+      = SourceMgr.getFileManager().getCanonicalName(FrameworkDir);
 
     bool canInfer = false;
     if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
@@ -654,11 +652,11 @@ void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
 
 const FileEntry *
 ModuleMap::getContainingModuleMapFile(Module *Module) const {
-  if (Module->DefinitionLoc.isInvalid() || !SourceMgr)
+  if (Module->DefinitionLoc.isInvalid())
     return 0;
 
-  return SourceMgr->getFileEntryForID(
-           SourceMgr->getFileID(Module->DefinitionLoc));
+  return SourceMgr.getFileEntryForID(
+           SourceMgr.getFileID(Module->DefinitionLoc));
 }
 
 void ModuleMap::dump() {
@@ -2110,15 +2108,15 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) {
     return Known->second;
 
   assert(Target != 0 && "Missing target information");
-  FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User);
-  const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID);
+  FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
+  const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID);
   if (!Buffer)
     return ParsedModuleMap[File] = true;
   
   // Parse this module map file.
-  Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
+  Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts);
   Diags->getClient()->BeginSourceFile(MMapLangOpts);
-  ModuleMapParser Parser(L, *SourceMgr, Target, *Diags, *this, File->getDir(),
+  ModuleMapParser Parser(L, SourceMgr, Target, *Diags, *this, File->getDir(),
                          BuiltinIncludeDir, IsSystem);
   bool Result = Parser.parseModuleMapFile();
   Diags->getClient()->EndSourceFile();
index ae3e90801ec0cbc024a5441cb0202f23fb9a1936..774fc37760c9c765fba263941fe6303755c48660 100644 (file)
@@ -1,43 +1,43 @@
-module A {
+module XA {
   header "a.h"
 }
 
-module B {
+module XB {
   header "b.h"
 }
 
-module C {
+module XC {
   header "c.h"
-  use A
+  use XA
 }
 
-module D {
+module XD {
   header "d.h"
-  use A
+  use XA
 }
 
-module E {
+module XE {
   header "e.h"
-  use A
-  use B
+  use XA
+  use XB
 }
 
-module F {
+module XF {
   header "f.h"
-  use A
-  use B
+  use XA
+  use XB
 }
 
-module G {
+module XG {
   header "g.h"
   header "g1.h"
-  use C
-  use E
+  use XC
+  use XE
 }
 
-module H {
+module XH {
   header "h.h"
   header "h1.h"
-  use C
-  use E
+  use XC
+  use XE
 }
index 445c8010db9b04a86c1c4a42f2e68364989e3818..0904fe68a62c5c662b00e2fd1491cb6fed21dfe6 100644 (file)
@@ -1,4 +1,4 @@
-module libPrivate1 {
+module libPrivate {
   header "public1.h"
   private header "private1.h"
 }
index 6c5efb60209da124cea9b1b58c953b2c348167d6..3d2a5786f9b10cc5394c2b84c5d4d2fef342cfcf 100644 (file)
@@ -1,4 +1,4 @@
-module libPrivate2 {
+module libPrivateN2 {
   header "public2.h"
   private header "private2.h"
 }
index 5bb7e2a47aff2547b8e06abfd2a0aa4d25448a34..4508017c12d205e7d2828c86f5bba4ce5eed2b6b 100644 (file)
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=G -I %S/Inputs/declare-use %s -verify
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=XG -I %S/Inputs/declare-use %s -verify
 
 #include "g.h"
 #include "e.h"
index 807962cbdb4af1e8e036132bd2e893289228b727..a2ec55e5e5ca3b4fb1c43a1641087d0a3838116b 100644 (file)
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=H -I %S/Inputs/declare-use %s -verify
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=XH -I %S/Inputs/declare-use %s -verify
 
 #include "h.h"
 #include "e.h"
index e4eec0a515c8510d59bfa1f862aeadda15a8804e..811a2333d1db4dd1ef1590c8cd2da90d44058010 100644 (file)
@@ -2,7 +2,7 @@
 // RUN: %clang_cc1 -x objective-c -fmodules-cache-path=%t -fmodules -I %S/Inputs/private0 -I %S/Inputs/private1 -I %S/Inputs/private2 %s -verify
 
 #include "common.h"
-@import libPrivate1;
+@import libPrivateN2;
 #include "private1.h" // expected-error {{use of private header from outside its module}}
 #include "public2.h"
 #include "private2.h" // expected-error {{use of private header from outside its module}}
index 8e7f4a0371afd8806d64c9cc129bcd385764fb73..d94cfe9c3fab0baeeb0af5c6c53b6b5eb6599656 100644 (file)
@@ -73,7 +73,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
   FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf);
 
   VoidModuleLoader ModLoader;
-  HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, 
+  HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, 
                           &*Target);
   Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
                   SourceMgr, HeaderInfo, ModLoader,
@@ -188,7 +188,7 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
   SourceMgr.overrideFileContents(headerFile, headerBuf);
 
   VoidModuleLoader ModLoader;
-  HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, 
+  HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, 
                           &*Target);
   Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
                   SourceMgr, HeaderInfo, ModLoader,
@@ -286,7 +286,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
   SourceMgr.overrideFileContents(headerFile, headerBuf);
 
   VoidModuleLoader ModLoader;
-  HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, 
+  HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, 
                           &*Target);
   Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
                   SourceMgr, HeaderInfo, ModLoader,
index a8e25cb2a394cceb7b21344438deb153019dab92..40ce928014d5462b4c5ac7193f4f6b1768f0aaac 100644 (file)
@@ -62,7 +62,7 @@ protected:
     (void) SourceMgr.createMainFileIDForMemBuffer(buf);
 
     VoidModuleLoader ModLoader;
-    HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+    HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
                             Target.getPtr());
     Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
                     SourceMgr, HeaderInfo, ModLoader, /*IILookup =*/ 0,
index fd407b52c6ebed7a7314446ab2dbe1eaa6e512b0..9405a84024bd052c2cc077df3afb261e304908fd 100644 (file)
@@ -162,7 +162,8 @@ protected:
     VoidModuleLoader ModLoader;
 
     IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
-    HeaderSearch HeaderInfo(HSOpts, FileMgr, Diags, LangOpts, Target.getPtr());
+    HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
+                            Target.getPtr());
     AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
 
     IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
@@ -198,7 +199,7 @@ protected:
     (void)SourceMgr.createMainFileIDForMemBuffer(sourceBuf);
 
     VoidModuleLoader ModLoader;
-    HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, 
+    HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, 
                             OpenCLLangOpts, Target.getPtr());
 
     Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, 
index 082eced2d854cde3b7929af683aeb9b61575877b..58857fa5a133563f43fef4f61a9c3d1c1d80f848 100644 (file)
@@ -90,7 +90,7 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
   SourceMgr.createMainFileIDForMemBuffer(buf);
 
   VoidModuleLoader ModLoader;
-  HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, 
+  HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, 
                           Target.getPtr());
   Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts,Target.getPtr(),
                   SourceMgr, HeaderInfo, ModLoader,
index e435ea92e235c4759e4262895a4b38f3205e4d92..412af7adda9bbabc84341c484e185685a9631b55 100644 (file)
@@ -131,6 +131,26 @@ TEST(ToolInvocation, TestMapVirtualFile) {
   EXPECT_TRUE(Invocation.run());
 }
 
+TEST(ToolInvocation, TestVirtualModulesCompilation) {
+  // FIXME: Currently, this only tests that we don't exit with an error if a
+  // mapped module.map is found on the include path. In the future, expand this
+  // test to run a full modules enabled compilation, so we make sure we can
+  // rerun modules compilations with a virtual file system.
+  clang::FileManager Files((clang::FileSystemOptions()));
+  std::vector<std::string> Args;
+  Args.push_back("tool-executable");
+  Args.push_back("-Idef");
+  Args.push_back("-fsyntax-only");
+  Args.push_back("test.cpp");
+  clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction, &Files);
+  Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
+  Invocation.mapVirtualFile("def/abc", "\n");
+  // Add a module.map file in the include directory of our header, so we trigger
+  // the module.map header search logic.
+  Invocation.mapVirtualFile("def/module.map", "\n");
+  EXPECT_TRUE(Invocation.run());
+}
+
 struct VerifyEndCallback : public SourceFileCallbacks {
   VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
   virtual bool handleBeginSource(CompilerInstance &CI,