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 StoragePath The path to a directory, in which to create a temporary
79   /// file to store PCH in. If empty, the default system temporary directory is
80   /// used. This parameter is ignored if \p StoreInMemory is true.
81   ///
82   /// \param Callbacks A set of callbacks to be executed when building
83   /// the preamble.
84   static llvm::ErrorOr<PrecompiledPreamble>
85   Build(const CompilerInvocation &Invocation,
86         const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
87         DiagnosticsEngine &Diagnostics,
88         IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
89         std::shared_ptr<PCHContainerOperations> PCHContainerOps,
90         bool StoreInMemory, StringRef StoragePath,
91         PreambleCallbacks &Callbacks);
92 
93   PrecompiledPreamble(PrecompiledPreamble &&);
94   PrecompiledPreamble &operator=(PrecompiledPreamble &&);
95   ~PrecompiledPreamble();
96 
97   /// PreambleBounds used to build the preamble.
98   PreambleBounds getBounds() const;
99 
100   /// Returns the size, in bytes, that preamble takes on disk or in memory.
101   /// For on-disk preambles returns 0 if filesystem operations fail. Intended to
102   /// be used for logging and debugging purposes only.
103   std::size_t getSize() const;
104 
105   /// Returned string is not null-terminated.
106   llvm::StringRef getContents() const {
107     return {PreambleBytes.data(), PreambleBytes.size()};
108   }
109 
110   /// Check whether PrecompiledPreamble can be reused for the new contents(\p
111   /// MainFileBuffer) of the main file.
112   bool CanReuse(const CompilerInvocation &Invocation,
113                 const llvm::MemoryBufferRef &MainFileBuffer,
114                 PreambleBounds Bounds, llvm::vfs::FileSystem &VFS) const;
115 
116   /// Changes options inside \p CI to use PCH from this preamble. Also remaps
117   /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble
118   /// is accessible.
119   /// Requires that CanReuse() is true.
120   /// For in-memory preambles, PrecompiledPreamble instance continues to own the
121   /// MemoryBuffer with the Preamble after this method returns. The caller is
122   /// responsible for making sure the PrecompiledPreamble instance outlives the
123   /// compiler run and the AST that will be using the PCH.
124   void AddImplicitPreamble(CompilerInvocation &CI,
125                            IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
126                            llvm::MemoryBuffer *MainFileBuffer) const;
127 
128   /// Configure \p CI to use this preamble.
129   /// Like AddImplicitPreamble, but doesn't assume CanReuse() is true.
130   /// If this preamble does not match the file, it may parse differently.
131   void OverridePreamble(CompilerInvocation &CI,
132                         IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
133                         llvm::MemoryBuffer *MainFileBuffer) const;
134 
135 private:
136   PrecompiledPreamble(std::unique_ptr<PCHStorage> Storage,
137                       std::vector<char> PreambleBytes,
138                       bool PreambleEndsAtStartOfLine,
139                       llvm::StringMap<PreambleFileHash> FilesInPreamble,
140                       llvm::StringSet<> MissingFiles);
141 
142   /// Data used to determine if a file used in the preamble has been changed.
143   struct PreambleFileHash {
144     /// All files have size set.
145     off_t Size = 0;
146 
147     /// Modification time is set for files that are on disk.  For memory
148     /// buffers it is zero.
149     time_t ModTime = 0;
150 
151     /// Memory buffers have MD5 instead of modification time.  We don't
152     /// compute MD5 for on-disk files because we hope that modification time is
153     /// enough to tell if the file was changed.
154     llvm::MD5::MD5Result MD5 = {};
155 
156     static PreambleFileHash createForFile(off_t Size, time_t ModTime);
157     static PreambleFileHash
158     createForMemoryBuffer(const llvm::MemoryBufferRef &Buffer);
159 
160     friend bool operator==(const PreambleFileHash &LHS,
161                            const PreambleFileHash &RHS) {
162       return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
163              LHS.MD5 == RHS.MD5;
164     }
165     friend bool operator!=(const PreambleFileHash &LHS,
166                            const PreambleFileHash &RHS) {
167       return !(LHS == RHS);
168     }
169   };
170 
171   /// Helper function to set up PCH for the preamble into \p CI and \p VFS to
172   /// with the specified \p Bounds.
173   void configurePreamble(PreambleBounds Bounds, CompilerInvocation &CI,
174                          IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
175                          llvm::MemoryBuffer *MainFileBuffer) const;
176 
177   /// Sets up the PreprocessorOptions and changes VFS, so that PCH stored in \p
178   /// Storage is accessible to clang. This method is an implementation detail of
179   /// AddImplicitPreamble.
180   static void
181   setupPreambleStorage(const PCHStorage &Storage,
182                        PreprocessorOptions &PreprocessorOpts,
183                        IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS);
184 
185   /// Manages the memory buffer or temporary file that stores the PCH.
186   std::unique_ptr<PCHStorage> Storage;
187   /// Keeps track of the files that were used when computing the
188   /// preamble, with both their buffer size and their modification time.
189   ///
190   /// If any of the files have changed from one compile to the next,
191   /// the preamble must be thrown away.
192   llvm::StringMap<PreambleFileHash> FilesInPreamble;
193   /// Files that were not found during preamble building. If any of these now
194   /// exist then the preamble should not be reused.
195   ///
196   /// Storing *all* the missing files that could invalidate the preamble would
197   /// make it too expensive to revalidate (when the include path has many
198   /// entries, each #include will miss half of them on average).
199   /// Instead, we track only files that could have satisfied an #include that
200   /// was ultimately not found.
201   llvm::StringSet<> MissingFiles;
202   /// The contents of the file that was used to precompile the preamble. Only
203   /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
204   /// part of the file has not changed, so that preamble can be reused.
205   std::vector<char> PreambleBytes;
206   /// See PreambleBounds::PreambleEndsAtStartOfLine
207   bool PreambleEndsAtStartOfLine;
208 };
209 
210 /// A set of callbacks to gather useful information while building a preamble.
211 class PreambleCallbacks {
212 public:
213   virtual ~PreambleCallbacks() = default;
214 
215   /// Called before FrontendAction::Execute.
216   /// Can be used to store references to various CompilerInstance fields
217   /// (e.g. SourceManager) that may be interesting to the consumers of other
218   /// callbacks.
219   virtual void BeforeExecute(CompilerInstance &CI);
220   /// Called after FrontendAction::Execute(), but before
221   /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
222   /// various CompilerInstance fields before they are destroyed.
223   virtual void AfterExecute(CompilerInstance &CI);
224   /// Called after PCH has been emitted. \p Writer may be used to retrieve
225   /// information about AST, serialized in PCH.
226   virtual void AfterPCHEmitted(ASTWriter &Writer);
227   /// Called for each TopLevelDecl.
228   /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
229   /// used instead, but having only this method allows a simpler API.
230   virtual void HandleTopLevelDecl(DeclGroupRef DG);
231   /// Creates wrapper class for PPCallbacks so we can also process information
232   /// about includes that are inside of a preamble. Called after BeforeExecute.
233   virtual std::unique_ptr<PPCallbacks> createPPCallbacks();
234   /// The returned CommentHandler will be added to the preprocessor if not null.
235   virtual CommentHandler *getCommentHandler();
236   /// Determines which function bodies are parsed, by default skips everything.
237   /// Only used if FrontendOpts::SkipFunctionBodies is true.
238   /// See ASTConsumer::shouldSkipFunctionBody.
239   virtual bool shouldSkipFunctionBody(Decl *D) { return true; }
240 };
241 
242 enum class BuildPreambleError {
243   CouldntCreateTempFile = 1,
244   CouldntCreateTargetInfo,
245   BeginSourceFileFailed,
246   CouldntEmitPCH,
247   BadInputs
248 };
249 
250 class BuildPreambleErrorCategory final : public std::error_category {
251 public:
252   const char *name() const noexcept override;
253   std::string message(int condition) const override;
254 };
255 
256 std::error_code make_error_code(BuildPreambleError Error);
257 } // namespace clang
258 
259 namespace std {
260 template <>
261 struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
262 } // namespace std
263 
264 #endif
265