diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
| commit | c0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch) | |
| tree | f42add1021b9f2ac6a69ac7cf6c4499962739a45 /clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp | |
| parent | 344a3780b2e33f6ca763666c380202b18aab72a3 (diff) | |
Diffstat (limited to 'clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp')
| -rw-r--r-- | clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp | 111 |
1 files changed, 76 insertions, 35 deletions
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 88cee63c98aa..383a850301a1 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -1,9 +1,8 @@ //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -18,11 +17,26 @@ using namespace clang; using namespace tooling; using namespace dependencies; +static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, + ASTReader &Reader, + const serialization::ModuleFile &MF) { + // Only preserve search paths that were used during the dependency scan. + std::vector<HeaderSearchOptions::Entry> Entries = Opts.UserEntries; + Opts.UserEntries.clear(); + for (unsigned I = 0; I < Entries.size(); ++I) + if (MF.SearchPathUsage[I]) + Opts.UserEntries.push_back(Entries[I]); +} + CompilerInvocation ModuleDepCollector::makeInvocationForModuleBuildWithoutPaths( - const ModuleDeps &Deps) const { + const ModuleDeps &Deps, + llvm::function_ref<void(CompilerInvocation &)> Optimize) const { // Make a deep copy of the original Clang invocation. CompilerInvocation CI(OriginalInvocation); + CI.getLangOpts()->resetNonModularOptions(); + CI.getPreprocessorOpts().resetNonModularOptions(); + // Remove options incompatible with explicit module build. CI.getFrontendOpts().Inputs.clear(); CI.getFrontendOpts().OutputFile.clear(); @@ -34,12 +48,18 @@ CompilerInvocation ModuleDepCollector::makeInvocationForModuleBuildWithoutPaths( CI.getLangOpts()->ImplicitModules = false; // Report the prebuilt modules this module uses. - for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps) { + for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps) CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile); - CI.getFrontendOpts().ModuleMapFiles.push_back(PrebuiltModule.ModuleMapFile); - } - CI.getPreprocessorOpts().ImplicitPCHInclude.clear(); + Optimize(CI); + + // The original invocation probably didn't have strict context hash enabled. + // We will use the context hash of this invocation to distinguish between + // multiple incompatible versions of the same module and will use it when + // reporting dependencies to the clients. Let's make sure we're using + // **strict** context hash in order to prevent accidental sharing of + // incompatible modules (e.g. with differences in search paths). + CI.getHeaderSearchOpts().ModulesStrictContextHash = true; return CI; } @@ -62,7 +82,7 @@ serializeCompilerInvocation(const CompilerInvocation &CI) { std::vector<std::string> ModuleDeps::getCanonicalCommandLine( std::function<StringRef(ModuleID)> LookupPCMPath, std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const { - CompilerInvocation CI(Invocation); + CompilerInvocation CI(BuildInvocation); FrontendOptions &FrontendOpts = CI.getFrontendOpts(); InputKind ModuleMapInputKind(FrontendOpts.DashX.getLanguage(), @@ -79,7 +99,7 @@ std::vector<std::string> ModuleDeps::getCanonicalCommandLine( std::vector<std::string> ModuleDeps::getCanonicalCommandLineWithoutModulePaths() const { - return serializeCompilerInvocation(Invocation); + return serializeCompilerInvocation(BuildInvocation); } void dependencies::detail::collectPCMAndModuleMapPaths( @@ -112,15 +132,15 @@ void ModuleDepCollectorPP::FileChanged(SourceLocation Loc, FileID PrevFID) { if (Reason != PPCallbacks::EnterFile) return; - + // This has to be delayed as the context hash can change at the start of // `CompilerInstance::ExecuteAction`. if (MDC.ContextHash.empty()) { - MDC.ContextHash = Instance.getInvocation().getModuleHash(); + MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash(); MDC.Consumer.handleContextHash(MDC.ContextHash); } - SourceManager &SM = Instance.getSourceManager(); + SourceManager &SM = MDC.ScanInstance.getSourceManager(); // Dependency generation really does want to go all the way to the // file entry for a source location to find out what is depended on. @@ -163,12 +183,14 @@ void ModuleDepCollectorPP::handleImport(const Module *Imported) { } void ModuleDepCollectorPP::EndOfMainFile() { - FileID MainFileID = Instance.getSourceManager().getMainFileID(); - MDC.MainFile = std::string( - Instance.getSourceManager().getFileEntryForID(MainFileID)->getName()); + FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID(); + MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager() + .getFileEntryForID(MainFileID) + ->getName()); - if (!Instance.getPreprocessorOpts().ImplicitPCHInclude.empty()) - MDC.FileDeps.push_back(Instance.getPreprocessorOpts().ImplicitPCHInclude); + if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) + MDC.FileDeps.push_back( + MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude); for (const Module *M : DirectModularDeps) { // A top-level module might not be actually imported as a module when @@ -207,15 +229,16 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName()); MD.IsSystem = M->IsSystem; - const FileEntry *ModuleMap = Instance.getPreprocessor() + const FileEntry *ModuleMap = MDC.ScanInstance.getPreprocessor() .getHeaderSearchInfo() .getModuleMap() .getModuleMapFileForUniquing(M); MD.ClangModuleMapFile = std::string(ModuleMap ? ModuleMap->getName() : ""); serialization::ModuleFile *MF = - MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile()); - MDC.Instance.getASTReader()->visitInputFiles( + MDC.ScanInstance.getASTReader()->getModuleManager().lookup( + M->getASTFile()); + MDC.ScanInstance.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 @@ -232,10 +255,16 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { // Add direct prebuilt module dependencies now, so that we can use them when // creating a CompilerInvocation and computing context hash for this // ModuleDeps instance. - addDirectPrebuiltModuleDeps(M, MD); + llvm::DenseSet<const Module *> SeenModules; + addAllSubmodulePrebuiltDeps(M, MD, SeenModules); - MD.Invocation = MDC.makeInvocationForModuleBuildWithoutPaths(MD); - MD.ID.ContextHash = MD.Invocation.getModuleHash(); + MD.BuildInvocation = MDC.makeInvocationForModuleBuildWithoutPaths( + MD, [&](CompilerInvocation &BuildInvocation) { + if (MDC.OptimizeArgs) + optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(), + *MDC.ScanInstance.getASTReader(), *MF); + }); + MD.ID.ContextHash = MD.BuildInvocation.getModuleHash(); llvm::DenseSet<const Module *> AddedModules; addAllSubmoduleDeps(M, MD, AddedModules); @@ -243,12 +272,23 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { return MD.ID; } -void ModuleDepCollectorPP::addDirectPrebuiltModuleDeps(const Module *M, - ModuleDeps &MD) { +void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps( + const Module *M, ModuleDeps &MD, + llvm::DenseSet<const Module *> &SeenSubmodules) { + addModulePrebuiltDeps(M, MD, SeenSubmodules); + + for (const Module *SubM : M->submodules()) + addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules); +} + +void ModuleDepCollectorPP::addModulePrebuiltDeps( + const Module *M, ModuleDeps &MD, + llvm::DenseSet<const Module *> &SeenSubmodules) { for (const Module *Import : M->Imports) if (Import->getTopLevelModule() != M->getTopLevelModule()) - if (MDC.isPrebuiltModule(Import)) - MD.PrebuiltModuleDeps.emplace_back(Import); + if (MDC.isPrebuiltModule(Import->getTopLevelModule())) + if (SeenSubmodules.insert(Import->getTopLevelModule()).second) + MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule()); } void ModuleDepCollectorPP::addAllSubmoduleDeps( @@ -274,13 +314,14 @@ void ModuleDepCollectorPP::addModuleDep( } ModuleDepCollector::ModuleDepCollector( - std::unique_ptr<DependencyOutputOptions> Opts, CompilerInstance &I, - DependencyConsumer &C, CompilerInvocation &&OriginalCI) - : Instance(I), Consumer(C), Opts(std::move(Opts)), - OriginalInvocation(std::move(OriginalCI)) {} + std::unique_ptr<DependencyOutputOptions> Opts, + CompilerInstance &ScanInstance, DependencyConsumer &C, + CompilerInvocation &&OriginalCI, bool OptimizeArgs) + : ScanInstance(ScanInstance), Consumer(C), Opts(std::move(Opts)), + OriginalInvocation(std::move(OriginalCI)), OptimizeArgs(OptimizeArgs) {} void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { - PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(Instance, *this)); + PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this)); } void ModuleDepCollector::attachToASTReader(ASTReader &R) {} @@ -288,7 +329,7 @@ void ModuleDepCollector::attachToASTReader(ASTReader &R) {} bool ModuleDepCollector::isPrebuiltModule(const Module *M) { std::string Name(M->getTopLevelModuleName()); const auto &PrebuiltModuleFiles = - Instance.getHeaderSearchOpts().PrebuiltModuleFiles; + ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles; auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name); if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end()) return false; |
