diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -141,6 +141,9 @@ /// The name of the umbrella entry, as written in the module map. std::string UmbrellaAsWritten; + // The path to the umbrella entry relative to the root module's \c Directory. + std::string UmbrellaRelativeToRootModuleDirectory; + /// The module through which entities defined in this module will /// eventually be exposed, for use in "private" modules. std::string ExportAsModule; @@ -188,6 +191,7 @@ /// file. struct Header { std::string NameAsWritten; + std::string PathRelativeToRootModuleDirectory; const FileEntry *Entry; explicit operator bool() { return Entry; } @@ -197,6 +201,7 @@ /// file. struct DirectoryName { std::string NameAsWritten; + std::string PathRelativeToRootModuleDirectory; const DirectoryEntry *Entry; explicit operator bool() { return Entry; } @@ -545,7 +550,8 @@ /// module. Header getUmbrellaHeader() const { if (auto *FE = Umbrella.dyn_cast()) - return Header{UmbrellaAsWritten, FE}; + return Header{UmbrellaAsWritten, UmbrellaRelativeToRootModuleDirectory, + FE}; return Header{}; } diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -649,12 +649,14 @@ /// Sets the umbrella header of the given module to the given /// header. void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader, - Twine NameAsWritten); + Twine NameAsWritten, + Twine PathRelativeToRootModuleDirectory); /// Sets the umbrella directory of the given module to the given /// directory. void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir, - Twine NameAsWritten); + Twine NameAsWritten, + Twine PathRelativeToRootModuleDirectory); /// Adds this header to the given module. /// \param Role The role of the header wrt the module. diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -245,9 +245,10 @@ Module::DirectoryName Module::getUmbrellaDir() const { if (Header U = getUmbrellaHeader()) - return {"", U.Entry->getDir()}; + return {"", "", U.Entry->getDir()}; - return {UmbrellaAsWritten, Umbrella.dyn_cast()}; + return {UmbrellaAsWritten, UmbrellaRelativeToRootModuleDirectory, + Umbrella.dyn_cast()}; } void Module::addTopHeader(const FileEntry *File) { diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -342,7 +342,8 @@ // file relative to the module build directory (the directory containing // the module map file) so this will find the same file that we found // while parsing the module map. - addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC); + addHeaderInclude(H.PathRelativeToRootModuleDirectory, Includes, LangOpts, + Module->IsExternC); } } // Note that Module->PrivateHeaders will not be a TopHeader. @@ -351,8 +352,8 @@ Module->addTopHeader(UmbrellaHeader.Entry); if (Module->Parent) // Include the umbrella header for submodules. - addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts, - Module->IsExternC); + addHeaderInclude(UmbrellaHeader.PathRelativeToRootModuleDirectory, + Includes, LangOpts, Module->IsExternC); } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) { // Add all of the headers we find in this subdirectory. std::error_code EC; @@ -386,7 +387,8 @@ auto PathIt = llvm::sys::path::rbegin(Dir->path()); for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt) Components.push_back(*PathIt); - SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten); + SmallString<128> RelativeHeader( + UmbrellaDir.PathRelativeToRootModuleDirectory); for (auto It = Components.rbegin(), End = Components.rend(); It != End; ++It) llvm::sys::path::append(RelativeHeader, *It); @@ -470,7 +472,7 @@ // Dig out the module definition. HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule, - /*AllowSearch=*/false); + /*AllowSearch=*/true); if (!M) { CI.getDiagnostics().Report(diag::err_missing_module) << CI.getLangOpts().CurrentModule << ModuleMapFilename; @@ -528,8 +530,8 @@ SmallString<256> HeaderContents; std::error_code Err = std::error_code(); if (Module::Header UmbrellaHeader = M->getUmbrellaHeader()) - addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents, - CI.getLangOpts(), M->IsExternC); + addHeaderInclude(UmbrellaHeader.PathRelativeToRootModuleDirectory, + HeaderContents, CI.getLangOpts(), M->IsExternC); Err = collectModuleHeaderIncludes( CI.getLangOpts(), FileMgr, CI.getDiagnostics(), CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), M, diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -297,7 +297,8 @@ << Name; continue; } - Headers.push_back({std::string(Name), &FE->getFileEntry()}); + Headers.push_back( + {std::string(Name), std::string(Name), &FE->getFileEntry()}); } HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers); diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -260,9 +260,10 @@ << UmbrellaMod->getFullModuleName(); else // Record this umbrella header. - setUmbrellaHeader(Mod, *File, RelativePathName.str()); + setUmbrellaHeader(Mod, *File, Header.FileName, RelativePathName.str()); } else { - Module::Header H = {std::string(RelativePathName.str()), *File}; + Module::Header H = {Header.FileName, std::string(RelativePathName.str()), + *File}; if (Header.Kind == Module::HK_Excluded) excludeHeader(Mod, H); else @@ -305,7 +306,7 @@ return false; auto Role = headerKindToRole(Header.Kind); - Module::Header H = {std::string(Path.str()), *File}; + Module::Header H = {Header.FileName, std::string(Path.str()), *File}; addHeader(Mod, H, Role); return true; } @@ -1038,11 +1039,13 @@ Result->NoUndeclaredIncludes |= Attrs.NoUndeclaredIncludes; Result->Directory = FrameworkDir; + // Chop off the first framework bit, as that is implied. + StringRef RelativePath = UmbrellaName.str().substr( + Result->getTopLevelModule()->Directory->getName().size()); + RelativePath = llvm::sys::path::relative_path(RelativePath); + // umbrella header "umbrella-header-name" - // - // The "Headers/" component of the name is implied because this is - // a framework module. - setUmbrellaHeader(Result, *UmbrellaHeader, ModuleName + ".h"); + setUmbrellaHeader(Result, *UmbrellaHeader, ModuleName + ".h", RelativePath); // export * Result->Exports.push_back(Module::ExportDecl(nullptr, true)); @@ -1122,10 +1125,13 @@ } void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader, - Twine NameAsWritten) { + Twine NameAsWritten, + Twine PathRelativeToRootModuleDirectory) { Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader)); Mod->Umbrella = UmbrellaHeader; Mod->UmbrellaAsWritten = NameAsWritten.str(); + Mod->UmbrellaRelativeToRootModuleDirectory = + PathRelativeToRootModuleDirectory.str(); UmbrellaDirs[UmbrellaHeader->getDir()] = Mod; // Notify callbacks that we just added a new header. @@ -1134,9 +1140,12 @@ } void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir, - Twine NameAsWritten) { + Twine NameAsWritten, + Twine PathRelativeToRootModuleDirectory) { Mod->Umbrella = UmbrellaDir; Mod->UmbrellaAsWritten = NameAsWritten.str(); + Mod->UmbrellaRelativeToRootModuleDirectory = + PathRelativeToRootModuleDirectory.str(); UmbrellaDirs[UmbrellaDir] = Mod; } @@ -2405,6 +2414,7 @@ } std::string DirName = std::string(Tok.getString()); + std::string DirNameAsWritten = DirName; SourceLocation DirNameLoc = consumeToken(); // Check whether we already have an umbrella. @@ -2446,7 +2456,7 @@ for (llvm::vfs::recursive_directory_iterator I(FS, Dir->getName(), EC), E; I != E && !EC; I.increment(EC)) { if (auto FE = SourceMgr.getFileManager().getFile(I->path())) { - Module::Header Header = {std::string(I->path()), *FE}; + Module::Header Header = {"", std::string(I->path()), *FE}; Headers.push_back(std::move(Header)); } } @@ -2467,7 +2477,7 @@ } // Record this umbrella directory. - Map.setUmbrellaDir(ActiveModule, Dir, DirName); + Map.setUmbrellaDir(ActiveModule, Dir, DirNameAsWritten, DirName); } /// Parse a module export declaration. diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1924,7 +1924,8 @@ // FIXME: This is not always the right filename-as-written, but we're not // going to use this information to rebuild the module, so it doesn't make // a lot of difference. - Module::Header H = {std::string(key.Filename), *FileMgr.getFile(Filename)}; + Module::Header H = {std::string(key.Filename), "", + *FileMgr.getFile(Filename)}; ModMap.addHeader(Mod, H, HeaderRole, /*Imported*/true); HFI.isModuleHeader |= !(HeaderRole & ModuleMap::TextualHeader); } @@ -5618,7 +5619,8 @@ ResolveImportedPath(F, Filename); if (auto Umbrella = PP.getFileManager().getFile(Filename)) { if (!CurrentModule->getUmbrellaHeader()) - ModMap.setUmbrellaHeader(CurrentModule, *Umbrella, Blob); + // FIXME: NameAsWritten + ModMap.setUmbrellaHeader(CurrentModule, *Umbrella, Blob, ""); else if (CurrentModule->getUmbrellaHeader().Entry != *Umbrella) { if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Error("mismatched umbrella headers in submodule"); @@ -5651,7 +5653,8 @@ ResolveImportedPath(F, Dirname); if (auto Umbrella = PP.getFileManager().getDirectory(Dirname)) { if (!CurrentModule->getUmbrellaDir()) - ModMap.setUmbrellaDir(CurrentModule, *Umbrella, Blob); + // FIXME: NameAsWritten + ModMap.setUmbrellaDir(CurrentModule, *Umbrella, Blob, ""); else if (CurrentModule->getUmbrellaDir().Entry != *Umbrella) { if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Error("mismatched umbrella directories in submodule"); diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -32,7 +32,6 @@ CI.getFrontendOpts().IsSystemModule = Deps.IsSystem; CI.getLangOpts()->ImplicitModules = false; - CI.getHeaderSearchOpts().ImplicitModuleMaps = false; return CI; } @@ -171,7 +170,7 @@ const FileEntry *ModuleMap = Instance.getPreprocessor() .getHeaderSearchInfo() .getModuleMap() - .getContainingModuleMapFile(M); + .getModuleMapFileForUniquing(M); MD.Invocation = Instance.getInvocationPtr(); MD.ClangModuleMapFile = std::string(ModuleMap ? ModuleMap->getName() : ""); @@ -183,6 +182,15 @@ MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile()); MDC.Instance.getASTReader()->visitInputFiles( *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) { + // __inferred_module.map is the result of the way in which an implicit + // module build handles inferred modules. It adds an overlay VFS with + // this file in the proper directory and relies on the rest of Clang to + // handle it like normal. With explicitly built modules we don't need + // to play VFS tricks, so replace it with the correct module map. + if (IF.getFile()->getName().endswith("__inferred_module.map")) { + MD.FileDeps.insert(ModuleMap->getName()); + return; + } MD.FileDeps.insert(IF.getFile()->getName()); }); diff --git a/clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Frameworks/Sub.framework/Headers/Sub.h b/clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Frameworks/Sub.framework/Headers/Sub.h new file mode 100644 diff --git a/clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Headers/Inferred.h b/clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Headers/Inferred.h new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Headers/Inferred.h @@ -0,0 +1 @@ +typedef int inferred; diff --git a/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Headers/System.h b/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Headers/System.h new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Headers/System.h @@ -0,0 +1 @@ +enum { bigger_than_int = 0x80000000 }; diff --git a/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Modules/module.modulemap b/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Modules/module.modulemap new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Modules/module.modulemap @@ -0,0 +1,3 @@ +framework module System [system] { + umbrella header "System.h" +} diff --git a/clang/test/ClangScanDeps/Inputs/frameworks/module.modulemap b/clang/test/ClangScanDeps/Inputs/frameworks/module.modulemap new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/frameworks/module.modulemap @@ -0,0 +1 @@ +framework module * {} diff --git a/clang/test/ClangScanDeps/Inputs/modules_inferred_cdb.json b/clang/test/ClangScanDeps/Inputs/modules_inferred_cdb.json new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/modules_inferred_cdb.json @@ -0,0 +1,7 @@ +[ +{ + "directory": "DIR", + "command": "clang -E DIR/modules_cdb_input.cpp -FFRAMEWORKS -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-modules -fimplicit-module-maps -pedantic -Werror", + "file": "DIR/modules_cdb_input.cpp" +} +] diff --git a/clang/test/ClangScanDeps/module-deps-to-rsp.py b/clang/test/ClangScanDeps/module-deps-to-rsp.py new file mode 100755 --- /dev/null +++ b/clang/test/ClangScanDeps/module-deps-to-rsp.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python + +import argparse +import json +import sys + +class ModuleNotFoundError(Exception): + def __init__(self, module_name): + self.module_name = module_name + +class FullDeps: + def __init__(self): + self.modules = dict() + self.translation_units = str() + +def getModulePathArgs(modules, full_deps): + cmd = [] + for md in modules: + m = full_deps.modules[md['module-name'] + '-' + md['context-hash']] + cmd += [u'-fmodule-map-file=' + m['clang-modulemap-file']] + cmd += [u'-fmodule-file=' + md['module-name'] + '-' + md['context-hash'] + '.pcm'] + return cmd + +def getCommandLineForModule(module_name, full_deps): + for m in full_deps.modules.values(): + if m['name'] == module_name: + module = m + break + else: + raise ModuleNotFoundError(module_name) + + cmd = m['command-line'] + cmd += getModulePathArgs(m['clang-module-deps'], full_deps) + cmd += [u'-o', m['name'] + '-' + m['context-hash'] + '.pcm'] + cmd += [m['clang-modulemap-file']] + + return cmd + +def getCommandLineForTU(tu, full_deps): + cmd = tu['command-line'] + cmd = [a for a in cmd if not (a.startswith('-fmodule-map-file=') or a.startswith('-fmodule-file='))] + cmd += getModulePathArgs(tu['clang-module-deps'], full_deps) + return cmd + +def parseFullDeps(json): + ret = FullDeps() + for m in json['modules']: + ret.modules[m['name'] + '-' + m['context-hash']] = m + ret.translation_units = json['translation-units'] + return ret + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("full_deps_file", help="Path to the full dependencies json file", + type=str) + action = parser.add_mutually_exclusive_group(required=True) + action.add_argument("--module-name", help="The name of the module to get arguments for", + type=str) + action.add_argument("--tu-index", help="The index of the translation unit to get arguments for", + type=int) + args = parser.parse_args() + + full_deps = parseFullDeps(json.load(open(args.full_deps_file, 'r'))) + + try: + if args.module_name: + print(" ".join(getCommandLineForModule(args.module_name, full_deps))) + + elif args.tu_index != None: + print(" ".join(getCommandLineForTU(full_deps.translation_units[args.tu_index], full_deps))) + except: + print("Unexpected error:", sys.exc_info()[0]) + raise + +if __name__ == '__main__': + main() diff --git a/clang/test/ClangScanDeps/modules-full.cpp b/clang/test/ClangScanDeps/modules-full.cpp --- a/clang/test/ClangScanDeps/modules-full.cpp +++ b/clang/test/ClangScanDeps/modules-full.cpp @@ -40,7 +40,6 @@ // CHECK-NEXT: "-cc1", // CHECK: "-fmodule-map-file=[[PREFIX]]/Inputs/module.modulemap", // CHECK: "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm", -// CHECK-NOT: "-fimplicit-module-maps", // CHECK: "-fno-implicit-modules", // CHECK: ], // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1]]", @@ -55,7 +54,6 @@ // CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap", // CHECK-NEXT: "command-line": [ // CHECK-NEXT: "-cc1", -// CHECK-NOT: "-fimplicit-module-maps", // CHECK: "-fno-implicit-modules", // CHECK: ], // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H2:[A-Z0-9]+]]", @@ -70,7 +68,6 @@ // CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/module.modulemap", // CHECK-NEXT: "command-line": [ // CHECK-NEXT: "-cc1", -// CHECK-NOT: "-fimplicit-module-maps", // CHECK: "-fno-implicit-modules", // CHECK: ], // CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1]]", diff --git a/clang/test/ClangScanDeps/modules-inferred-explicit-build.m b/clang/test/ClangScanDeps/modules-inferred-explicit-build.m new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/modules-inferred-explicit-build.m @@ -0,0 +1,22 @@ +// RUN: rm -rf %t.dir +// RUN: rm -rf %t.cdb +// RUN: mkdir -p %t.dir +// RUN: cp %s %t.dir/modules_cdb_input.cpp +// RUN: sed -e "s|DIR|%/t.dir|g" -e "s|FRAMEWORKS|%/S/Inputs/frameworks|g" -e "s|-E|-x objective-c -E|g" \ +// RUN: %S/Inputs/modules_inferred_cdb.json > %t.cdb +// +// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -format experimental-full \ +// RUN: -mode preprocess-minimized-sources > %t.db +// RUN: %S/module-deps-to-rsp.py %t.db --module-name=Inferred > %t.inferred.rsp +// RUN: %S/module-deps-to-rsp.py %t.db --module-name=System > %t.system.rsp +// RUN: %S/module-deps-to-rsp.py %t.db --tu-index=0 > %t.tu.rsp +// RUN: %clang @%t.inferred.rsp -pedantic -Werror +// RUN: %clang @%t.system.rsp -pedantic -Werror +// RUN: %clang -x objective-c -fsyntax-only %t.dir/modules_cdb_input.cpp \ +// RUN: -F%S/Inputs/frameworks -fmodules -fimplicit-module-maps \ +// RUN: -pedantic -Werror @%t.tu.rsp + +#include +#include + +inferred a = bigger_than_int; diff --git a/clang/test/ClangScanDeps/modules-inferred.m b/clang/test/ClangScanDeps/modules-inferred.m new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/modules-inferred.m @@ -0,0 +1,61 @@ +// RUN: rm -rf %t.dir +// RUN: rm -rf %t.cdb +// RUN: mkdir -p %t.dir +// RUN: cp %s %t.dir/modules_cdb_input.cpp +// RUN: sed -e "s|DIR|%/t.dir|g" -e "s|FRAMEWORKS|%S/Inputs/frameworks|g" \ +// RUN: %S/Inputs/modules_inferred_cdb.json > %t.cdb +// +// RUN: echo -%t.dir > %t.result +// RUN: echo -%S >> %t.result +// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -format experimental-full \ +// RUN: -mode preprocess-minimized-sources >> %t.result +// RUN: cat %t.result | sed 's/\\/\//g' | FileCheck --check-prefixes=CHECK %s + +#include + +inferred a = 0; + +// CHECK: -[[PREFIX:.*]] +// CHECK-NEXT: -[[SOURCEDIR:.*]] +// CHECK-NEXT: { +// CHECK-NEXT: "modules": [ +// CHECK-NEXT: { +// CHECK-NEXT: "clang-module-deps": [], +// CHECK-NEXT: "clang-modulemap-file": "[[SOURCEDIR]]/Inputs/frameworks/module.modulemap", +// CHECK-NEXT: "command-line": [ +// CHECK-NEXT: "-cc1", +// CHECK: "-emit-module", +// CHECK: "-fmodule-name=Inferred", +// CHECK: "-fno-implicit-modules", +// CHECK: ], +// CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1:[A-Z0-9]+]]", +// CHECK-NEXT: "file-deps": [ +// CHECK-NEXT: "[[SOURCEDIR]]/Inputs/frameworks/Inferred.framework/Frameworks/Sub.framework/Headers/Sub.h", +// CHECK-NEXT: "[[SOURCEDIR]]/Inputs/frameworks/Inferred.framework/Headers/Inferred.h", +// CHECK-NEXT: "[[SOURCEDIR]]/Inputs/frameworks/module.modulemap" +// CHECK-NEXT: ], +// CHECK-NEXT: "name": "Inferred" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "translation-units": [ +// CHECK-NEXT: { +// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH_H1]]", +// CHECK-NEXT: "clang-module-deps": [ +// CHECK-NEXT: { +// CHECK-NEXT: "context-hash": "[[CONTEXT_HASH_H1]]", +// CHECK-NEXT: "module-name": "Inferred" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "command-line": [ +// CHECK-NEXT: "-fno-implicit-modules", +// CHECK-NEXT: "-fno-implicit-module-maps", +// CHECK-NEXT: "-fmodule-file=[[PREFIX]]/module-cache/[[CONTEXT_HASH_H1]]/Inferred-{{[A-Z0-9]+}}.pcm", +// CHECK-NEXT: "-fmodule-map-file=[[SOURCEDIR]]/Inputs/frameworks/module.modulemap" +// CHECK-NEXT: ], +// CHECK-NEXT: "file-deps": [ +// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp" +// CHECK-NEXT: ], +// CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }