Coverage Report

Created: 2022-07-16 07:03

/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_PRECOMPILEDPREAMBLE_H
14
#define LLVM_CLANG_FRONTEND_PRECOMPILEDPREAMBLE_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/MD5.h"
21
#include <cstddef>
22
#include <memory>
23
#include <system_error>
24
#include <type_traits>
25
26
namespace llvm {
27
class MemoryBuffer;
28
class MemoryBufferRef;
29
namespace vfs {
30
class FileSystem;
31
}
32
} // namespace llvm
33
34
namespace clang {
35
class CompilerInstance;
36
class CompilerInvocation;
37
class Decl;
38
class DeclGroupRef;
39
class PCHContainerOperations;
40
41
/// Runs lexer to compute suggested preamble bounds.
42
PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
43
                                     const llvm::MemoryBufferRef &Buffer,
44
                                     unsigned MaxLines);
45
46
class PreambleCallbacks;
47
48
/// A class holding a PCH and all information to check whether it is valid to
49
/// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and
50
/// CanReusePreamble + AddImplicitPreamble to make use of it.
51
class PrecompiledPreamble {
52
  class PCHStorage;
53
  struct PreambleFileHash;
54
55
public:
56
  /// Try to build PrecompiledPreamble for \p Invocation. See
57
  /// BuildPreambleError for possible error codes.
58
  ///
59
  /// \param Invocation Original CompilerInvocation with options to compile the
60
  /// file.
61
  ///
62
  /// \param MainFileBuffer Buffer with the contents of the main file.
63
  ///
64
  /// \param Bounds Bounds of the preamble, result of calling
65
  /// ComputePreambleBounds.
66
  ///
67
  /// \param Diagnostics Diagnostics engine to be used while building the
68
  /// preamble.
69
  ///
70
  /// \param VFS An instance of vfs::FileSystem to be used for file
71
  /// accesses.
72
  ///
73
  /// \param PCHContainerOps An instance of PCHContainerOperations.
74
  ///
75
  /// \param StoreInMemory Store PCH in memory. If false, PCH will be stored in
76
  /// a temporary file.
77
  ///
78
  /// \param Callbacks A set of callbacks to be executed when building
79
  /// the preamble.
80
  static llvm::ErrorOr<PrecompiledPreamble>
81
  Build(const CompilerInvocation &Invocation,
82
        const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
83
        DiagnosticsEngine &Diagnostics,
84
        IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
85
        std::shared_ptr<PCHContainerOperations> PCHContainerOps,
86
        bool StoreInMemory, PreambleCallbacks &Callbacks);
87
88
  PrecompiledPreamble(PrecompiledPreamble &&);
89
  PrecompiledPreamble &operator=(PrecompiledPreamble &&);
90
  ~PrecompiledPreamble();
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(std::unique_ptr<PCHStorage> Storage,
132
                      std::vector<char> PreambleBytes,
133
                      bool PreambleEndsAtStartOfLine,
134
                      llvm::StringMap<PreambleFileHash> FilesInPreamble,
135
                      llvm::StringSet<> MissingFiles);
136
137
  /// Data used to determine if a file used in the preamble has been changed.
138
  struct PreambleFileHash {
139
    /// All files have size set.
140
    off_t Size = 0;
141
142
    /// Modification time is set for files that are on disk.  For memory
143
    /// buffers it is zero.
144
    time_t ModTime = 0;
145
146
    /// Memory buffers have MD5 instead of modification time.  We don't
147
    /// compute MD5 for on-disk files because we hope that modification time is
148
    /// enough to tell if the file was changed.
149
    llvm::MD5::MD5Result MD5 = {};
150
151
    static PreambleFileHash createForFile(off_t Size, time_t ModTime);
152
    static PreambleFileHash
153
    createForMemoryBuffer(const llvm::MemoryBufferRef &Buffer);
154
155
    friend bool operator==(const PreambleFileHash &LHS,
156
6
                           const PreambleFileHash &RHS) {
157
6
      return LHS.Size == RHS.Size && 
LHS.ModTime == RHS.ModTime5
&&
158
6
             
LHS.MD5 == RHS.MD55
;
159
6
    }
160
    friend bool operator!=(const PreambleFileHash &LHS,
161
6
                           const PreambleFileHash &RHS) {
162
6
      return !(LHS == RHS);
163
6
    }
164
  };
165
166
  /// Helper function to set up PCH for the preamble into \p CI and \p VFS to
167
  /// with the specified \p Bounds.
168
  void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI,
169
                         IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
170
                         llvm::MemoryBuffer *MainFileBuffer) const;
