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   PrecompiledPreamble(PrecompiledPreamble &&) = default;
90   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   llvm::StringRef getContents() const {
102     return {PreambleBytes.data(), PreambleBytes.size()};
103   }
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     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                            const PreambleFileHash &RHS) {
224       return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
225              LHS.MD5 == RHS.MD5;
226     }
227     friend bool operator!=(const PreambleFileHash &LHS,
228                            const PreambleFileHash &RHS) {
229       return !(LHS == RHS);
230     }
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   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   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
327