clang 17.0.0git
ModuleDepCollector.h
Go to the documentation of this file.
1//===- ModuleDepCollector.h - Callbacks to collect deps ---------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H
10#define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H
11
12#include "clang/Basic/LLVM.h"
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/StringSet.h"
21#include "llvm/Support/raw_ostream.h"
22#include <optional>
23#include <string>
24#include <unordered_map>
25
26namespace clang {
27namespace tooling {
28namespace dependencies {
29
30class DependencyConsumer;
31
32/// Modular dependency that has already been built prior to the dependency scan.
34 std::string ModuleName;
35 std::string PCMFile;
36 std::string ModuleMapFile;
37
38 explicit PrebuiltModuleDep(const Module *M)
39 : ModuleName(M->getTopLevelModuleName()),
40 PCMFile(M->getASTFile()->getName()),
41 ModuleMapFile(M->PresumedModuleMapFile) {}
42};
43
44/// This is used to identify a specific module.
45struct ModuleID {
46 /// The name of the module. This may include `:` for C++20 module partitions,
47 /// or a header-name for C++20 header units.
48 std::string ModuleName;
49
50 /// The context hash of a module represents the compiler options that affect
51 /// the resulting command-line invocation.
52 ///
53 /// Modules with the same name and ContextHash but different invocations could
54 /// cause non-deterministic build results.
55 ///
56 /// Modules with the same name but a different \c ContextHash should be
57 /// treated as separate modules for the purpose of a build.
58 std::string ContextHash;
59
60 bool operator==(const ModuleID &Other) const {
61 return ModuleName == Other.ModuleName && ContextHash == Other.ContextHash;
62 }
63};
64
65/// An output from a module compilation, such as the path of the module file.
66enum class ModuleOutputKind {
67 /// The module file (.pcm). Required.
69 /// The path of the dependency file (.d), if any.
71 /// The null-separated list of names to use as the targets in the dependency
72 /// file, if any. Defaults to the value of \c ModuleFile, as in the driver.
74 /// The path of the serialized diagnostic file (.dia), if any.
76};
77
78struct ModuleDeps {
79 /// The identifier of the module.
81
82 /// Whether this is a "system" module.
84
85 /// The path to the modulemap file which defines this module.
86 ///
87 /// This can be used to explicitly build this module. This file will
88 /// additionally appear in \c FileDeps as a dependency.
89 std::string ClangModuleMapFile;
90
91 /// A collection of absolute paths to files that this module directly depends
92 /// on, not including transitive dependencies.
93 llvm::StringSet<> FileDeps;
94
95 /// A collection of absolute paths to module map files that this module needs
96 /// to know about. The ordering is significant.
97 std::vector<std::string> ModuleMapFileDeps;
98
99 /// A collection of prebuilt modular dependencies this module directly depends
100 /// on, not including transitive dependencies.
101 std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
102
103 /// A list of module identifiers this module directly depends on, not
104 /// including transitive dependencies.
105 ///
106 /// This may include modules with a different context hash when it can be
107 /// determined that the differences are benign for this compilation.
108 std::vector<ModuleID> ClangModuleDeps;
109
110 // Used to track which modules that were discovered were directly imported by
111 // the primary TU.
112 bool ImportedByMainFile = false;
113
114 /// Compiler invocation that can be used to build this module. Does not
115 /// include argv[0].
116 std::vector<std::string> BuildArguments;
117};
118
120
121/// Callback that records textual includes and direct modular includes/imports
122/// during preprocessing. At the end of the main file, it also collects
123/// transitive modular dependencies and passes everything to the
124/// \c DependencyConsumer of the parent \c ModuleDepCollector.
125class ModuleDepCollectorPP final : public PPCallbacks {
126public:
128
131 FileID PrevFID) override;
132 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
133 StringRef FileName, bool IsAngled,
134 CharSourceRange FilenameRange,
135 OptionalFileEntryRef File, StringRef SearchPath,
136 StringRef RelativePath, const Module *Imported,
137 SrcMgr::CharacteristicKind FileType) override;
138 void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path,
139 const Module *Imported) override;
140
141 void EndOfMainFile() override;
142
143private:
144 /// The parent dependency collector.
146 /// Working set of direct modular dependencies.
147 llvm::SetVector<const Module *> DirectModularDeps;
148
149 void handleImport(const Module *Imported);
150
151 /// Adds direct modular dependencies that have already been built to the
152 /// ModuleDeps instance.
153 void
154 addAllSubmodulePrebuiltDeps(const Module *M, ModuleDeps &MD,
155 llvm::DenseSet<const Module *> &SeenSubmodules);
156 void addModulePrebuiltDeps(const Module *M, ModuleDeps &MD,
157 llvm::DenseSet<const Module *> &SeenSubmodules);
158
159 /// Traverses the previously collected direct modular dependencies to discover
160 /// transitive modular dependencies and fills the parent \c ModuleDepCollector
161 /// with both.
162 /// Returns the ID or nothing if the dependency is spurious and is ignored.
163 std::optional<ModuleID> handleTopLevelModule(const Module *M);
164 void addAllSubmoduleDeps(const Module *M, ModuleDeps &MD,
165 llvm::DenseSet<const Module *> &AddedModules);
166 void addModuleDep(const Module *M, ModuleDeps &MD,
167 llvm::DenseSet<const Module *> &AddedModules);
168
169 /// Traverses the affecting modules and updates \c MD with references to the
170 /// parent \c ModuleDepCollector info.
171 void addAllAffectingClangModules(const Module *M, ModuleDeps &MD,
172 llvm::DenseSet<const Module *> &AddedModules);
173 void addAffectingClangModule(const Module *M, ModuleDeps &MD,
174 llvm::DenseSet<const Module *> &AddedModules);
175};
176
177/// Collects modular and non-modular dependencies of the main file by attaching
178/// \c ModuleDepCollectorPP to the preprocessor.
180public:
181 ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,
182 CompilerInstance &ScanInstance, DependencyConsumer &C,
183 CompilerInvocation OriginalCI, bool OptimizeArgs,
184 bool EagerLoadModules);
185
186 void attachToPreprocessor(Preprocessor &PP) override;
187 void attachToASTReader(ASTReader &R) override;
188
189 /// Apply any changes implied by the discovered dependencies to the given
190 /// invocation, (e.g. disable implicit modules, add explicit module paths).
192
193private:
195
196 /// The compiler instance for scanning the current translation unit.
197 CompilerInstance &ScanInstance;
198 /// The consumer of collected dependency information.
199 DependencyConsumer &Consumer;
200 /// Path to the main source file.
201 std::string MainFile;
202 /// Hash identifying the compilation conditions of the current TU.
203 std::string ContextHash;
204 /// Non-modular file dependencies. This includes the main source file and
205 /// textually included header files.
206 std::vector<std::string> FileDeps;
207 /// Direct and transitive modular dependencies of the main source file.
208 llvm::MapVector<const Module *, std::unique_ptr<ModuleDeps>> ModularDeps;
209 /// Secondary mapping for \c ModularDeps allowing lookup by ModuleID without
210 /// a preprocessor. Storage owned by \c ModularDeps.
211 llvm::DenseMap<ModuleID, ModuleDeps *> ModuleDepsByID;
212 /// Direct modular dependencies that have already been built.
213 llvm::MapVector<const Module *, PrebuiltModuleDep> DirectPrebuiltModularDeps;
214 /// Options that control the dependency output generation.
215 std::unique_ptr<DependencyOutputOptions> Opts;
216 /// The original Clang invocation passed to dependency scanner.
217 CompilerInvocation OriginalInvocation;
218 /// Whether to optimize the modules' command-line arguments.
219 bool OptimizeArgs;
220 /// Whether to set up command-lines to load PCM files eagerly.
221 bool EagerLoadModules;
222
223 /// Checks whether the module is known as being prebuilt.
224 bool isPrebuiltModule(const Module *M);
225
226 /// Adds \p Path to \c FileDeps, making it absolute if necessary.
227 void addFileDep(StringRef Path);
228 /// Adds \p Path to \c MD.FileDeps, making it absolute if necessary.
229 void addFileDep(ModuleDeps &MD, StringRef Path);
230
231 /// Constructs a CompilerInvocation that can be used to build the given
232 /// module, excluding paths to discovered modular dependencies that are yet to
233 /// be built.
234 CompilerInvocation makeInvocationForModuleBuildWithoutOutputs(
235 const ModuleDeps &Deps,
236 llvm::function_ref<void(CompilerInvocation &)> Optimize) const;
237
238 /// Collect module map files for given modules.
240 collectModuleMapFiles(ArrayRef<ModuleID> ClangModuleDeps) const;
241
242 /// Add module map files to the invocation, if needed.
243 void addModuleMapFiles(CompilerInvocation &CI,
244 ArrayRef<ModuleID> ClangModuleDeps) const;
245 /// Add module files (pcm) to the invocation, if needed.
246 void addModuleFiles(CompilerInvocation &CI,
247 ArrayRef<ModuleID> ClangModuleDeps) const;
248
249 /// Add paths that require looking up outputs to the given dependencies.
250 void addOutputPaths(CompilerInvocation &CI, ModuleDeps &Deps);
251
252 /// Compute the context hash for \p Deps, and create the mapping
253 /// \c ModuleDepsByID[Deps.ID] = &Deps.
254 void associateWithContextHash(const CompilerInvocation &CI, ModuleDeps &Deps);
255};
256
257} // end namespace dependencies
258} // end namespace tooling
259} // end namespace clang
260
261namespace llvm {
262template <> struct DenseMapInfo<clang::tooling::dependencies::ModuleID> {
264 static inline ModuleID getEmptyKey() { return ModuleID{"", ""}; }
265 static inline ModuleID getTombstoneKey() {
266 return ModuleID{"~", "~"}; // ~ is not a valid module name or context hash
267 }
268 static unsigned getHashValue(const ModuleID &ID) {
269 return hash_combine(ID.ModuleName, ID.ContextHash);
270 }
271 static bool isEqual(const ModuleID &LHS, const ModuleID &RHS) {
272 return LHS == RHS;
273 }
274};
275} // namespace llvm
276
277#endif // LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the PPCallbacks interface.
static std::string getName(const CallEvent &Call)
Defines the SourceManager interface.
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:366
Represents a character-granular source range.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Helper class for holding the data necessary to invoke the compiler.
An interface for collecting the dependencies of a compilation.
Definition: Utils.h:61
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Record the location of an inclusion directive, such as an #include or #import statement.
Describes a module or submodule.
Definition: Module.h:98
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition: PPCallbacks.h:35
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
Encodes a location in the source.
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
Callback that records textual includes and direct modular includes/imports during preprocessing.
void EndOfMainFile() override
Callback invoked when the end of the main file is reached.
void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID) override
Callback invoked whenever a source file is entered or exited.
void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, const Module *Imported) override
Callback invoked whenever there was an explicit module-import syntax.
Collects modular and non-modular dependencies of the main file by attaching ModuleDepCollectorPP to t...
void applyDiscoveredDependencies(CompilerInvocation &CI)
Apply any changes implied by the discovered dependencies to the given invocation, (e....
void attachToPreprocessor(Preprocessor &PP) override
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
Definition: SourceManager.h:80
ModuleOutputKind
An output from a module compilation, such as the path of the module file.
@ DiagnosticSerializationFile
The path of the serialized diagnostic file (.dia), if any.
@ DependencyFile
The path of the dependency file (.d), if any.
@ DependencyTargets
The null-separated list of names to use as the targets in the dependency file, if any.
@ ModuleFile
The module file (.pcm). Required.
@ C
Languages that the frontend can parse and compile.
YAML serialization mapping.
Definition: Dominators.h:30
std::string ClangModuleMapFile
The path to the modulemap file which defines this module.
std::vector< std::string > ModuleMapFileDeps
A collection of absolute paths to module map files that this module needs to know about.
std::vector< std::string > BuildArguments
Compiler invocation that can be used to build this module.
std::vector< PrebuiltModuleDep > PrebuiltModuleDeps
A collection of prebuilt modular dependencies this module directly depends on, not including transiti...
std::vector< ModuleID > ClangModuleDeps
A list of module identifiers this module directly depends on, not including transitive dependencies.
ModuleID ID
The identifier of the module.
llvm::StringSet FileDeps
A collection of absolute paths to files that this module directly depends on, not including transitiv...
bool IsSystem
Whether this is a "system" module.
This is used to identify a specific module.
std::string ContextHash
The context hash of a module represents the compiler options that affect the resulting command-line i...
std::string ModuleName
The name of the module.
bool operator==(const ModuleID &Other) const
Modular dependency that has already been built prior to the dependency scan.
static bool isEqual(const ModuleID &LHS, const ModuleID &RHS)