https://github.com/cyndyishida updated 
https://github.com/llvm/llvm-project/pull/130634

>From aca254a154489fda68292f6d06a866ae7011a7f6 Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ish...@apple.com>
Date: Mon, 10 Mar 2025 09:06:32 -0700
Subject: [PATCH 1/4] [clang][DependencyScanning] Track modules that resolve
 from sysroot.

That patch tracks whether all the file & module dependencies of a module
resolve to a sysroot location. This information will later be queried by
build systems for determining where to store the accompanying pcms.
---
 .../DependencyScanning/ModuleDepCollector.h   |   7 ++
 .../DependencyScanning/ModuleDepCollector.cpp |  25 +++-
 clang/test/ClangScanDeps/modules-in-sysroot.c | 107 ++++++++++++++++++
 clang/tools/clang-scan-deps/ClangScanDeps.cpp |   2 +
 4 files changed, 139 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/ClangScanDeps/modules-in-sysroot.c

diff --git 
a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h 
b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index 20fb4de6a2a73..6187f0168e6d9 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -114,6 +114,10 @@ struct ModuleDeps {
   /// Whether this is a "system" module.
   bool IsSystem;
 
+  /// Whether this is a module where it's dependencies resolve within the
+  /// sysroot.
+  bool IsInSysroot;
+
   /// The path to the modulemap file which defines this module.
   ///
   /// This can be used to explicitly build this module. This file will
@@ -219,6 +223,9 @@ class ModuleDepCollectorPP final : public PPCallbacks {
                               llvm::DenseSet<const Module *> &AddedModules);
   void addAffectingClangModule(const Module *M, ModuleDeps &MD,
                           llvm::DenseSet<const Module *> &AddedModules);
+
+  /// Add discovered module dependency for the given module.
+  void addClangModule(const Module *M, const ModuleID ID, ModuleDeps &MD);
 };
 
 /// Collects modular and non-modular dependencies of the main file by attaching
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp 
b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index 36b75c1016cd8..86eda34472cf0 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -698,6 +698,15 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module 
*M) {
 
   MD.ID.ModuleName = M->getFullModuleName();
   MD.IsSystem = M->IsSystem;
+
+  // Start off with the assumption that this module is in the sysroot when 
there
+  // is a sysroot provided. As more dependencies are discovered, check if those
+  // come from the provided sysroot.
+  const StringRef CurrSysroot = MDC.ScanInstance.getHeaderSearchOpts().Sysroot;
+  MD.IsInSysroot =
+      !CurrSysroot.empty() &&
+      (llvm::sys::path::root_directory(CurrSysroot) != CurrSysroot);
+
   // For modules which use export_as link name, the linked product that of the
   // corresponding export_as-named module.
   if (!M->UseExportAsModuleLinkName)
@@ -739,6 +748,11 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module 
*M) {
   MDC.ScanInstance.getASTReader()->visitInputFileInfos(
       *MF, /*IncludeSystem=*/true,
       [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
+        auto FullFilePath = ASTReader::ResolveImportedPath(
+            PathBuf, IFI.UnresolvedImportedFilename, MF->BaseDirectory);
+        if (MD.IsInSysroot)
+          MD.IsInSysroot = FullFilePath->starts_with(CurrSysroot);
+        PathBuf.resize_for_overwrite(256);
         if (!(IFI.TopLevel && IFI.ModuleMap))
           return;
         if (IFI.UnresolvedImportedFilenameAsRequested.ends_with(
@@ -835,6 +849,13 @@ void ModuleDepCollectorPP::addAllSubmoduleDeps(
   });
 }
 
+void ModuleDepCollectorPP::addClangModule(const Module *M, const ModuleID ID,
+                                          ModuleDeps &MD) {
+  MD.ClangModuleDeps.push_back(ID);
+  if (MD.IsInSysroot)
+    MD.IsInSysroot = MDC.ModularDeps[M]->IsInSysroot;
+}
+
 void ModuleDepCollectorPP::addModuleDep(
     const Module *M, ModuleDeps &MD,
     llvm::DenseSet<const Module *> &AddedModules) {
@@ -843,7 +864,7 @@ void ModuleDepCollectorPP::addModuleDep(
         !MDC.isPrebuiltModule(Import)) {
       if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
         if (AddedModules.insert(Import->getTopLevelModule()).second)
-          MD.ClangModuleDeps.push_back(*ImportID);
+          addClangModule(Import->getTopLevelModule(), *ImportID, MD);
     }
   }
 }
@@ -867,7 +888,7 @@ void ModuleDepCollectorPP::addAffectingClangModule(
         !MDC.isPrebuiltModule(Affecting)) {
       if (auto ImportID = handleTopLevelModule(Affecting))
         if (AddedModules.insert(Affecting).second)
-          MD.ClangModuleDeps.push_back(*ImportID);
+          addClangModule(Affecting, *ImportID, MD);
     }
   }
 }
