Coverage Report

Created: 2022-07-16 07:03

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
Line
Count
Source
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"
13
#include "clang/Basic/SourceManager.h"
14
#include "clang/Frontend/CompilerInvocation.h"
15
#include "clang/Frontend/Utils.h"
16
#include "clang/Lex/HeaderSearch.h"
17
#include "clang/Lex/PPCallbacks.h"
18
#include "clang/Serialization/ASTReader.h"
19
#include "llvm/ADT/DenseMap.h"
20
#include "llvm/ADT/StringSet.h"
21
#include "llvm/Support/raw_ostream.h"
22
#include <string>
23
#include <unordered_map>
24
25
namespace clang {
26
namespace tooling {
27
namespace dependencies {
28
29
class DependencyConsumer;
30
31
/// Modular dependency that has already been built prior to the dependency scan.
32
struct PrebuiltModuleDep {
33
  std::string ModuleName;
34
  std::string PCMFile;
35
  std::string ModuleMapFile;
36
37
  explicit PrebuiltModuleDep(const Module *M)
38
      : ModuleName(M->getTopLevelModuleName()),
39
        PCMFile(M->getASTFile()->getName()),
40
5
        ModuleMapFile(M->PresumedModuleMapFile) {}
41
};
42
43
/// This is used to identify a specific module.
44
struct ModuleID {
45
  /// The name of the module. This may include `:` for C++20 module partitions,
46
  /// or a header-name for C++20 header units.
47
  std::string ModuleName;
48
49
  /// The context hash of a module represents the set of compiler options that
50
  /// may make one version of a module incompatible with another. This includes
51
  /// things like language mode, predefined macros, header search paths, etc...
52
  ///
53
  /// Modules with the same name but a different \c ContextHash should be
54
  /// treated as separate modules for the purpose of a build.
55
  std::string ContextHash;
56
57
106
  bool operator==(const ModuleID &Other) const {
58
106
    return ModuleName == Other.ModuleName && 
ContextHash == Other.ContextHash77
;
59
106
  }
60
};
61
62
struct ModuleIDHasher {
63
125
  std::size_t operator()(const ModuleID &MID) const {
64
125
    return llvm::hash_combine(MID.ModuleName, MID.ContextHash);
65
125
  }
66
};
67
68
/// An output from a module compilation, such as the path of the module file.
69
enum class ModuleOutputKind {
70
  /// The module file (.pcm). Required.
71
  ModuleFile,
72
  /// The path of the dependency file (.d), if any.
73
  DependencyFile,
74
  /// The null-separated list of names to use as the targets in the dependency
75
  /// file, if any. Defaults to the value of \c ModuleFile, as in the driver.
76
  DependencyTargets,
77
  /// The path of the serialized diagnostic file (.dia), if any.
78
  DiagnosticSerializationFile,
79
};
80
81
struct ModuleDeps {
82
  /// The identifier of the module.
83
  ModuleID ID;
84
85
  /// Whether this is a "system" module.
86
  bool IsSystem;
87
88
  /// The path to the modulemap file which defines this module.
89
  ///
90
  /// This can be used to explicitly build this module. This file will
91
  /// additionally appear in \c FileDeps as a dependency.
92
  std::string ClangModuleMapFile;
93
94
  /// The path to where an implicit build would put the PCM for this module.
95
  std::string ImplicitModulePCMPath;
96
97
  /// A collection of absolute paths to files that this module directly depends
98
  /// on, not including transitive dependencies.
99
  llvm::StringSet<> FileDeps;
100
101
  /// A collection of absolute paths to module map files that this module needs
102
  /// to know about.
103
  std::vector<std::string> ModuleMapFileDeps;
104
105
  /// A collection of prebuilt modular dependencies this module directly depends
106
  /// on, not including transitive dependencies.
107
  std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
108
109
  /// A list of module identifiers this module directly depends on, not
110
  /// including transitive dependencies.
111
  ///
112
  /// This may include modules with a different context hash when it can be
113
  /// determined that the differences are benign for this compilation.
114
  std::vector<ModuleID> ClangModuleDeps;
115
116
  // Used to track which modules that were discovered were directly imported by
117
  // the primary TU.
118
  bool ImportedByMainFile = false;
119
120
  /// Whether the TU had a dependency file. The path in \c BuildInvocation is
121
  /// cleared to avoid leaking the specific path from the TU into the module.
122
  bool HadDependencyFile = false;
123
124
  /// Whether the TU had serialized diagnostics. The path in \c BuildInvocation
125
  /// is cleared to avoid leaking the specific path from the TU into the module.
126
  bool HadSerializedDiagnostics = false;
127
128
  /// Compiler invocation that can be used to build this module (without paths).
129
  CompilerInvocation BuildInvocation;
130
131
  /// Gets the canonical command line suitable for passing to clang.
132
  ///
133
  /// \param LookupModuleOutput This function is called to fill in
134
  ///                           "-fmodule-file=", "-o" and other output
135
  ///                           arguments.
136
  std::vector<std::string> getCanonicalCommandLine(
137
      llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
138
          LookupModuleOutput) const;
139
140
  /// Gets the canonical command line suitable for passing to clang, excluding
141
  /// "-fmodule-file=" and "-o" arguments.
142
  std::vector<std::string> getCanonicalCommandLineWithoutModulePaths() const;
143
};
144
145
class ModuleDepCollector;
146
147
/// Callback that records textual includes and direct modular includes/imports
148
/// during preprocessing. At the end of the main file, it also collects
149
/// transitive modular dependencies and passes everything to the
150
/// \c DependencyConsumer of the parent \c ModuleDepCollector.
151
class ModuleDepCollectorPP final : public PPCallbacks {
152
public:
153
54
  ModuleDepCollectorPP(ModuleDepCollector &MDC) : MDC(MDC) {}
154
155
  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
156
                   SrcMgr::CharacteristicKind FileType,
157
                   FileID PrevFID) override;
158
  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
159
                          StringRef FileName, bool IsAngled,
160
                          CharSourceRange FilenameRange,
161
                          Optional<FileEntryRef> File, StringRef SearchPath,
162
                          StringRef RelativePath, const Module *Imported,
163
                          SrcMgr::CharacteristicKind FileType) override;
164
  void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path,
165
                    const Module *Imported) override;
166
167
  void EndOfMainFile() override;
168
169
private:
170
  /// The parent dependency collector.
171
  ModuleDepCollector &MDC;
172
  /// Working set of direct modular dependencies.
173
  llvm::SetVector<const Module *> DirectModularDeps;
174
  /// Working set of direct modular dependencies that have already been built.
175
  llvm::SetVector<const Module *> DirectPrebuiltModularDeps;
176
177
  void handleImport(const Module *Imported);
178
179
  /// Adds direct modular dependencies that have already been built to the
180
  /// ModuleDeps instance.
181
  void
182
  addAllSubmodulePrebuiltDeps(const Module *M, ModuleDeps &MD,
183
                              llvm::DenseSet<const Module *> &SeenSubmodules);
184
  void addModulePrebuiltDeps(const Module *M, ModuleDeps &MD,
185
                             llvm::DenseSet<const Module *> &SeenSubmodules);
186
187
  /// Traverses the previously collected direct modular dependencies to discover
188
  /// transitive modular dependencies and fills the parent \c ModuleDepCollector
189
  /// with both.
190
  ModuleID handleTopLevelModule(const Module *M);
191
  void addAllSubmoduleDeps(const Module *M, ModuleDeps &MD,
192
                           llvm::DenseSet<const Module *> &AddedModules);
193
  void addModuleDep(const Module *M, ModuleDeps &MD,
194
                    llvm::DenseSet<const Module *> &AddedModules);
195
};
196
197
/// Collects modular and non-modular dependencies of the main file by attaching
198
/// \c ModuleDepCollectorPP to the preprocessor.
199
class ModuleDepCollector final : public DependencyCollector {
200
public:
201
  ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,
202
                     CompilerInstance &ScanInstance, DependencyConsumer &C,
203
                     CompilerInvocation &&OriginalCI, bool OptimizeArgs);
