Coverage Report

Created: 2021-08-24 07:12

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Frontend/PrecompiledPreamble.h
Line
Count
Source (jump to first uncovered line)
1
//===--- PrecompiledPreamble.h - Build precompiled preambles ----*- 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
// Helper class to build precompiled preamble.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#ifndef LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H
14
#define LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H
15
16
#include "clang/Lex/Lexer.h"
17
#include "clang/Lex/Preprocessor.h"
18
#include "llvm/ADT/IntrusiveRefCntPtr.h"
19
#include "llvm/ADT/StringRef.h"
20
#include "llvm/Support/AlignOf.h"
21
#include "llvm/Support/MD5.h"
22
#include <cstddef>
23
#include <memory>
24
#include <system_error>
25
#include <type_traits>
26
27
namespace llvm {
28
class MemoryBuffer;
29
class MemoryBufferRef;
30
namespace vfs {
31
class FileSystem;
32
}
33
} // namespace llvm
34
35
namespace clang {
36
class CompilerInstance;
37
class CompilerInvocation;
38
class Decl;
39
class DeclGroupRef;
40
class PCHContainerOperations;
41
42
/// Runs lexer to compute suggested preamble bounds.
43
PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
44
                                     const llvm::MemoryBufferRef &Buffer,
45
                                     unsigned MaxLines);
