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 { 50 PreambleData(const ParseInputs &Inputs, PrecompiledPreamble Preamble, 51 std::vector<Diag> Diags, IncludeStructure Includes, 52 MainFileMacros Macros, 53 std::unique_ptr<PreambleFileStatusCache> StatCache, 54 CanonicalIncludes CanonIncludes); 55 56 // Version of the ParseInputs this preamble was built from. 57 std::string Version; 58 tooling::CompileCommand CompileCommand; 59 PrecompiledPreamble Preamble; 60 std::vector<Diag> Diags; 61 // Processes like code completions and go-to-definitions will need #include 62 // information, and their compile action skips preamble range. 63 IncludeStructure Includes; 64 // Macros defined in the preamble section of the main file. 65 // Users care about headers vs main-file, not preamble vs non-preamble. 66 // These should be treated as main-file entities e.g. for code completion. 67 MainFileMacros Macros; 68 // Cache of FS operations performed when building the preamble. 69 // When reusing a preamble, this cache can be consumed to save IO. 70 std::unique_ptr<PreambleFileStatusCache> StatCache; 71 CanonicalIncludes CanonIncludes; 72 }; 73 74 using PreambleParsedCallback = 75 std::function<void(ASTContext &, std::shared_ptr<clang::Preprocessor>, 76 const CanonicalIncludes &)>; 77 78 /// Build a preamble for the new inputs unless an old one can be reused. 79 /// If \p PreambleCallback is set, it will be run on top of the AST while 80 /// building the preamble. 81 std::shared_ptr<const PreambleData> 82 buildPreamble(PathRef FileName, CompilerInvocation CI, 83 const ParseInputs &Inputs, bool StoreInMemory, 84 PreambleParsedCallback PreambleCallback); 85 86 /// Returns true if \p Preamble is reusable for \p Inputs. Note that it will 87 /// return true when some missing headers are now available. 88 /// FIXME: Should return more information about the delta between \p Preamble 89 /// and \p Inputs, e.g. new headers. 90 bool isPreambleCompatible(const PreambleData &Preamble, 91 const ParseInputs &Inputs, PathRef FileName, 92 const CompilerInvocation &CI); 93 94 /// Stores information required to parse a TU using a (possibly stale) Baseline 95 /// preamble. Later on this information can be injected into the main file by 96 /// updating compiler invocation with \c apply. This injected section 97 /// approximately reflects additions to the preamble in Modified contents, e.g. 98 /// new include directives. 99 class PreamblePatch { 100 public: 101 /// \p Preamble is used verbatim. 102 static PreamblePatch unmodified(const PreambleData &Preamble); 103 /// Builds a patch that contains new PP directives introduced to the preamble 104 /// section of \p Modified compared to \p Baseline. 105 /// FIXME: This only handles include directives, we should at least handle 106 /// define/undef. 107 static PreamblePatch create(llvm::StringRef FileName, 108 const ParseInputs &Modified, 109 const PreambleData &Baseline); 110 /// Adjusts CI (which compiles the modified inputs) to be used with the 111 /// baseline preamble. This is done by inserting an artifical include to the 112 /// \p CI that contains new directives calculated in create. 113 void apply(CompilerInvocation &CI) const; 114 115 /// Returns #include directives from the \c Modified preamble that were 116 /// resolved using the \c Baseline preamble. This covers the new locations of 117 /// inclusions that were moved around, but not inclusions of new files. Those 118 /// will be recorded when parsing the main file: the includes in the injected 119 /// section will be resolved back to their spelled positions in the main file 120 /// using the presumed-location mechanism. 121 std::vector<Inclusion> preambleIncludes() const; 122 123 /// Returns preamble bounds for the Modified. modifiedBounds()124 PreambleBounds modifiedBounds() const { return ModifiedBounds; } 125 126 /// Returns textual patch contents. text()127 llvm::StringRef text() const { return PatchContents; } 128 129 private: 130 PreamblePatch() = default; 131 std::string PatchContents; 132 std::string PatchFileName; 133 /// Includes that are present in both \p Baseline and \p Modified. Used for 134 /// patching includes of baseline preamble. 135 std::vector<Inclusion> PreambleIncludes; 136 PreambleBounds ModifiedBounds = {0, false}; 137 }; 138 139 /// Translates locations inside preamble patch to their main-file equivalent 140 /// using presumed locations. Returns \p Loc if it isn't inside preamble patch. 141 SourceLocation translatePreamblePatchLocation(SourceLocation Loc, 142 const SourceManager &SM); 143 144 } // namespace clangd 145 } // namespace clang 146 147 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_PREAMBLE_H 148