Coverage Report

Created: 2021-09-21 08:58

/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_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H
10
#define LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_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
4
        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
34
  bool operator==(const ModuleID &Other) const {
58
34
    return ModuleName == Other.ModuleName && 
ContextHash == Other.ContextHash28
;
59
34
  }
60
};
61
62
struct ModuleIDHasher {
63
45
  std::size_t operator()(const ModuleID &MID) const {
64
45
    return llvm::hash_combine(MID.ModuleName, MID.ContextHash);
65
45
  }
66
};
67
68
struct ModuleDeps {
69
  /// The identifier of the module.
70
  ModuleID ID;
71
72
  /// Whether this is a "system" module.
73
  bool IsSystem;
74
75
  /// The path to the modulemap file which defines this module.
76
  ///
77
  /// This can be used to explicitly build this module. This file will
78
  /// additionally appear in \c FileDeps as a dependency.
79
  std::string ClangModuleMapFile;
80
81
  /// The path to where an implicit build would put the PCM for this module.
82
  std::string ImplicitModulePCMPath;
83
84
  /// A collection of absolute paths to files that this module directly depends
85
  /// on, not including transitive dependencies.
86
  llvm::StringSet<> FileDeps;
87
88
  /// A collection of prebuilt modular dependencies this module directly depends
89
  /// on, not including transitive dependencies.
90
  std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
91
92
  /// A list of module identifiers this module directly depends on, not
93
  /// including transitive dependencies.
94
  ///
95
  /// This may include modules with a different context hash when it can be
96
  /// determined that the differences are benign for this compilation.
97
  std::vector<ModuleID> ClangModuleDeps;
98
99
  // Used to track which modules that were discovered were directly imported by
100
  // the primary TU.
101
  bool ImportedByMainFile = false;
102
103
  /// Compiler invocation that can be used to build this module (without paths).
104
  CompilerInvocation Invocation;
105
106
  /// Gets the canonical command line suitable for passing to clang.
107
  ///
108
  /// \param LookupPCMPath This function is called to fill in "-fmodule-file="
109
  ///                      arguments and the "-o" argument. It needs to return
110
  ///                      a path for where the PCM for the given module is to
111
  ///                      be located.
112
  /// \param LookupModuleDeps This function is called to collect the full
113
  ///                         transitive set of dependencies for this
114
  ///                         compilation and fill in "-fmodule-map-file="
115
  ///                         arguments.
116
  std::vector<std::string> getCanonicalCommandLine(
117
      std::function<StringRef(ModuleID)> LookupPCMPath,
118
      std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const;
119
120
  /// Gets the canonical command line suitable for passing to clang, excluding
121
  /// arguments containing modules-related paths: "-fmodule-file=", "-o",
122
  /// "-fmodule-map-file=".
123
  std::vector<std::string> getCanonicalCommandLineWithoutModulePaths() const;
124
};
125
126
namespace detail {
127
/// Collect the paths of PCM and module map files for the modules in \c Modules
128
/// transitively.
129
void collectPCMAndModuleMapPaths(
130
    llvm::ArrayRef<ModuleID> Modules,
131
    std::function<StringRef(ModuleID)> LookupPCMPath,
132
    std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps,
133
    std::vector<std::string> &PCMPaths, std::vector<std::string> &ModMapPaths);
134
} // namespace detail
135
136
class ModuleDepCollector;
137
138
/// Callback that records textual includes and direct modular includes/imports
139
/// during preprocessing. At the end of the main file, it also collects
140
/// transitive modular dependencies and passes everything to the
141
/// \c DependencyConsumer of the parent \c ModuleDepCollector.
142
class ModuleDepCollectorPP final : public PPCallbacks {
143
public:
144
  ModuleDepCollectorPP(CompilerInstance &I, ModuleDepCollector &MDC)
145
33
      : Instance(I), MDC(MDC) {}
146
147
  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
148
                   SrcMgr::CharacteristicKind FileType,
149
                   FileID PrevFID) override;
150
  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
151
                          StringRef FileName, bool IsAngled,
152
                          CharSourceRange FilenameRange, const FileEntry *File,
153
                          StringRef SearchPath, StringRef RelativePath,
154
                          const Module *Imported,
155
                          SrcMgr::CharacteristicKind FileType) override;
156
  void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path,
157
                    const Module *Imported) override;
158
159
  void EndOfMainFile() override;
160
161
private:
162
  /// The compiler instance for the current translation unit.
163
  CompilerInstance &Instance;
164
  /// The parent dependency collector.
165
  ModuleDepCollector &MDC;
166
  /// Working set of direct modular dependencies.
167
  llvm::DenseSet<const Module *> DirectModularDeps;
168
  /// Working set of direct modular dependencies that have already been built.
169
  llvm::DenseSet<const Module *> DirectPrebuiltModularDeps;
170
171
  void handleImport(const Module *Imported);
172
173
  /// Adds direct modular dependencies that have already been built to the
174
  /// ModuleDeps instance.
175
  void
176
  addAllSubmodulePrebuiltDeps(const Module *M, ModuleDeps &MD,
177
                              llvm::DenseSet<const Module *> &SeenSubmodules);
178
  void addModulePrebuiltDeps(const Module *M, ModuleDeps &MD,
179
                             llvm::DenseSet<const Module *> &SeenSubmodules);
180
181
  /// Traverses the previously collected direct modular dependencies to discover
182
  /// transitive modular dependencies and fills the parent \c ModuleDepCollector
183
  /// with both.
184
  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
191
/// Collects modular and non-modular dependencies of the main file by attaching
192
/// \c ModuleDepCollectorPP to the preprocessor.
193
class ModuleDepCollector final : public DependencyCollector {
194
public:
195
  ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,
196
                     CompilerInstance &I, DependencyConsumer &C,
197
                     CompilerInvocation &&OriginalCI);
198
199
  void attachToPreprocessor(Preprocessor &PP) override;
200
  void attachToASTReader(ASTReader &R) override;
201
202
private:
203
  friend ModuleDepCollectorPP;
204
205
  /// The compiler instance for the current translation unit.
206
  CompilerInstance &Instance;
207
  /// The consumer of collected dependency information.
208
  DependencyConsumer &Consumer;
209
  /// Path to the main source file.
210
  std::string MainFile;
211
  /// Hash identifying the compilation conditions of the current TU.
212
  std::string ContextHash;
213
  /// Non-modular file dependencies. This includes the main source file and
214
  /// textually included header files.
215
  std::vector<std::string> FileDeps;
216
  /// Direct and transitive modular dependencies of the main source file.
217
  std::unordered_map<const Module *, ModuleDeps> ModularDeps;
218
  /// Options that control the dependency output generation.
219
  std::unique_ptr<DependencyOutputOptions> Opts;
220
  /// The original Clang invocation passed to dependency scanner.
221
  CompilerInvocation OriginalInvocation;
222
223
  /// Checks whether the module is known as being prebuilt.
224
  bool isPrebuiltModule(const Module *M);
225
226
  /// Constructs a CompilerInvocation that can be used to build the given
227
  /// module, excluding paths to discovered modular dependencies that are yet to
228
  /// be built.
229
  CompilerInvocation
230
  makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps) const;
231
};
232
233
} // end namespace dependencies
234
} // end namespace tooling
235
} // end namespace clang
236
237
#endif // LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H