46
47
class PreambleCallbacks;
48
49
/// A class holding a PCH and all information to check whether it is valid to
50
/// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and
51
/// CanReusePreamble + AddImplicitPreamble to make use of it.
52
class PrecompiledPreamble {
53
  class PCHStorage;
54
  struct PreambleFileHash;
55
56
public:
57
  /// Try to build PrecompiledPreamble for \p Invocation. See
58
  /// BuildPreambleError for possible error codes.
59
  ///
60
  /// \param Invocation Original CompilerInvocation with options to compile the
61
  /// file.
62
  ///
63
  /// \param MainFileBuffer Buffer with the contents of the main file.
64
  ///
65
  /// \param Bounds Bounds of the preamble, result of calling
66
  /// ComputePreambleBounds.
67
  ///
68
  /// \param Diagnostics Diagnostics engine to be used while building the
69
  /// preamble.
70
  ///
71
  /// \param VFS An instance of vfs::FileSystem to be used for file
72
  /// accesses.
73
  ///
74
  /// \param PCHContainerOps An instance of PCHContainerOperations.
75
  ///
76
  /// \param StoreInMemory Store PCH in memory. If false, PCH will be stored in
77
  /// a temporary file.
78
  ///
79
  /// \param Callbacks A set of callbacks to be executed when building
80
  /// the preamble.
81
  static llvm::ErrorOr<PrecompiledPreamble>
82
  Build(const CompilerInvocation &Invocation,
83
        const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
84
        DiagnosticsEngine &Diagnostics,
85
        IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
86
        std::shared_ptr<PCHContainerOperations> PCHContainerOps,
87
        bool StoreInMemory, PreambleCallbacks &Callbacks);
88
89
180
  PrecompiledPreamble(PrecompiledPreamble &&) = default;
90
0
  PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default;
91
92
  /// PreambleBounds used to build the preamble.
93
  PreambleBounds getBounds() const;
94
95
  /// Returns the size, in bytes, that preamble takes on disk or in memory.
96
  /// For on-disk preambles returns 0 if filesystem operations fail. Intended to
97
  /// be used for logging and debugging purposes only.
98
  std::size_t getSize() const;
99
100
  /// Returned string is not null-terminated.
101
0
  llvm::StringRef getContents() const {
102
0
    return {PreambleBytes.data(), PreambleBytes.size()};
103
0
  }
104
105
  /// Check whether PrecompiledPreamble can be reused for the new contents(\p
106
  /// MainFileBuffer) of the main file.
107
  bool CanReuse(const CompilerInvocation &Invocation,
108
                const llvm::MemoryBufferRef &MainFileBuffer,
109
                PreambleBounds Bounds, llvm::vfs::FileSystem &VFS) const;
110
111
  /// Changes options inside \p CI to use PCH from this preamble. Also remaps
112
  /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble
113
  /// is accessible.
114
  /// Requires that CanReuse() is true.
115
  /// For in-memory preambles, PrecompiledPreamble instance continues to own the
116
  /// MemoryBuffer with the Preamble after this method returns. The caller is
117
  /// responsible for making sure the PrecompiledPreamble instance outlives the
118
  /// compiler run and the AST that will be using the PCH.
119
  void AddImplicitPreamble(CompilerInvocation &CI,
120
                           IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
121
                           llvm::MemoryBuffer *MainFileBuffer) const;
122
123
  /// Configure \p CI to use this preamble.
124
  /// Like AddImplicitPreamble, but doesn't assume CanReuse() is true.
125
  /// If this preamble does not match the file, it may parse differently.
126
  void OverridePreamble(CompilerInvocation &CI,
127
                        IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
128
                        llvm::MemoryBuffer *MainFileBuffer) const;
129
130
private:
131
  PrecompiledPreamble(PCHStorage Storage, std::vector<char> PreambleBytes,
132
                      bool PreambleEndsAtStartOfLine,
133
                      llvm::StringMap<PreambleFileHash> FilesInPreamble,
134
                      llvm::StringSet<> MissingFiles);
135
136
  /// A temp file that would be deleted on destructor call. If destructor is not
137
  /// called for any reason, the file will be deleted at static objects'
138
  /// destruction.
139
  /// An assertion will fire if two TempPCHFiles are created with the same name,
140
  /// so it's not intended to be used outside preamble-handling.
141
  class TempPCHFile {
142
  public:
143
    // A main method used to construct TempPCHFile.
144
    static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile();
145
146
  private:
147
    TempPCHFile(std::string FilePath);
148
149
  public:
150
    TempPCHFile(TempPCHFile &&Other);
151
    TempPCHFile &operator=(TempPCHFile &&Other);
152
153
    TempPCHFile(const TempPCHFile &) = delete;
154
    ~TempPCHFile();
155
156
    /// A path where temporary file is stored.
157
    llvm::StringRef getFilePath() const;
158
159
  private:
160
    void RemoveFileIfPresent();
161
162
  private:
163
    llvm::Optional<std::string> FilePath;
164
  };
165
166
  class InMemoryPreamble {
167
  public:
168
    std::string Data;
169
  };
170
171
  class PCHStorage {
172
  public:
173
    enum class Kind { Empty, InMemory, TempFile };
174
175
360
    PCHStorage() = default;
176
    PCHStorage(TempPCHFile File);
177
    PCHStorage(InMemoryPreamble Memory);
178
179
    PCHStorage(const PCHStorage &) = delete;
180
    PCHStorage &operator=(const PCHStorage &) = delete;
181
182
    PCHStorage(PCHStorage &&Other);
183
    PCHStorage &operator=(PCHStorage &&Other);
184
185
    ~PCHStorage();
186
187
    Kind getKind() const;
188
189
    TempPCHFile &asFile();
190
    const TempPCHFile &asFile() const;
191
192
    InMemoryPreamble &asMemory();
193
    const InMemoryPreamble &asMemory() const;
194
195
  private:
196
    void destroy();
197
    void setEmpty();
198
199
  private:
200
    Kind StorageKind = Kind::Empty;
201
    llvm::AlignedCharArrayUnion<TempPCHFile, InMemoryPreamble> Storage = {};
202
  };
203
204
  /// Data used to determine if a file used in the preamble has been changed.
205
  struct PreambleFileHash {
206
    /// All files have size set.
207
    off_t Size = 0;
208
209
    /// Modification time is set for files that are on disk.  For memory
210
    /// buffers it is zero.
211
    time_t ModTime = 0;
212
213
    /// Memory buffers have MD5 instead of modification time.  We don't
214
    /// compute MD5 for on-disk files because we hope that modification time is
215
    /// enough to tell if the file was changed.
216
    llvm::MD5::MD5Result MD5 = {};
217
218
    static PreambleFileHash createForFile(off_t Size, time_t ModTime);
219
    static PreambleFileHash
220
    createForMemoryBuffer(const llvm::MemoryBufferRef &Buffer);
221
222
    friend bool operator==(const PreambleFileHash &LHS,
223
6
                           const PreambleFileHash &RHS) {
224
6
      return LHS.Size == RHS.Size && 
LHS.ModTime == RHS.ModTime5
&&
225
6
             
LHS.MD5 == RHS.MD55
;
226
6
    }
227
    friend bool operator!=(const PreambleFileHash &LHS,
228
6
                           const PreambleFileHash &RHS) {
229
6
      return !(LHS == RHS);
230
6
    }
231
  };
232
233
  /// Helper function to set up PCH for the preamble into \p CI and \p VFS to
234
  /// with the specified \p Bounds.
235
  void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI,
236
                         IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
237
                         llvm::MemoryBuffer *MainFileBuffer) const;
