summaryrefslogtreecommitdiff
path: root/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-11-19 20:06:13 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-11-19 20:06:13 +0000
commitc0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch)
treef42add1021b9f2ac6a69ac7cf6c4499962739a45 /clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
parent344a3780b2e33f6ca763666c380202b18aab72a3 (diff)
Diffstat (limited to 'clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp')
-rw-r--r--clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp111
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;