204
205
  void attachToPreprocessor(Preprocessor &PP) override;
206
  void attachToASTReader(ASTReader &R) override;
207
208
private:
209
  friend ModuleDepCollectorPP;
210
211
  /// The compiler instance for scanning the current translation unit.
212
  CompilerInstance &ScanInstance;
213
  /// The consumer of collected dependency information.
214
  DependencyConsumer &Consumer;
215
  /// Path to the main source file.
216
  std::string MainFile;
217
  /// Hash identifying the compilation conditions of the current TU.
218
  std::string ContextHash;
219
  /// Non-modular file dependencies. This includes the main source file and
220
  /// textually included header files.
221
  std::vector<std::string> FileDeps;
222
  /// Direct and transitive modular dependencies of the main source file.
223
  llvm::MapVector<const Module *, std::unique_ptr<ModuleDeps>> ModularDeps;
224
  /// Options that control the dependency output generation.
225
  std::unique_ptr<DependencyOutputOptions> Opts;
226
  /// The original Clang invocation passed to dependency scanner.
227
  CompilerInvocation OriginalInvocation;
228
  /// Whether to optimize the modules' command-line arguments.
229
  bool OptimizeArgs;
230
231
  /// Checks whether the module is known as being prebuilt.
232
  bool isPrebuiltModule(const Module *M);
233
234
  /// Constructs a CompilerInvocation that can be used to build the given
235
  /// module, excluding paths to discovered modular dependencies that are yet to
236
  /// be built.
237
  CompilerInvocation makeInvocationForModuleBuildWithoutPaths(
238
      const ModuleDeps &Deps,
239
      llvm::function_ref<void(CompilerInvocation &)> Optimize) const;
240
};
241
242
} // end namespace dependencies
243
} // end namespace tooling
244
} // end namespace clang
245
246
#endif // LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H