diff --git a/clang/test/ClangScanDeps/modules-in-sysroot.c 
b/clang/test/ClangScanDeps/modules-in-sysroot.c
new file mode 100644
index 0000000000000..d96aa69c0e8f4
--- /dev/null
+++ b/clang/test/ClangScanDeps/modules-in-sysroot.c
@@ -0,0 +1,107 @@
+// This test verifies modules that are entirely comprised from sysroot inputs 
are captured in
+// dependency information.
+
+// The first compilation verifies that transitive dependencies on non-sysroot 
input are captured.
+// The second compilation verifies that external paths are resolved when a 
vfsoverlay is applied when considering sysroot-ness.
+
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s|DIR|%/t|g" %t/compile-commands.json.in > 
%t/compile-commands.json
+// RUN: sed -e "s|DIR|%/t|g" %t/overlay.json.template > %t/overlay.json
+// RUN: clang-scan-deps -compilation-database %t/compile-commands.json \
+// RUN:   -j 1 -format experimental-full > %t/deps.db
+// RUN: cat %t/deps.db | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t
+
+// CHECK:   "modules": [
+// CHECK-NEXT:     {
+// CHECK:            "is-in-sysroot": true,
+// CHECK:            "name": "A"
+
+// Verify that there are no more occurances of sysroot.
+// CHECK-NOT:            "is-in-sysroot"
+
+// CHECK:            "name": "A"
+// CHECK:            "USE_VFS"
+// CHECK:            "name": "B"
+// CHECK:            "name": "C"
+// CHECK:            "name": "D"
+// CHECK:            "name": "NotInSDK"
+
+//--- compile-commands.json.in
+[
+{
+  "directory": "DIR",
+  "command": "clang -c DIR/client.m -isysroot DIR/MacOSX.sdk -I DIR/BuildDir 
-fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
+  "file": "DIR/client.m"
+},
+{
+  "directory": "DIR",
+  "command": "clang -c DIR/client.m -isysroot DIR/MacOSX.sdk  -ivfsoverlay 
DIR/overlay.json -DUSE_VFS -I DIR/BuildDir -fmodules 
-fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
+  "file": "DIR/client.m"
+}
+]
+
+//--- overlay.json.template
+{
+  "version": 0,
+  "case-sensitive": "false",
+  "roots": [
+    {
+          "external-contents": "DIR/local/A/A_vfs.h",
+          "name": "DIR/MacOSX.sdk/usr/include/A/A_vfs.h",
+          "type": "file"
+    }
+  ]
+}
+
+//--- MacOSX.sdk/usr/include/A/module.modulemap
+module A {
+  umbrella "."
+}
+
+//--- MacOSX.sdk/usr/include/A/A.h
+#ifdef USE_VFS
+#include <A/A_vfs.h>
+#endif 
+typedef int A_t;
+
+//--- local/A/A_vfs.h
+typedef int typeFromVFS;
+
+//--- MacOSX.sdk/usr/include/B/module.modulemap
+module B [system] {
+  umbrella "."
+}
+
+//--- MacOSX.sdk/usr/include/B/B.h
+#include <C/C.h>
+typedef int B_t;
+
+//--- MacOSX.sdk/usr/include/C/module.modulemap
+module C [system] {
+  umbrella "."
+}
+
+//--- MacOSX.sdk/usr/include/C/C.h
+#include <D/D.h>
+
+//--- MacOSX.sdk/usr/include/D/module.modulemap
+module D [system] {
+  umbrella "."
+}
+
+// Simulate a header that will be resolved in a local directory, from a 
sysroot header.
+//--- MacOSX.sdk/usr/include/D/D.h
+#include <HeaderNotFoundInSDK.h>
+
+//--- BuildDir/module.modulemap
+module NotInSDK [system] {
+  umbrella "."
+}
+
+//--- BuildDir/HeaderNotFoundInSDK.h
+typedef int local_t;
+
+//--- client.m
+#include <A/A.h>
+#include <B/B.h>
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp 
b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 3bdeb461e4bfa..f5946b30fb84d 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -471,6 +471,8 @@ class FullDeps {
         for (auto &&ModID : ModuleIDs) {
           auto &MD = Modules[ModID];
           JOS.object([&] {
+            if (MD.IsInSysroot)
+              JOS.attribute("is-in-sysroot", MD.IsInSysroot);
             JOS.attributeArray("clang-module-deps",
                                toJSONSorted(JOS, MD.ClangModuleDeps));
             JOS.attribute("clang-modulemap-file",

>From fd4abaa6c8097694fe1fad2510beb6b11653f01f Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ish...@apple.com>
Date: Mon, 10 Mar 2025 13:39:42 -0700
Subject: [PATCH 2/4] Add explicit search paths into SDK as they aren't passed
 with non-darwin targets

---
 clang/test/ClangScanDeps/modules-in-sysroot.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/clang/test/ClangScanDeps/modules-in-sysroot.c 
b/clang/test/ClangScanDeps/modules-in-sysroot.c
index d96aa69c0e8f4..2ecf9c293b23d 100644
--- a/clang/test/ClangScanDeps/modules-in-sysroot.c
+++ b/clang/test/ClangScanDeps/modules-in-sysroot.c
@@ -4,6 +4,7 @@
 // The first compilation verifies that transitive dependencies on non-sysroot 
input are captured.
 // The second compilation verifies that external paths are resolved when a 
vfsoverlay is applied when considering sysroot-ness.
 
+// REQUIRES: shell
 // RUN: rm -rf %t
 // RUN: split-file %s %t
 // RUN: sed -e "s|DIR|%/t|g" %t/compile-commands.json.in > 
%t/compile-commands.json
@@ -31,13 +32,13 @@
 [
 {
   "directory": "DIR",
-  "command": "clang -c DIR/client.m -isysroot DIR/MacOSX.sdk -I DIR/BuildDir 
-fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
-  "file": "DIR/client.m"
+  "command": "clang -c DIR/client.c -isysroot DIR/MacOSX.sdk 
-IDIR/MacOSX.sdk/usr/include -IDIR/BuildDir -fmodules 
-fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
+  "file": "DIR/client.c"
 },
 {
   "directory": "DIR",
-  "command": "clang -c DIR/client.m -isysroot DIR/MacOSX.sdk  -ivfsoverlay 
DIR/overlay.json -DUSE_VFS -I DIR/BuildDir -fmodules 
-fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
-  "file": "DIR/client.m"
+  "command": "clang -c DIR/client.c -isysroot DIR/MacOSX.sdk 
-IDIR/MacOSX.sdk/usr/include -ivfsoverlay DIR/overlay.json -DUSE_VFS 
-IDIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache 
-fimplicit-module-maps",
+  "file": "DIR/client.c"
 }
 ]
 
@@ -102,6 +103,6 @@ module NotInSDK [system] {
 //--- BuildDir/HeaderNotFoundInSDK.h
 typedef int local_t;
 
-//--- client.m
+//--- client.c
 #include <A/A.h>
 #include <B/B.h>

>From 032d7f84a0bf3647dba8633993ed1cbf1653b0bc Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ish...@apple.com>
Date: Thu, 13 Mar 2025 23:27:12 -0700
Subject: [PATCH 3/4] Address review comments except for prebuilt module
 dependencies

---
 .../Tooling/DependencyScanning/ModuleDepCollector.h      | 8 ++++++--
 .../Tooling/DependencyScanning/ModuleDepCollector.cpp    | 9 +++++----
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git 
a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h 
b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index 6187f0168e6d9..b0eed8a85a9c6 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -114,8 +114,12 @@ struct ModuleDeps {
   /// Whether this is a "system" module.
   bool IsSystem;
 
-  /// Whether this is a module where it's dependencies resolve within the
-  /// sysroot.
+  /// Whether this module is fully composed of file & module inputs from the
+  /// sysroot. External paths, as opposed to virtual file paths, are always 
used
+  /// for computing this value.
+  ///
+  /// This attribute is useful for identifying modules that are unlikely to
+  /// change under an active development and build cycle.
   bool IsInSysroot;
 
   /// The path to the modulemap file which defines this module.
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp 
b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index 86eda34472cf0..2f9939d4ac3c8 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -748,11 +748,12 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module 
*M) {
   MDC.ScanInstance.getASTReader()->visitInputFileInfos(
       *MF, /*IncludeSystem=*/true,
       [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
-        auto FullFilePath = ASTReader::ResolveImportedPath(
-            PathBuf, IFI.UnresolvedImportedFilename, MF->BaseDirectory);
-        if (MD.IsInSysroot)
+        if (MD.IsInSysroot) {
+          auto FullFilePath = ASTReader::ResolveImportedPath(
+              PathBuf, IFI.UnresolvedImportedFilename, MF->BaseDirectory);
           MD.IsInSysroot = FullFilePath->starts_with(CurrSysroot);
-        PathBuf.resize_for_overwrite(256);
+          PathBuf.resize_for_overwrite(256);
+        }
         if (!(IFI.TopLevel && IFI.ModuleMap))
           return;
         if (IFI.UnresolvedImportedFilenameAsRequested.ends_with(

>From 175e9ce016dbcef19de98bfdc5d82118fca72592 Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ish...@apple.com>
Date: Fri, 14 Mar 2025 18:00:16 -0700
Subject: [PATCH 4/4] Update IsInSysroot -> IsShareable

* We need to track more than just sysroot, so start with sysroot and
  resource directory as a starting point, but allow the ability to
capture more as they are discovered in the future.

* Check a subset of the compiler invocation of module compilations for
  determining if a module can be shared.
* When a module has a prebuilt module dependency, consider is not
  shareable for now.
---
 .../DependencyScanning/ModuleDepCollector.h   |  20 +--
 .../DependencyScanning/ModuleDepCollector.cpp |  86 ++++++++++---
 ...-in-sysroot.c => modules-in-shared-dirs.c} |  37 +++---
 .../prebuilt-modules-in-shared-dirs.c         | 114 ++++++++++++++++++
 clang/tools/clang-scan-deps/ClangScanDeps.cpp |   4 +-
 5 files changed, 219 insertions(+), 42 deletions(-)
 rename clang/test/ClangScanDeps/{modules-in-sysroot.c => 
modules-in-shared-dirs.c} (63%)
 create mode 100644 clang/test/ClangScanDeps/prebuilt-modules-in-shared-dirs.c

diff --git 
a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h 
b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index b0eed8a85a9c6..cab4c6771666e 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -114,13 +114,13 @@ struct ModuleDeps {
   /// Whether this is a "system" module.
   bool IsSystem;
 
-  /// Whether this module is fully composed of file & module inputs from the
-  /// sysroot. External paths, as opposed to virtual file paths, are always 
used
-  /// for computing this value.
+  /// Whether this module is fully composed of file & module inputs from
+  /// locations likely to stay the same across the active development and build
+  /// cycle. For example, when all those input paths only resolve in Sysroot.
   ///
-  /// This attribute is useful for identifying modules that are unlikely to
-  /// change under an active development and build cycle.
-  bool IsInSysroot;
+  /// External paths, as opposed to virtual file paths, are always used
+  /// for computing this value.
+  bool IsShareable;
 
   /// The path to the modulemap file which defines this module.
   ///
@@ -229,7 +229,7 @@ class ModuleDepCollectorPP final : public PPCallbacks {
                           llvm::DenseSet<const Module *> &AddedModules);
 
   /// Add discovered module dependency for the given module.
-  void addClangModule(const Module *M, const ModuleID ID, ModuleDeps &MD);
+  void addOneModuleDep(const Module *M, const ModuleID ID, ModuleDeps &MD);
 };
 
 /// Collects modular and non-modular dependencies of the main file by attaching
@@ -331,6 +331,12 @@ void resetBenignCodeGenOptions(frontend::ActionKind 
ProgramAction,
                                const LangOptions &LangOpts,
                                CodeGenOptions &CGOpts);
 
+/// Determine if \c Input can be resolved within a shared location.
+///
+/// \param Directories Paths known to be in a shared location. e.g. Sysroot.
+/// \param Input Path to evaluate.
+bool isPathInSharedDir(ArrayRef<StringRef> Directories, const StringRef Input);
+
 } // end namespace dependencies
 } // end namespace tooling
 } // end namespace clang
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp 
b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index 2f9939d4ac3c8..05ca7718cb99e 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -157,6 +157,32 @@ static void optimizeCWD(CowCompilerInvocation 
&BuildInvocation, StringRef CWD) {
   }
 }
 
+/// Check a subset of invocation options to determine whether the current
+/// context can safely be considered as shareable.
+static bool areOptionsInSharedDir(CowCompilerInvocation &BuildInvocation,
+                                  const ArrayRef<StringRef> SharedDirs) {
+  const auto &HSOpts = BuildInvocation.getHeaderSearchOpts();
+  if (!isPathInSharedDir(SharedDirs, HSOpts.Sysroot))
+    return false;
+
+  if (!isPathInSharedDir(SharedDirs, HSOpts.ResourceDir))
+    return false;
+
+  for (const auto &Entry : HSOpts.UserEntries) {
+    if (!Entry.IgnoreSysRoot)
+      continue;
+    if (!isPathInSharedDir(SharedDirs, Entry.Path))
+      return false;
+  }
+
+  for (const auto &SysPrefix : HSOpts.SystemHeaderPrefixes) {
+    if (!isPathInSharedDir(SharedDirs, SysPrefix.Prefix))
+      return false;
+  }
+
+  return true;
+}
+
 static std::vector<std::string> splitString(std::string S, char Separator) {
   SmallVector<StringRef> Segments;
   StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, 
/*KeepEmpty=*/false);
@@ -212,6 +238,25 @@ void 
dependencies::resetBenignCodeGenOptions(frontend::ActionKind ProgramAction,
   }
 }
 
+bool dependencies::isPathInSharedDir(ArrayRef<StringRef> Directories,
+                                     const StringRef Input) {
+  auto PathStartsWith = [](StringRef Prefix, StringRef Path) {
+    auto PrefixIt = llvm::sys::path::begin(Prefix),
+         PrefixEnd = llvm::sys::path::end(Prefix);
+    for (auto PathIt = llvm::sys::path::begin(Path),
+              PathEnd = llvm::sys::path::end(Path);
+         PrefixIt != PrefixEnd && PathIt != PathEnd; ++PrefixIt, ++PathIt) {
+      if (*PrefixIt != *PathIt)
+        return false;
+    }
+    return PrefixIt == PrefixEnd;
+  };
+
+  return any_of(Directories, [&](StringRef Dir) {
+    return !Dir.empty() && PathStartsWith(Dir, Input);
+  });
+}
+
 static CowCompilerInvocation
 makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
   CI.resetNonModularOptions();
@@ -699,13 +744,15 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module 
*M) {
   MD.ID.ModuleName = M->getFullModuleName();
   MD.IsSystem = M->IsSystem;
 
-  // Start off with the assumption that this module is in the sysroot when 
there
+  // Start off with the assumption that this module is shareable when there
   // is a sysroot provided. As more dependencies are discovered, check if those
-  // come from the provided sysroot.
-  const StringRef CurrSysroot = MDC.ScanInstance.getHeaderSearchOpts().Sysroot;
-  MD.IsInSysroot =
-      !CurrSysroot.empty() &&
-      (llvm::sys::path::root_directory(CurrSysroot) != CurrSysroot);
+  // come from the provided shared directories.
+  const llvm::SmallVector<StringRef> SharedDirs = {
+      MDC.ScanInstance.getHeaderSearchOpts().Sysroot,
+      MDC.ScanInstance.getHeaderSearchOpts().ResourceDir};
+  MD.IsShareable =
+      !SharedDirs[0].empty() &&
+      (llvm::sys::path::root_directory(SharedDirs[0]) != SharedDirs[0]);
 
   // For modules which use export_as link name, the linked product that of the
   // corresponding export_as-named module.
@@ -748,10 +795,10 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module 
*M) {
   MDC.ScanInstance.getASTReader()->visitInputFileInfos(
       *MF, /*IncludeSystem=*/true,
       [&](const serialization::InputFileInfo &IFI, bool IsSystem) {
-        if (MD.IsInSysroot) {
+        if (MD.IsShareable) {
           auto FullFilePath = ASTReader::ResolveImportedPath(
               PathBuf, IFI.UnresolvedImportedFilename, MF->BaseDirectory);
-          MD.IsInSysroot = FullFilePath->starts_with(CurrSysroot);
+          MD.IsShareable = isPathInSharedDir(SharedDirs, *FullFilePath);
           PathBuf.resize_for_overwrite(256);
         }
         if (!(IFI.TopLevel && IFI.ModuleMap))
@@ -795,6 +842,10 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module 
*M) {
             }
           });
 
+  // Check provided input paths from the invocation for determining 
IsShareable.
+  if (MD.IsShareable)
+    MD.IsShareable = areOptionsInSharedDir(CI, SharedDirs);
+
   MDC.associateWithContextHash(CI, IgnoreCWD, MD);
 
   // Finish the compiler invocation. Requires dependencies and the context 
hash.
@@ -836,8 +887,13 @@ void ModuleDepCollectorPP::addModulePrebuiltDeps(
   for (const Module *Import : M->Imports)
     if (Import->getTopLevelModule() != M->getTopLevelModule())
       if (MDC.isPrebuiltModule(Import->getTopLevelModule()))
-        if (SeenSubmodules.insert(Import->getTopLevelModule()).second)
+        if (SeenSubmodules.insert(Import->getTopLevelModule()).second) {
           MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule());
+          // Conservatively consider the module as not shareable,
+          // as transitive dependencies from the prebuilt module have not been
+          // determined.
+          MD.IsShareable = false;
+        }
 }
 
 void ModuleDepCollectorPP::addAllSubmoduleDeps(
@@ -850,11 +906,11 @@ void ModuleDepCollectorPP::addAllSubmoduleDeps(
   });
 }
 
-void ModuleDepCollectorPP::addClangModule(const Module *M, const ModuleID ID,
-                                          ModuleDeps &MD) {
+void ModuleDepCollectorPP::addOneModuleDep(const Module *M, const ModuleID ID,
+                                           ModuleDeps &MD) {
   MD.ClangModuleDeps.push_back(ID);
-  if (MD.IsInSysroot)
-    MD.IsInSysroot = MDC.ModularDeps[M]->IsInSysroot;
+  if (MD.IsShareable)
+    MD.IsShareable = MDC.ModularDeps[M]->IsShareable;
 }
 
 void ModuleDepCollectorPP::addModuleDep(
@@ -865,7 +921,7 @@ void ModuleDepCollectorPP::addModuleDep(
         !MDC.isPrebuiltModule(Import)) {
       if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
         if (AddedModules.insert(Import->getTopLevelModule()).second)
-          addClangModule(Import->getTopLevelModule(), *ImportID, MD);
+          addOneModuleDep(Import->getTopLevelModule(), *ImportID, MD);
     }
   }
 }
@@ -889,7 +945,7 @@ void ModuleDepCollectorPP::addAffectingClangModule(
         !MDC.isPrebuiltModule(Affecting)) {
       if (auto ImportID = handleTopLevelModule(Affecting))
         if (AddedModules.insert(Affecting).second)
-          addClangModule(Affecting, *ImportID, MD);
+          addOneModuleDep(Affecting, *ImportID, MD);
     }
   }
 }
diff --git a/clang/test/ClangScanDeps/modules-in-sysroot.c 
b/clang/test/ClangScanDeps/modules-in-shared-dirs.c
similarity index 63%
rename from clang/test/ClangScanDeps/modules-in-sysroot.c
rename to clang/test/ClangScanDeps/modules-in-shared-dirs.c
index 2ecf9c293b23d..bce927f866268 100644
--- a/clang/test/ClangScanDeps/modules-in-sysroot.c
+++ b/clang/test/ClangScanDeps/modules-in-shared-dirs.c
@@ -1,8 +1,9 @@
-// This test verifies modules that are entirely comprised from sysroot inputs 
are captured in
+// This test verifies modules that are entirely comprised from shared 
directory inputs are captured in
 // dependency information.
 
-// The first compilation verifies that transitive dependencies on non-sysroot 
input are captured.
-// The second compilation verifies that external paths are resolved when a 
vfsoverlay is applied when considering sysroot-ness.
+// The first compilation verifies that transitive dependencies on local input 
are captured.
+// The second compilation verifies that external paths are resolved when a 
+// vfsoverlay for determining is-shareable.
 
 // REQUIRES: shell
 // RUN: rm -rf %t
@@ -15,11 +16,11 @@
 
 // CHECK:   "modules": [
 // CHECK-NEXT:     {
-// CHECK:            "is-in-sysroot": true,
+// CHECK:            "is-shareable": true,
 // CHECK:            "name": "A"
 
 // Verify that there are no more occurances of sysroot.
-// CHECK-NOT:            "is-in-sysroot"
+// CHECK-NOT:            "is-shareable"
 
 // CHECK:            "name": "A"
 // CHECK:            "USE_VFS"
@@ -32,12 +33,12 @@
 [
 {
   "directory": "DIR",
-  "command": "clang -c DIR/client.c -isysroot DIR/MacOSX.sdk 
-IDIR/MacOSX.sdk/usr/include -IDIR/BuildDir -fmodules 
-fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
+  "command": "clang -c DIR/client.c -isysroot DIR/Sysroot 
-IDIR/Sysroot/usr/include -IDIR/BuildDir -fmodules 
-fmodules-cache-path=DIR/module-cache -fimplicit-module-maps",
   "file": "DIR/client.c"
 },
 {
   "directory": "DIR",
-  "command": "clang -c DIR/client.c -isysroot DIR/MacOSX.sdk 
-IDIR/MacOSX.sdk/usr/include -ivfsoverlay DIR/overlay.json -DUSE_VFS 
-IDIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache 
-fimplicit-module-maps",
+  "command": "clang -c DIR/client.c -isysroot DIR/Sysroot 
-IDIR/Sysroot/usr/include -ivfsoverlay DIR/overlay.json -DUSE_VFS 
-IDIR/BuildDir -fmodules -fmodules-cache-path=DIR/module-cache 
-fimplicit-module-maps",
   "file": "DIR/client.c"
 }
 ]
@@ -48,51 +49,51 @@
   "case-sensitive": "false",
   "roots": [
     {
-          "external-contents": "DIR/local/A/A_vfs.h",
-          "name": "DIR/MacOSX.sdk/usr/include/A/A_vfs.h",
+          "external-contents": "DIR/SysrootButNotReally/A/A_vfs.h",
+          "name": "DIR/Sysroot/usr/include/A/A_vfs.h",
           "type": "file"
     }
   ]
 }
 
