1 //===--- Preamble.h - Reusing expensive parts of the AST ---------*- 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 // The vast majority of code in a typical translation unit is in the headers
10 // included at the top of the file.
11 //
12 // The preamble optimization says that we can parse this code once, and reuse
13 // the result multiple times. The preamble is invalidated by changes to the
14 // code in the preamble region, to the compile command, or to files on disk.
15 //
16 // This is the most important optimization in clangd: it allows operations like
17 // code-completion to have sub-second latency. It is supported by the
18 // PrecompiledPreamble functionality in clang, which wraps the techniques used
19 // by PCH files, modules etc into a convenient interface.
20 //
21 //===----------------------------------------------------------------------===//
22 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PREAMBLE_H
23 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PREAMBLE_H
24 
25 #include "CollectMacros.h"
26 #include "Compiler.h"
27 #include "Diagnostics.h"
28 #include "FS.h"
29 #include "Headers.h"
30 #include "index/CanonicalIncludes.h"
31 #include "support/Path.h"
32 #include "clang/Frontend/CompilerInvocation.h"
33 #include "clang/Frontend/PrecompiledPreamble.h"
34 #include "clang/Lex/Lexer.h"
35 #include "clang/Tooling/CompilationDatabase.h"
36 #include "llvm/ADT/StringRef.h"
37 
38 #include <memory>
39 #include <string>
40 #include <vector>
41 
42 namespace clang {
43 namespace clangd {
44 
45 /// The parsed preamble and associated data.
46 ///
47 /// As we must avoid re-parsing the preamble, any information that can only
48 /// be obtained during parsing must be eagerly captured and stored here.
49 struct PreambleData {
PreambleDataPreambleData50   PreambleData(PrecompiledPreamble Preamble) : Preamble(std::move(Preamble)) {}
51 
52   // Version of the ParseInputs this preamble was built from.
53   std::string Version;
54   tooling::CompileCommand CompileCommand;
55   PrecompiledPreamble Preamble;
56   std::vector<Diag> Diags;
57   // Processes like code completions and go-to-definitions will need #include
58   // information, and their compile action skips preamble range.
59   IncludeStructure Includes;
60   // Macros defined in the preamble section of the main file.
61   // Users care about headers vs main-file, not preamble vs non-preamble.
62   // These should be treated as main-file entities e.g. for code completion.
63   MainFileMacros Macros;
64   // Pragma marks defined in the preamble section of the main file.
65   std::vector<PragmaMark> Marks;
66   // Cache of FS operations performed when building the preamble.
67   // When reusing a preamble, this cache can be consumed to save IO.
68   std::unique_ptr<PreambleFileStatusCache> StatCache;
69   CanonicalIncludes CanonIncludes;
70   // Whether there was a (possibly-incomplete) include-guard on the main file.
71   // We need to propagate this information "by hand" to subsequent parses.
72   bool MainIsIncludeGuarded = false;
73 };
74 
75 using PreambleParsedCallback = std::function<void(ASTContext &, Preprocessor &,
76                                                   const CanonicalIncludes &)>;
77 
78 /// Timings and statistics from the premble build. Unlike PreambleData, these
79 /// do not need to be stored for later, but can be useful for logging, metrics,
80 /// etc.
81 struct PreambleBuildStats {
82   /// Total wall time it took to build preamble, in seconds.
83   double TotalBuildTime;
84   /// Time spent in filesystem operations during the build, in seconds.
85   double FileSystemTime;
86 
87   /// Estimate of the memory used while building the preamble.
88   /// This memory has been released when buildPreamble returns.
89   /// For example, this includes the size of the in-memory AST (ASTContext).
90   size_t BuildSize;
91   /// The serialized size of the preamble.
92   /// This storage is needed while the preamble is used (but may be on disk).
93   size_t SerializedSize;
94 };
95 
96 /// Build a preamble for the new inputs unless an old one can be reused.
97 /// If \p PreambleCallback is set, it will be run on top of the AST while
98 /// building the preamble.
99 /// If Stats is not non-null, build statistics will be exported there.
100 std::shared_ptr<const PreambleData>
101 buildPreamble(PathRef FileName, CompilerInvocation CI,
102               const ParseInputs &Inputs, bool StoreInMemory,
103               PreambleParsedCallback PreambleCallback,
104               PreambleBuildStats *Stats = nullptr);
105 
106 /// Returns true if \p Preamble is reusable for \p Inputs. Note that it will
107 /// return true when some missing headers are now available.
108 /// FIXME: Should return more information about the delta between \p Preamble
109 /// and \p Inputs, e.g. new headers.
110 bool isPreambleCompatible(const PreambleData &Preamble,
111                           const ParseInputs &Inputs, PathRef FileName,
112                           const CompilerInvocation &CI);
113 
114 /// Stores information required to parse a TU using a (possibly stale) Baseline
115 /// preamble. Later on this information can be injected into the main file by
116 /// updating compiler invocation with \c apply. This injected section
117 /// approximately reflects additions to the preamble in Modified contents, e.g.
118 /// new include directives.
119 class PreamblePatch {
120 public:
121   enum class PatchType { MacroDirectives, All };
122   /// \p Preamble is used verbatim.
123   static PreamblePatch unmodified(const PreambleData &Preamble);
124   /// Builds a patch that contains new PP directives introduced to the preamble
125   /// section of \p Modified compared to \p Baseline.
126   /// FIXME: This only handles include directives, we should at least handle
127   /// define/undef.
128   static PreamblePatch createFullPatch(llvm::StringRef FileName,
129                                        const ParseInputs &Modified,
130                                        const PreambleData &Baseline);
131   static PreamblePatch createMacroPatch(llvm::StringRef FileName,
132                                         const ParseInputs &Modified,
133                                         const PreambleData &Baseline);
134 
135   /// Adjusts CI (which compiles the modified inputs) to be used with the
136   /// baseline preamble. This is done by inserting an artifical include to the
137   /// \p CI that contains new directives calculated in create.
138   void apply(CompilerInvocation &CI) const;
139 
140   /// Returns #include directives from the \c Modified preamble that were
141   /// resolved using the \c Baseline preamble. This covers the new locations of
142   /// inclusions that were moved around, but not inclusions of new files. Those
143   /// will be recorded when parsing the main file: the includes in the injected
144   /// section will be resolved back to their spelled positions in the main file
145   /// using the presumed-location mechanism.
146   std::vector<Inclusion> preambleIncludes() const;
147 
148   /// Returns preamble bounds for the Modified.
modifiedBounds()149   PreambleBounds modifiedBounds() const { return ModifiedBounds; }
150 
151   /// Returns textual patch contents.
text()152   llvm::StringRef text() const { return PatchContents; }
153 
154   /// Whether diagnostics generated using this patch are trustable.
preserveDiagnostics()155   bool preserveDiagnostics() const { return PatchContents.empty(); }
156 
157 private:
158   static PreamblePatch create(llvm::StringRef FileName,
159                               const ParseInputs &Modified,
160                               const PreambleData &Baseline,
161                               PatchType PatchType);
162 
163   PreamblePatch() = default;
164   std::string PatchContents;
165   std::string PatchFileName;
166   /// Includes that are present in both \p Baseline and \p Modified. Used for
167   /// patching includes of baseline preamble.
168   std::vector<Inclusion> PreambleIncludes;
169   PreambleBounds ModifiedBounds = {0, false};
170 };
171 
172 /// Translates locations inside preamble patch to their main-file equivalent
173 /// using presumed locations. Returns \p Loc if it isn't inside preamble patch.
174 SourceLocation translatePreamblePatchLocation(SourceLocation Loc,
175                                               const SourceManager &SM);
176 
177 } // namespace clangd
178 } // namespace clang
179 
180 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_PREAMBLE_H
181