diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h --- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -21,7 +21,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/Support/raw_ostream.h" #include -#include +#include 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 &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 &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 FileDeps; /// Direct and transitive modular dependencies of the main source file. - std::unordered_map ModularDeps; + std::vector ModularDeps; + /// Mapping of top-level modules that were already handled to their index in + /// ModularDeps. + llvm::DenseMap HandledTopLevelModules; /// Options that control the dependency output generation. std::unique_ptr Opts; }; diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -8,6 +8,7 @@ #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" #include "clang/Frontend/Utils.h" +#include 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; 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 @@ -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 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 &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 &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); } } } diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -24,6 +24,7 @@ #include "llvm/Support/Threading.h" #include #include +#include using namespace clang; using namespace tooling::dependencies;