-//--- MacOSX.sdk/usr/include/A/module.modulemap
+//--- Sysroot/usr/include/A/module.modulemap
 module A {
   umbrella "."
 }
 
-//--- MacOSX.sdk/usr/include/A/A.h
+//--- Sysroot/usr/include/A/A.h
 #ifdef USE_VFS
 #include <A/A_vfs.h>
 #endif 
 typedef int A_t;
 
-//--- local/A/A_vfs.h
+//--- SysrootButNotReally/A/A_vfs.h
 typedef int typeFromVFS;
 
-//--- MacOSX.sdk/usr/include/B/module.modulemap
+//--- Sysroot/usr/include/B/module.modulemap
 module B [system] {
   umbrella "."
 }
 
-//--- MacOSX.sdk/usr/include/B/B.h
+//--- Sysroot/usr/include/B/B.h
 #include <C/C.h>
 typedef int B_t;
 
-//--- MacOSX.sdk/usr/include/C/module.modulemap
+//--- Sysroot/usr/include/C/module.modulemap
 module C [system] {
   umbrella "."
 }
 
-//--- MacOSX.sdk/usr/include/C/C.h
+//--- Sysroot/usr/include/C/C.h
 #include <D/D.h>
 
-//--- MacOSX.sdk/usr/include/D/module.modulemap
+//--- Sysroot/usr/include/D/module.modulemap
 module D [system] {
   umbrella "."
 }
 
 // Simulate a header that will be resolved in a local directory, from a 