171
172
  /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p
173
  /// Storage is accessible to clang. This method is an implementation detail of
174
  /// AddImplicitPreamble.
175
  static void
176
  setupPreambleStorage(const PCHStorage &Storage,
177
                       PreprocessorOptions &PreprocessorOpts,
178
                       IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS);
179
180
  /// Manages the memory buffer or temporary file that stores the PCH.
181
  std::unique_ptr<PCHStorage> Storage;
182
  /// Keeps track of the files that were used when computing the
183
  /// preamble, with both their buffer size and their modification time.
184
  ///
185
  /// If any of the files have changed from one compile to the next,
186
  /// the preamble must be thrown away.
187
  llvm::StringMap<PreambleFileHash> FilesInPreamble;
188
  /// Files that were not found during preamble building. If any of these now
189
  /// exist then the preamble should not be reused.
190
  ///
191
  /// Storing *all* the missing files that could invalidate the preamble would
192
  /// make it too expensive to revalidate (when the include path has many
193
  /// entries, each #include will miss half of them on average).
194
  /// Instead, we track only files that could have satisfied an #include that
195
  /// was ultimately not found.
196
  llvm::StringSet<> MissingFiles;
197
  /// The contents of the file that was used to precompile the preamble. Only
198
  /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
199
  /// part of the file has not changed, so that preamble can be reused.
200
  std::vector<char> PreambleBytes;
201
  /// See PreambleBounds::PreambleEndsAtStartOfLine
202
  bool PreambleEndsAtStartOfLine;
203
};
204
205
/// A set of callbacks to gather useful information while building a preamble.
206
class PreambleCallbacks {
207
public:
208
91
  virtual ~PreambleCallbacks() = default;
209
210
  /// Called before FrontendAction::Execute.
211
  /// Can be used to store references to various CompilerInstance fields
212
  /// (e.g. SourceManager) that may be interesting to the consumers of other
213
  /// callbacks.
214
  virtual void BeforeExecute(CompilerInstance &CI);
215
  /// Called after FrontendAction::Execute(), but before
216
  /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
217
  /// various CompilerInstance fields before they are destroyed.
218
  virtual void AfterExecute(CompilerInstance &CI);
219
  /// Called after PCH has been emitted. \p Writer may be used to retrieve
220
  /// information about AST, serialized in PCH.
221
  virtual void AfterPCHEmitted(ASTWriter &Writer);
222
  /// Called for each TopLevelDecl.
223
  /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
224
  /// used instead, but having only this method allows a simpler API.
225
  virtual void HandleTopLevelDecl(DeclGroupRef DG);
226
  /// Creates wrapper class for PPCallbacks so we can also process information
227
  /// about includes that are inside of a preamble. Called after BeforeExecute.
228
  virtual std::unique_ptr<PPCallbacks> createPPCallbacks();
229
  /// The returned CommentHandler will be added to the preprocessor if not null.
230
  virtual CommentHandler *getCommentHandler();
231
  /// Determines which function bodies are parsed, by default skips everything.
232
  /// Only used if FrontendOpts::SkipFunctionBodies is true.
233
  /// See ASTConsumer::shouldSkipFunctionBody.
234
1
  virtual bool shouldSkipFunctionBody(Decl *D) { return true; }
235
};
236
237
enum class BuildPreambleError {
238
  CouldntCreateTempFile = 1,
239
  CouldntCreateTargetInfo,
240
  BeginSourceFileFailed,
241
  CouldntEmitPCH,
242
  BadInputs
243
};
244
245
class BuildPreambleErrorCategory final : public std::error_category {
246
public:
247
  const char *name() const noexcept override;
248
  std::string message(int condition) const override;
249
};
250
251
std::error_code make_error_code(BuildPreambleError Error);
252
} // namespace clang
253
254
namespace std {
255
template <>
256
struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
257
} // namespace std
258
259
#endif