Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 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 <optional>
23
#include <string>
24
#include <unordered_map>
25
 
26
namespace clang {
27
namespace tooling {
28
namespace dependencies {
29
 
30
class DependencyConsumer;
31
 
32
/// Modular dependency that has already been built prior to the dependency scan.
33
struct PrebuiltModuleDep {
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.
45
struct 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
/// P1689ModuleInfo - Represents the needed information of standard C++20
66
/// modules for P1689 format.
67
struct P1689ModuleInfo {
68
  /// The name of the module. This may include `:` for partitions.
69
  std::string ModuleName;
70
 
71
  /// Optional. The source path to the module.
72
  std::string SourcePath;
73
 
74
  /// If this module is a standard c++ interface unit.
75
  bool IsStdCXXModuleInterface = true;
76
 
77
  enum class ModuleType {
78
    NamedCXXModule
79
    // To be supported
80
    // AngleHeaderUnit,
81
    // QuoteHeaderUnit
82
  };
83
  ModuleType Type = ModuleType::NamedCXXModule;
84
};
85
 
86
/// An output from a module compilation, such as the path of the module file.
87
enum class ModuleOutputKind {
88
  /// The module file (.pcm). Required.
89
  ModuleFile,
90
  /// The path of the dependency file (.d), if any.
91
  DependencyFile,
92
  /// The null-separated list of names to use as the targets in the dependency
93
  /// file, if any. Defaults to the value of \c ModuleFile, as in the driver.
94
  DependencyTargets,
95
  /// The path of the serialized diagnostic file (.dia), if any.
96
  DiagnosticSerializationFile,
97
};
98
 
99
struct ModuleDeps {
100
  /// The identifier of the module.
101
  ModuleID ID;
102
 
103
  /// Whether this is a "system" module.
104
  bool IsSystem;
105
 
106
  /// The path to the modulemap file which defines this module.
107
  ///
108
  /// This can be used to explicitly build this module. This file will
109
  /// additionally appear in \c FileDeps as a dependency.
110
  std::string ClangModuleMapFile;
111
 
112
  /// A collection of absolute paths to files that this module directly depends
113
  /// on, not including transitive dependencies.
114
  llvm::StringSet<> FileDeps;
115
 
116
  /// A collection of absolute paths to module map files that this module needs
117
  /// to know about. The ordering is significant.
118
  std::vector<std::string> ModuleMapFileDeps;
119
 
120
  /// A collection of prebuilt modular dependencies this module directly depends
121
  /// on, not including transitive dependencies.
122
  std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
123
 
124
  /// A list of module identifiers this module directly depends on, not
125
  /// including transitive dependencies.
126
  ///
127
  /// This may include modules with a different context hash when it can be
128
  /// determined that the differences are benign for this compilation.
129
  std::vector<ModuleID> ClangModuleDeps;
130
 
131
  // Used to track which modules that were discovered were directly imported by
132
  // the primary TU.
133
  bool ImportedByMainFile = false;
134
 
135
  /// Compiler invocation that can be used to build this module. Does not
136
  /// include argv[0].
137
  std::vector<std::string> BuildArguments;
138
};
139
 
140
class ModuleDepCollector;
141
 
142
/// Callback that records textual includes and direct modular includes/imports
143
/// during preprocessing. At the end of the main file, it also collects
144
/// transitive modular dependencies and passes everything to the
145
/// \c DependencyConsumer of the parent \c ModuleDepCollector.
146
class ModuleDepCollectorPP final : public PPCallbacks {
147
public:
148
  ModuleDepCollectorPP(ModuleDepCollector &MDC) : MDC(MDC) {}
149
 
150
  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
151
                   SrcMgr::CharacteristicKind FileType,
152
                   FileID PrevFID) override;
153
  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
154
                          StringRef FileName, bool IsAngled,
155
                          CharSourceRange FilenameRange,
156
                          OptionalFileEntryRef File, StringRef SearchPath,
157
                          StringRef RelativePath, const Module *Imported,
158
                          SrcMgr::CharacteristicKind FileType) override;
159
  void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path,
160
                    const Module *Imported) override;
161
 
162
  void EndOfMainFile() override;
163
 
164
private:
165
  /// The parent dependency collector.
166
  ModuleDepCollector &MDC;
167
  /// Working set of direct modular dependencies.
168
  llvm::SetVector<const Module *> DirectModularDeps;
169
 
170
  void handleImport(const Module *Imported);
171
 
172
  /// Adds direct modular dependencies that have already been built to the
173
  /// ModuleDeps instance.
174
  void
175
  addAllSubmodulePrebuiltDeps(const Module *M, ModuleDeps &MD,
176
                              llvm::DenseSet<const Module *> &SeenSubmodules);
177
  void addModulePrebuiltDeps(const Module *M, ModuleDeps &MD,
178
                             llvm::DenseSet<const Module *> &SeenSubmodules);
179
 
180
  /// Traverses the previously collected direct modular dependencies to discover
181
  /// transitive modular dependencies and fills the parent \c ModuleDepCollector
182
  /// with both.
183
  /// Returns the ID or nothing if the dependency is spurious and is ignored.
184
  std::optional<ModuleID> handleTopLevelModule(const Module *M);
185
  void addAllSubmoduleDeps(const Module *M, ModuleDeps &MD,
186
                           llvm::DenseSet<const Module *> &AddedModules);
187
  void addModuleDep(const Module *M, ModuleDeps &MD,
188
                    llvm::DenseSet<const Module *> &AddedModules);
189
 
190
  /// Traverses the affecting modules and updates \c MD with references to the
191
  /// parent \c ModuleDepCollector info.
192
  void addAllAffectingClangModules(const Module *M, ModuleDeps &MD,
193
                              llvm::DenseSet<const Module *> &AddedModules);
194
  void addAffectingClangModule(const Module *M, ModuleDeps &MD,
195
                          llvm::DenseSet<const Module *> &AddedModules);
196
};
197
 
198
/// Collects modular and non-modular dependencies of the main file by attaching
199
/// \c ModuleDepCollectorPP to the preprocessor.
200
class ModuleDepCollector final : public DependencyCollector {
201
public:
202
  ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,
203
                     CompilerInstance &ScanInstance, DependencyConsumer &C,
204
                     CompilerInvocation OriginalCI, bool OptimizeArgs,
205
                     bool EagerLoadModules, bool IsStdModuleP1689Format);
206
 
207
  void attachToPreprocessor(Preprocessor &PP) override;
208
  void attachToASTReader(ASTReader &R) override;
209
 
210
  /// Apply any changes implied by the discovered dependencies to the given
211
  /// invocation, (e.g. disable implicit modules, add explicit module paths).
212
  void applyDiscoveredDependencies(CompilerInvocation &CI);
213
 
214
private:
215
  friend ModuleDepCollectorPP;
216
 
217
  /// The compiler instance for scanning the current translation unit.
218
  CompilerInstance &ScanInstance;
219
  /// The consumer of collected dependency information.
220
  DependencyConsumer &Consumer;
221
  /// Path to the main source file.
222
  std::string MainFile;
223
  /// Hash identifying the compilation conditions of the current TU.
224
  std::string ContextHash;
225
  /// Non-modular file dependencies. This includes the main source file and
226
  /// textually included header files.
227
  std::vector<std::string> FileDeps;
228
  /// Direct and transitive modular dependencies of the main source file.
229
  llvm::MapVector<const Module *, std::unique_ptr<ModuleDeps>> ModularDeps;
230
  /// Secondary mapping for \c ModularDeps allowing lookup by ModuleID without
231
  /// a preprocessor. Storage owned by \c ModularDeps.
232
  llvm::DenseMap<ModuleID, ModuleDeps *> ModuleDepsByID;
233
  /// Direct modular dependencies that have already been built.
234
  llvm::MapVector<const Module *, PrebuiltModuleDep> DirectPrebuiltModularDeps;
235
  /// Options that control the dependency output generation.
236
  std::unique_ptr<DependencyOutputOptions> Opts;
237
  /// The original Clang invocation passed to dependency scanner.
238
  CompilerInvocation OriginalInvocation;
239
  /// Whether to optimize the modules' command-line arguments.
240
  bool OptimizeArgs;
241
  /// Whether to set up command-lines to load PCM files eagerly.
242
  bool EagerLoadModules;
243
  /// If we're generating dependency output in P1689 format
244
  /// for standard C++ modules.
245
  bool IsStdModuleP1689Format;
246
 
247
  std::optional<P1689ModuleInfo> ProvidedStdCXXModule;
248
  std::vector<P1689ModuleInfo> RequiredStdCXXModules;
249
 
250
  /// Checks whether the module is known as being prebuilt.
251
  bool isPrebuiltModule(const Module *M);
252
 
253
  /// Adds \p Path to \c FileDeps, making it absolute if necessary.
254
  void addFileDep(StringRef Path);
255
  /// Adds \p Path to \c MD.FileDeps, making it absolute if necessary.
256
  void addFileDep(ModuleDeps &MD, StringRef Path);
257
 
258
  /// Constructs a CompilerInvocation that can be used to build the given
259
  /// module, excluding paths to discovered modular dependencies that are yet to
260
  /// be built.
261
  CompilerInvocation makeInvocationForModuleBuildWithoutOutputs(
262
      const ModuleDeps &Deps,
263
      llvm::function_ref<void(CompilerInvocation &)> Optimize) const;
264
 
265
  /// Collect module map files for given modules.
266
  llvm::DenseSet<const FileEntry *>
267
  collectModuleMapFiles(ArrayRef<ModuleID> ClangModuleDeps) const;
268
 
269
  /// Add module map files to the invocation, if needed.
270
  void addModuleMapFiles(CompilerInvocation &CI,
271
                         ArrayRef<ModuleID> ClangModuleDeps) const;
272
  /// Add module files (pcm) to the invocation, if needed.
273
  void addModuleFiles(CompilerInvocation &CI,
274
                      ArrayRef<ModuleID> ClangModuleDeps) const;
275
 
276
  /// Add paths that require looking up outputs to the given dependencies.
277
  void addOutputPaths(CompilerInvocation &CI, ModuleDeps &Deps);
278
 
279
  /// Compute the context hash for \p Deps, and create the mapping
280
  /// \c ModuleDepsByID[Deps.ID] = &Deps.
281
  void associateWithContextHash(const CompilerInvocation &CI, ModuleDeps &Deps);
282
};
283
 
284
} // end namespace dependencies
285
} // end namespace tooling
286
} // end namespace clang
287
 
288
namespace llvm {
289
template <> struct DenseMapInfo<clang::tooling::dependencies::ModuleID> {
290
  using ModuleID = clang::tooling::dependencies::ModuleID;
291
  static inline ModuleID getEmptyKey() { return ModuleID{"", ""}; }
292
  static inline ModuleID getTombstoneKey() {
293
    return ModuleID{"~", "~"}; // ~ is not a valid module name or context hash
294
  }
295
  static unsigned getHashValue(const ModuleID &ID) {
296
    return hash_combine(ID.ModuleName, ID.ContextHash);
297
  }
298
  static bool isEqual(const ModuleID &LHS, const ModuleID &RHS) {
299
    return LHS == RHS;
300
  }
301
};
302
} // namespace llvm
303
 
304
#endif // LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H