sysroot header.
-//--- MacOSX.sdk/usr/include/D/D.h
+//--- Sysroot/usr/include/D/D.h
 #include <HeaderNotFoundInSDK.h>
 
 //--- BuildDir/module.modulemap
diff --git a/clang/test/ClangScanDeps/prebuilt-modules-in-shared-dirs.c 
b/clang/test/ClangScanDeps/prebuilt-modules-in-shared-dirs.c
new file mode 100644
index 0000000000000..dc133bb376850
--- /dev/null
+++ b/clang/test/ClangScanDeps/prebuilt-modules-in-shared-dirs.c
@@ -0,0 +1,114 @@
+/// This test validates that modules that depend on prebuilt modules resolve 
`is-shareable` as false.
+ 
+// REQUIRES: shell
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s|DIR|%/t|g" %t/overlay.json.template > %t/overlay.json
+// RUN: sed -e "s|DIR|%/t|g" %t/compile-pch.json.in > %t/compile-pch.json
+// RUN: clang-scan-deps -compilation-database %t/compile-pch.json \
+// RUN:   -j 1 -format experimental-full > %t/deps_pch.db
+// RUN: %clang -x c-header -c %t/prebuild.h -isysroot %t/MacOSX.sdk \
+// RUN:   -I%t/BuildDir -ivfsoverlay %t/overlay.json \
+// RUN:   -I %t/MacOSX.sdk/usr/include -fmodules 
-fmodules-cache-path=%t/module-cache \
+// RUN:   -fimplicit-module-maps -o %t/prebuild.pch
+// RUN: sed -e "s|DIR|%/t|g" %t/compile-commands.json.in > 
%t/compile-commands.json
+// RUN: clang-scan-deps -compilation-database %t/compile-commands.json \
+// RUN:   -j 1 -format experimental-full > %t/deps.db
+// RUN: cat %t/deps_pch.db | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t 
--check-prefix PCH_DEP
+// RUN: cat %t/deps.db | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t 
+
+// PCH_DEP: "is-shareable": true
+// PCH_DEP: "name": "A"
+ 
+// Verify is-shareable is not in any module dependencies, as they all depend 
on prebuilt modules.
+// CHECK-NOT: "is-shareable"
+
+//--- compile-pch.json.in
+[
+{
+    "directory": "DIR",
+    "command": "clang -x c-header -c DIR/prebuild.h -isysroot DIR/MacOSX.sdk 
-IDIR/BuildDir -ivfsoverlay DIR/overlay.json -IDIR/MacOSX.sdk/usr/include 
-fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps -o 
DIR/prebuild.pch",
+    "file": "DIR/prebuild.h"
+}
+]
+
+//--- compile-commands.json.in
+[
+{
+    "directory": "DIR",
+    "command": "clang -c DIR/client.c -isysroot DIR/MacOSX.sdk -IDIR/BuildDir 
-ivfsoverlay DIR/overlay.json -IDIR/MacOSX.sdk/usr/include -fmodules 
-fmodules-cache-path=DIR/module-cache -fimplicit-module-maps -include-pch 
DIR/prebuild.pch",
+    "file": "DIR/client.c"
+}
+]
+
+//--- overlay.json.template
+{
+  "version": 0,
+  "case-sensitive": "false",
+  "roots": [
+    {
+          "external-contents": "DIR/BuildDir/B_vfs.h",
+          "name": "DIR/MacOSX.sdk/usr/include/B/B_vfs.h",
+          "type": "file"
+    }
+  ]
+}
+
+//--- MacOSX.sdk/usr/include/A/module.modulemap
+module A [system] {
+  umbrella "."
+}
+
+//--- MacOSX.sdk/usr/include/A/A.h
+typedef int A_type;
+
+//--- MacOSX.sdk/usr/include/B/module.modulemap
+module B [system] {
+  umbrella "."
+}
+
+//--- MacOSX.sdk/usr/include/B/B.h
+#include <B/B_vfs.h>
+
+//--- BuildDir/B_vfs.h
+typedef int local_t;
+
+//--- MacOSX.sdk/usr/include/sys/sys.h
+typedef int sys_t_m;
+
+//--- MacOSX.sdk/usr/include/sys/module.modulemap
+module sys [system] {
+  umbrella "."
+}
+
+//--- MacOSX.sdk/usr/include/B_transitive/B.h
+#include <B/B.h>
+
+//--- MacOSX.sdk/usr/include/B_transitive/module.modulemap
+module B_transitive [system] {
+  umbrella "."
+}
+
+//--- MacOSX.sdk/usr/include/C/module.modulemap
+module C [system] {
+  umbrella "."
+}
+
+//--- MacOSX.sdk/usr/include/C/C.h
+#include <B_transitive/B.h>
+
+
+//--- MacOSX.sdk/usr/include/D/module.modulemap
+module D [system] {
+  umbrella "."
+}
+
+//--- MacOSX.sdk/usr/include/D/D.h
+#include <C/C.h>
+
+//--- prebuild.h
+#include <A/A.h>
+#include <C/C.h> // This dependency transitively depends on a local header.
+
+//--- client.c
+#include <D/D.h> // This dependency transitively depends on a local header.
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp 
b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index f5946b30fb84d..53f77e59999cf 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -471,8 +471,8 @@ class FullDeps {
         for (auto &&ModID : ModuleIDs) {
           auto &MD = Modules[ModID];
           JOS.object([&] {
-            if (MD.IsInSysroot)
-              JOS.attribute("is-in-sysroot", MD.IsInSysroot);
+            if (MD.IsShareable)
+              JOS.attribute("is-shareable", MD.IsShareable);
             JOS.attributeArray("clang-module-deps",
                                toJSONSorted(JOS, MD.ClangModuleDeps));
             JOS.attribute("clang-modulemap-file",

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to