Coverage Report

Created: 2019-02-20 07:29

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