Index: clang/include/clang/Serialization/ASTReader.h =================================================================== --- clang/include/clang/Serialization/ASTReader.h +++ clang/include/clang/Serialization/ASTReader.h @@ -2338,8 +2338,7 @@ /// Visit all the top-level module maps loaded when building the given module /// file. void visitTopLevelModuleMaps(serialization::ModuleFile &MF, - llvm::function_ref< - void(const FileEntry *)> Visitor); + llvm::function_ref Visitor); bool isProcessingUpdateRecords() { return ProcessingUpdateRecords; } }; Index: clang/lib/Frontend/FrontendAction.cpp =================================================================== --- clang/lib/Frontend/FrontendAction.cpp +++ clang/lib/Frontend/FrontendAction.cpp @@ -639,9 +639,9 @@ CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName); ASTReader->visitTopLevelModuleMaps( - PrimaryModule, [&](const FileEntry *FE) { + PrimaryModule, [&](FileEntryRef FE) { CI.getFrontendOpts().ModuleMapFiles.push_back( - std::string(FE->getName())); + std::string(FE.getName())); }); } Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -9164,14 +9164,14 @@ void ASTReader::visitTopLevelModuleMaps( serialization::ModuleFile &MF, - llvm::function_ref Visitor) { + llvm::function_ref Visitor) { unsigned NumInputs = MF.InputFilesLoaded.size(); for (unsigned I = 0; I < NumInputs; ++I) { InputFileInfo IFI = readInputFileInfo(MF, I + 1); if (IFI.TopLevelModuleMap) // FIXME: This unnecessarily re-reads the InputFileInfo. if (auto FE = getInputFile(MF, I + 1).getFile()) - Visitor(FE); + Visitor(*FE); } } Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -1486,12 +1486,14 @@ /// An input file. struct InputFileEntry { - const FileEntry *File; + FileEntryRef File; bool IsSystemFile; bool IsTransient; bool BufferOverridden; bool IsTopLevelModuleMap; uint32_t ContentHash[2]; + + InputFileEntry(FileEntryRef File) : File(File) {} }; } // namespace @@ -1541,8 +1543,7 @@ if (!IsSLocAffecting[I]) continue; - InputFileEntry Entry; - Entry.File = Cache->OrigEntry; + InputFileEntry Entry(*Cache->OrigEntry); Entry.IsSystemFile = isSystem(File.getFileCharacteristic()); Entry.IsTransient = Cache->IsTransient; Entry.BufferOverridden = Cache->BufferOverridden; @@ -1559,7 +1560,7 @@ else // FIXME: The path should be taken from the FileEntryRef. PP->Diag(SourceLocation(), diag::err_module_unable_to_hash_content) - << Entry.File->getName(); + << Entry.File.getName(); } auto CH = llvm::APInt(64, ContentHash); Entry.ContentHash[0] = @@ -1599,14 +1600,13 @@ RecordData::value_type Record[] = { INPUT_FILE, InputFileOffsets.size(), - (uint64_t)Entry.File->getSize(), + (uint64_t)Entry.File.getSize(), (uint64_t)getTimestampForOutput(Entry.File), Entry.BufferOverridden, Entry.IsTransient, Entry.IsTopLevelModuleMap}; - // FIXME: The path should be taken from the FileEntryRef. - EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName()); + EmitRecordWithPath(IFAbbrevCode, Record, Entry.File.getName()); } // Emit content hash for this file. Index: clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -447,10 +447,10 @@ addAllAffectingClangModules(M, MD, SeenDeps); MDC.ScanInstance.getASTReader()->visitTopLevelModuleMaps( - *MF, [&](const FileEntry *FE) { - if (FE->getName().endswith("__inferred_module.map")) + *MF, [&](FileEntryRef FE) { + if (FE.getName().endswith("__inferred_module.map")) return; - MD.ModuleMapFileDeps.emplace_back(FE->getName()); + MD.ModuleMapFileDeps.emplace_back(FE.getName()); }); CompilerInvocation CI = MDC.makeInvocationForModuleBuildWithoutOutputs( Index: clang/test/ClangScanDeps/modules-symlink-dir-from-module.c =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/modules-symlink-dir-from-module.c @@ -0,0 +1,94 @@ +// Check that the path of an imported modulemap file is not influenced by +// modules outside that module's dependency graph. Specifically, the "Foo" +// module below does not transitively import Mod via a symlink, so it should not +// see the symlinked path. + +// REQUIRES: shell + +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.in > %t/cdb.json +// RUN: ln -s module %t/include/symlink-to-module + +// RUN: clang-scan-deps -compilation-database %t/cdb.json -j 1 \ +// RUN: -format experimental-full -mode=preprocess-dependency-directives \ +// RUN: -optimize-args -module-files-dir %t/build > %t/deps.json + +// RUN: cat %t/deps.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t + +// CHECK: "modules": [ +// CHECK: { +// CHECK: "command-line": [ +// CHECK: "-fmodule-map-file=[[PREFIX]]/include/module/module.modulemap" +// CHECK: ] +// CHECK: "name": "Foo" +// CHECK: } +// CHECK: { +// CHECK: "command-line": [ +// FIXME: canonicalize this path +// CHECK: "-fmodule-map-file=[[PREFIX]]/include/symlink-to-module/module.modulemap" +// CHECK: ] +// CHECK: "name": "Foo_Private" +// CHECK: } +// CHECK: { +// CHECK: "command-line": [ +// CHECK: "[[PREFIX]]/include/module/module.modulemap" +// CHECK: ] +// CHECK: "name": "Mod" +// CHECK: } +// CHECK: { +// CHECK: "command-line": [ +// FIXME: canonicalize this path +// CHECK: "-fmodule-map-file=[[PREFIX]]/include/symlink-to-module/module.modulemap" +// CHECK: ] +// CHECK: "name": "Other" +// CHECK: } +// CHECK: { +// CHECK: "command-line": [ +// FIXME: canonicalize this path +// CHECK: "-fmodule-map-file=[[PREFIX]]/include/symlink-to-module/module.modulemap" +// CHECK: ] +// CHECK: "name": "Test" +// CHECK: } +// CHECK: ] + +//--- cdb.json.in +[{ + "directory": "DIR", + "command": "clang -fsyntax-only DIR/test.c -F DIR/Frameworks -I DIR/include -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/module-cache", + "file": "DIR/test.c" +}] + +//--- include/module/module.modulemap +module Mod { header "mod.h" export * } + +//--- include/module/mod.h + +//--- include/module.modulemap +module Other { header "other.h" export * } + +//--- include/other.h +#include "symlink-to-module/mod.h" +#include "module/mod.h" + +//--- Frameworks/Foo.framework/Modules/module.modulemap +framework module Foo { header "Foo.h" export * } +//--- Frameworks/Foo.framework/Modules/module.private.modulemap +framework module Foo_Private { header "Priv.h" export * } + +//--- Frameworks/Foo.framework/Headers/Foo.h +#include "module/mod.h" + +//--- Frameworks/Foo.framework/PrivateHeaders/Priv.h +#include +#include "other.h" + +//--- module.modulemap +module Test { header "test.h" export * } + +//--- test.h +#include +#include + +//--- test.c +#include "test.h"