jansvoboda11 created this revision.
jansvoboda11 added reviewers: Bigcheese, dexonsmith.
jansvoboda11 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The context hash of modular dependencies can be different from the context hash 
of the original translation unit if we modify its CompilerInvocation.

Stop assuming the TU's context hash everywhere.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D102473

Files:
  clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
  clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
  clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
  clang/tools/clang-scan-deps/ClangScanDeps.cpp

Index: clang/tools/clang-scan-deps/ClangScanDeps.cpp
===================================================================
--- clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -24,6 +24,7 @@
 #include "llvm/Support/Threading.h"
 #include <mutex>
 #include <thread>
+#include <unordered_map>
 
 using namespace clang;
 using namespace tooling::dependencies;
Index: clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
===================================================================
--- clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -144,8 +144,6 @@
     return;
 
   const Module *TopLevelModule = Imported->getTopLevelModule();
-  MDC.ModularDeps[MDC.ContextHash + TopLevelModule->getFullModuleName()]
-      .ImportedByMainFile = true;
   DirectModularDeps.insert(TopLevelModule);
 }
 
@@ -157,35 +155,45 @@
   for (const Module *M : DirectModularDeps)
     handleTopLevelModule(M);
 
-  for (auto &&I : MDC.ModularDeps)
-    MDC.Consumer.handleModuleDependency(I.second);
+  for (auto &MD : MDC.ModularDeps)
+    MDC.Consumer.handleModuleDependency(MD);
 
   for (auto &&I : MDC.FileDeps)
     MDC.Consumer.handleFileDependency(*MDC.Opts, I);
 }
 
-void ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
+ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
   assert(M == M->getTopLevelModule() && "Expected top level module!");
 
-  auto ModI = MDC.ModularDeps.insert(
-      std::make_pair(MDC.ContextHash + M->getFullModuleName(), ModuleDeps{}));
+  // If this module hasn't been transformed into an instance of ModuleDeps yet,
+  // this is the index the new instance will occupy in the ModularDeps vector.
+  size_t MDIdx = MDC.ModularDeps.size();
 
-  if (!ModI.first->second.ID.ModuleName.empty())
-    return;
+  // If this module has been handled already, just return its ID.
+  auto ModI = MDC.HandledTopLevelModules.insert({M, MDIdx});
+  if (!ModI.second)
+    return MDC.ModularDeps[ModI.first->second].ID;
+
+  MDC.ModularDeps.push_back(ModuleDeps{});
+  ModuleDeps &MD = MDC.ModularDeps.back();
+
+  // FIXME: Prepare the CompilerInvocation for building this module **now**, so
+  //        that we store the actual context hash for this module (not just the
+  //        context hash inherited from the original TU).
+  MD.Invocation = Instance.getInvocationPtr();
+  ModuleID ID{M->getFullModuleName(), MD.Invocation->getModuleHash()};
+  MD.ID = ID;
 
-  ModuleDeps &MD = ModI.first->second;
+  MD.ImportedByMainFile = DirectModularDeps.contains(M);
+  MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName());
+  MD.IsSystem = M->IsSystem;
 
   const FileEntry *ModuleMap = Instance.getPreprocessor()
                                    .getHeaderSearchInfo()
                                    .getModuleMap()
                                    .getContainingModuleMapFile(M);
-
-  MD.Invocation = Instance.getInvocationPtr();
   MD.ClangModuleMapFile = std::string(ModuleMap ? ModuleMap->getName() : "");
-  MD.ID.ModuleName = M->getFullModuleName();
-  MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName());
-  MD.ID.ContextHash = MDC.ContextHash;
-  MD.IsSystem = M->IsSystem;
+
   serialization::ModuleFile *MF =
       MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile());
   MDC.Instance.getASTReader()->visitInputFiles(
@@ -194,28 +202,28 @@
       });
 
   llvm::DenseSet<const Module *> AddedModules;