238
239
  /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p
240
  /// Storage is accessible to clang. This method is an implementation detail of
241
  /// AddImplicitPreamble.
242
  static void
243
  setupPreambleStorage(const PCHStorage &Storage,
244
                       PreprocessorOptions &PreprocessorOpts,
245
                       IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS);
246
247
  /// Manages the memory buffer or temporary file that stores the PCH.
248
  PCHStorage Storage;
249
  /// Keeps track of the files that were used when computing the
250
  /// preamble, with both their buffer size and their modification time.
251
  ///
252
  /// If any of the files have changed from one compile to the next,
253
  /// the preamble must be thrown away.
254
  llvm::StringMap<PreambleFileHash> FilesInPreamble;
255
  /// Files that were not found during preamble building. If any of these now
256
  /// exist then the preamble should not be reused.
257
  ///
258
  /// Storing *all* the missing files that could invalidate the preamble would
259
  /// make it too expensive to revalidate (when the include path has many
260
  /// entries, each #include will miss half of them on average).
261
  /// Instead, we track only files that could have satisfied an #include that
262
  /// was ultimately not found.
263
  llvm::StringSet<> MissingFiles;
264
  /// The contents of the file that was used to precompile the preamble. Only
265
  /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
266
  /// part of the file has not changed, so that preamble can be reused.
267
  std::vector<char> PreambleBytes;
268
  /// See PreambleBounds::PreambleEndsAtStartOfLine
269
  bool PreambleEndsAtStartOfLine;
270
};
271
272
/// A set of callbacks to gather useful information while building a preamble.
273
class PreambleCallbacks {
274
public:
275
90
  virtual ~PreambleCallbacks() = default;
276
277
  /// Called before FrontendAction::BeginSourceFile.
278
  /// Can be used to store references to various CompilerInstance fields
279
  /// (e.g. SourceManager) that may be interesting to the consumers of other
280
  /// callbacks.
281
  virtual void BeforeExecute(CompilerInstance &CI);
282
  /// Called after FrontendAction::Execute(), but before
283
  /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
284
  /// various CompilerInstance fields before they are destroyed.
285
  virtual void AfterExecute(CompilerInstance &CI);
286
  /// Called after PCH has been emitted. \p Writer may be used to retrieve
287
  /// information about AST, serialized in PCH.
288
  virtual void AfterPCHEmitted(ASTWriter &Writer);
289
  /// Called for each TopLevelDecl.
290
  /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
291
  /// used instead, but having only this method allows a simpler API.
292
  virtual void HandleTopLevelDecl(DeclGroupRef DG);
293
  /// Creates wrapper class for PPCallbacks so we can also process information
294
  /// about includes that are inside of a preamble
295
  virtual std::unique_ptr<PPCallbacks> createPPCallbacks();
296
  /// The returned CommentHandler will be added to the preprocessor if not null.
297
  virtual CommentHandler *getCommentHandler();
298
  /// Determines which function bodies are parsed, by default skips everything.
299
  /// Only used if FrontendOpts::SkipFunctionBodies is true.
300
  /// See ASTConsumer::shouldSkipFunctionBody.
301
1
  virtual bool shouldSkipFunctionBody(Decl *D) { return true; }
302
};
303
304
enum class BuildPreambleError {
305
  CouldntCreateTempFile = 1,
306
  CouldntCreateTargetInfo,
307
  BeginSourceFileFailed,
308
  CouldntEmitPCH,
309
  BadInputs
310
};
311
312
class BuildPreambleErrorCategory final : public std::error_category {
313
public:
314
  const char *name() const noexcept override;
315
  std::string message(int condition) const override;
316
};
317
318
std::error_code make_error_code(BuildPreambleError Error);
319
} // namespace clang
320
321
namespace std {
322
template <>
323
struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
324
} // namespace std
325
326
#endif