clang-tools 10.0.0

Preamble.cpp
Go to the documentation of this file.
1 //===--- Preamble.cpp - Reusing expensive parts of the AST ----------------===//
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 #include "Preamble.h"
10 #include "Logger.h"
11 #include "Trace.h"
12 #include "clang/Basic/SourceLocation.h"
13 #include "clang/Lex/PPCallbacks.h"
14 #include "clang/Lex/PreprocessorOptions.h"
15
16 namespace clang {
17 namespace clangd {
18 namespace {
19
20 bool compileCommandsAreEqual(const tooling::CompileCommand &LHS,
21 const tooling::CompileCommand &RHS) {
22 // We don't check for Output, it should not matter to clangd.
23 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
24 llvm::makeArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
25 }
26
27 class CppFilePreambleCallbacks : public PreambleCallbacks {
28 public:
29 CppFilePreambleCallbacks(PathRef File, PreambleParsedCallback ParsedCallback)
30 : File(File), ParsedCallback(ParsedCallback) {}
31
32 IncludeStructure takeIncludes() { return std::move(Includes); }
33
34 MainFileMacros takeMacros() { return std::move(Macros); }
35
36 CanonicalIncludes takeCanonicalIncludes() { return std::move(CanonIncludes); }
37
38 void AfterExecute(CompilerInstance &CI) override {
39 if (!ParsedCallback)
40 return;
41 trace::Span Tracer("Running PreambleCallback");
42 ParsedCallback(CI.getASTContext(), CI.getPreprocessorPtr(), CanonIncludes);
43 }
44
45 void BeforeExecute(CompilerInstance &CI) override {
46 CanonIncludes.addSystemHeadersMapping(CI.getLangOpts());
47 LangOpts = &CI.getLangOpts();
48 SourceMgr = &CI.getSourceManager();
49 }
50
51 std::unique_ptr<PPCallbacks> createPPCallbacks() override {
52 assert(SourceMgr && LangOpts &&
53 "SourceMgr and LangOpts must be set at this point");
54
55 return std::make_unique<PPChainedCallbacks>(
56 collectIncludeStructureCallback(*SourceMgr, &Includes),
57 std::make_unique<CollectMainFileMacros>(*SourceMgr, *LangOpts, Macros));
58 }
59
60 CommentHandler *getCommentHandler() override {
61 IWYUHandler = collectIWYUHeaderMaps(&CanonIncludes);
62 return IWYUHandler.get();
63 }
64
65 private:
66 PathRef File;
67 PreambleParsedCallback ParsedCallback;
68 IncludeStructure Includes;
69 CanonicalIncludes CanonIncludes;
70 MainFileMacros Macros;
71 std::unique_ptr<CommentHandler> IWYUHandler = nullptr;
72 const clang::LangOptions *LangOpts = nullptr;
73 const SourceManager *SourceMgr = nullptr;
74 };
75
76 } // namespace
77
78 PreambleData::PreambleData(PrecompiledPreamble Preamble,
79 std::vector<Diag> Diags, IncludeStructure Includes,
80 MainFileMacros Macros,
81 std::unique_ptr<PreambleFileStatusCache> StatCache,
82 CanonicalIncludes CanonIncludes)
83 : Preamble(std::move(Preamble)), Diags(std::move(Diags)),
84 Includes(std::move(Includes)), Macros(std::move(Macros)),
85 StatCache(std::move(StatCache)), CanonIncludes(std::move(CanonIncludes)) {
86 }
87
88 std::shared_ptr<const PreambleData>
89 buildPreamble(PathRef FileName, CompilerInvocation &CI,
90 std::shared_ptr<const PreambleData> OldPreamble,
91 const tooling::CompileCommand &OldCompileCommand,
92 const ParseInputs &Inputs, bool StoreInMemory,
93 PreambleParsedCallback PreambleCallback) {
94 // Note that we don't need to copy the input contents, preamble can live
95 // without those.
96 auto ContentsBuffer =
97 llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName);
98 auto Bounds =
99 ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
100
101 if (OldPreamble &&
102 compileCommandsAreEqual(Inputs.CompileCommand, OldCompileCommand) &&
103 OldPreamble->Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds,
104 Inputs.FS.get())) {
105 vlog("Reusing preamble for {0}", FileName);
106 return OldPreamble;
107 }
108 vlog(OldPreamble ? "Rebuilding invalidated preamble for {0}"
109 : "Building first preamble for {0}",
110 FileName);
111
112 trace::Span Tracer("BuildPreamble");
113 SPAN_ATTACH(Tracer, "File", FileName);
114 StoreDiags PreambleDiagnostics;
115 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
116 CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(),
117 &PreambleDiagnostics, false);
118
119 // Skip function bodies when building the preamble to speed up building
120 // the preamble and make it smaller.
121 assert(!CI.getFrontendOpts().SkipFunctionBodies);
122 CI.getFrontendOpts().SkipFunctionBodies = true;
123 // We don't want to write comment locations into PCH. They are racy and slow
124 // to read back. We rely on dynamic index for the comments instead.
125 CI.getPreprocessorOpts().WriteCommentListToPCH = false;
126
127 CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback);
128 if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
129 log("Couldn't set working directory when building the preamble.");
130 // We proceed anyway, our lit-tests rely on results for non-existing working
131 // dirs.
132 }
133
134 llvm::SmallString<32> AbsFileName(FileName);
135 Inputs.FS->makeAbsolute(AbsFileName);
136 auto StatCache = std::make_unique<PreambleFileStatusCache>(AbsFileName);
137 auto BuiltPreamble = PrecompiledPreamble::Build(
138 CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine,
139 StatCache->getProducingFS(Inputs.FS),
140 std::make_shared<PCHContainerOperations>(), StoreInMemory,
141 SerializedDeclsCollector);
142
143 // When building the AST for the main file, we do want the function
144 // bodies.
145 CI.getFrontendOpts().SkipFunctionBodies = false;
146
147 if (BuiltPreamble) {
148 vlog("Built preamble of size {0} for file {1}", BuiltPreamble->getSize(),
149 FileName);
150 std::vector<Diag> Diags = PreambleDiagnostics.take();
151 return std::make_shared<PreambleData>(
152 std::move(*BuiltPreamble), std::move(Diags),
153 SerializedDeclsCollector.takeIncludes(),
154 SerializedDeclsCollector.takeMacros(), std::move(StatCache),
155 SerializedDeclsCollector.takeCanonicalIncludes());
156 } else {
157 elog("Could not build a preamble for file {0}", FileName);
158 return nullptr;
159 }
160 }
161
162 } // namespace clangd
163 } // namespace clang
clang::clangd::collectIWYUHeaderMaps
std::unique_ptr< CommentHandler > collectIWYUHeaderMaps(CanonicalIncludes *Includes)
Returns a CommentHandler that parses pragma comment on include files to determine when we should incl...
Definition: CanonicalIncludes.cpp:63
clang::clangd::PreambleData::PreambleData
PreambleData(PrecompiledPreamble Preamble, std::vector< Diag > Diags, IncludeStructure Includes, MainFileMacros Macros, std::unique_ptr< PreambleFileStatusCache > StatCache, CanonicalIncludes CanonIncludes)
Definition: Preamble.cpp:78
Trace.h
clang::clangd::StoreDiags
StoreDiags collects the diagnostics that can later be reported by clangd.
Definition: Diagnostics.h:119
clang::clangd::PathRef
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:23
clang::clangd::IncludeStructure
Definition: Headers.h:109
clang::clangd::vlog
void vlog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:67
clang::clangd::elog
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:56
clang::clangd::ParseInputs::Contents
std::string Contents
Definition: Compiler.h:47
clang::clangd::MainFileMacros
Definition: CollectMacros.h:24
clang::clangd::buildPreamble
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation &CI, std::shared_ptr< const PreambleData > OldPreamble, const tooling::CompileCommand &OldCompileCommand, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback)
Build a preamble for the new inputs unless an old one can be reused.
Definition: Preamble.cpp:89
clang::clangd::CanonicalIncludes
Maps a definition location onto an #include file, based on a set of filename rules.
Definition: CanonicalIncludes.h:36
Preamble.h
clang::clangd::PreambleData::StatCache
std::unique_ptr< PreambleFileStatusCache > StatCache
Definition: Preamble.h:63
clang::clangd::log
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:62
clang::clangd::ParseInputs::CompileCommand
tooling::CompileCommand CompileCommand
Definition: Compiler.h:45
FileName
PathRef FileName
Definition: CodeComplete.cpp:1018
clang::clangd::PreambleParsedCallback
std::function< void(ASTContext &, std::shared_ptr< clang::Preprocessor >, const CanonicalIncludes &)> PreambleParsedCallback
Definition: Preamble.h:69
Logger.h
clang::clangd::ParseInputs
Information required to run clang, e.g. to parse AST or do code completion.
Definition: Compiler.h:44
Preamble
const PreambleData * Preamble
Definition: CodeComplete.cpp:1020
clang::clangd::collectIncludeStructureCallback
std::unique_ptr< PPCallbacks > collectIncludeStructureCallback(const SourceManager &SM, IncludeStructure *Out)
Returns a PPCallback that visits all inclusions in the main file.
Definition: Headers.cpp:113
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::PreambleData::Diags
std::vector< Diag > Diags
Definition: Preamble.h:53
clang::clangd::ParseInputs::FS
IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS
Definition: Compiler.h:46
clang::clangd::trace::Span
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:81
clang::clangd::CompletionItemKind::File
SPAN_ATTACH
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Definition: Trace.h:97
clang::clangd::StoreDiags::take
std::vector< Diag > take(const clang::tidy::ClangTidyContext *Tidy=nullptr)
Definition: Diagnostics.cpp:417