-  addAllSubmoduleDeps(M, MD, AddedModules);
+  addAllSubmoduleDeps(M, MDIdx, AddedModules);
+
+  return ID;
 }
 
 void ModuleDepCollectorPP::addAllSubmoduleDeps(
-    const Module *M, ModuleDeps &MD,
+    const Module *M, size_t MDIdx,
     llvm::DenseSet<const Module *> &AddedModules) {
-  addModuleDep(M, MD, AddedModules);
+  addModuleDep(M, MDIdx, AddedModules);
 
   for (const Module *SubM : M->submodules())
-    addAllSubmoduleDeps(SubM, MD, AddedModules);
+    addAllSubmoduleDeps(SubM, MDIdx, AddedModules);
 }
 
 void ModuleDepCollectorPP::addModuleDep(
-    const Module *M, ModuleDeps &MD,
+    const Module *M, size_t MDIdx,
     llvm::DenseSet<const Module *> &AddedModules) {
   for (const Module *Import : M->Imports) {
     if (Import->getTopLevelModule() != M->getTopLevelModule()) {
+      ModuleID ImportID = handleTopLevelModule(Import->getTopLevelModule());
       if (AddedModules.insert(Import->getTopLevelModule()).second)
-        MD.ClangModuleDeps.push_back(
-            {std::string(Import->getTopLevelModuleName()),
-             Instance.getInvocation().getModuleHash()});
-      handleTopLevelModule(Import->getTopLevelModule());
+        MDC.ModularDeps[MDIdx].ClangModuleDeps.push_back(ImportID);
     }
   }
 }
Index: clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
===================================================================
--- clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -8,6 +8,7 @@
 
 #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
 #include "clang/Frontend/Utils.h"
+#include <unordered_map>
 
 namespace clang{
 namespace tooling{
@@ -143,7 +144,7 @@
       for (auto &&M : ClangModuleDeps) {
         auto &MD = M.second;
         if (MD.ImportedByMainFile)
-          FD.ClangModuleDeps.push_back({MD.ID.ModuleName, ContextHash});
+          FD.ClangModuleDeps.push_back(MD.ID);
       }
 
       FullDependenciesResult FDR;
Index: clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
===================================================================
--- clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -21,7 +21,7 @@
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/raw_ostream.h"
 #include <string>
-#include <unordered_map>
+#include <vector>
 
 namespace clang {
 namespace tooling {
@@ -144,13 +144,21 @@
 
   void handleImport(const Module *Imported);
 
-  /// Traverses the previously collected direct modular dependencies to discover
-  /// transitive modular dependencies and fills the parent \c ModuleDepCollector
-  /// with both.
-  void handleTopLevelModule(const Module *M);
-  void addAllSubmoduleDeps(const Module *M, ModuleDeps &MD,
+  /// Transforms the given module and its dependencies into ModuleDeps objects.
+  /// Stores the results in the parent \c ModuleDepCollector.
+  ModuleID handleTopLevelModule(const Module *M);
+
+  /// Handles dependencies of submodules of the given module. The ModuleDeps
+  /// object corresponding to the module that initiated the dependency
+  /// collection is stored at index MDIdx in the parent \c ModuleDepCollector.
+  void addAllSubmoduleDeps(const Module *M, size_t MDIdx,
                            llvm::DenseSet<const Module *> &AddedModules);
-  void addModuleDep(const Module *M, ModuleDeps &MD,
+
+  /// Handles the given module and puts a reference to it in the ModuleDeps
+  /// object corresponding to the module that initiated the dependency
+  /// collection (which is stored at index MDIdx in the parent
+  /// \c ModuleDepCollector).
+  void addModuleDep(const Module *M, size_t MDIdx,
                     llvm::DenseSet<const Module *> &AddedModules);
 };
 
@@ -173,13 +181,16 @@
   DependencyConsumer &Consumer;
   /// Path to the main source file.
   std::string MainFile;
-  /// The module hash identifying the compilation conditions.
+  /// Hash identifying the compilation conditions of the current TU.
   std::string ContextHash;
   /// Non-modular file dependencies. This includes the main source file and
   /// textually included header files.
   std::vector<std::string> FileDeps;
   /// Direct and transitive modular dependencies of the main source file.
-  std::unordered_map<std::string, ModuleDeps> ModularDeps;
+  std::vector<ModuleDeps> ModularDeps;
+  /// Mapping of top-level modules that were already handled to their index in
+  /// ModularDeps.
+  llvm::DenseMap<const Module *, size_t> HandledTopLevelModules;
   /// Options that control the dependency output generation.
   std::unique_ptr<DependencyOutputOptions> Opts;
 };
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to