blob: d7a15ff0a101d05d0493e230d771cbc8b40a04e8 [file] [log] [blame]
Sam McCallcf3a5852019-09-04 07:35:00 +00001//===--- 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"
Kadir Cetinkayaecd3e672020-03-11 16:34:01 +010010#include "Compiler.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020011#include "Headers.h"
Kadir Cetinkaya717bef62020-04-23 17:44:51 +020012#include "SourceCode.h"
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +020013#include "support/FSProvider.h"
Sam McCallad97ccf2020-04-28 17:49:17 +020014#include "support/Logger.h"
15#include "support/Trace.h"
Sam McCall4160f4c2020-06-09 15:46:35 +020016#include "clang/AST/DeclTemplate.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020017#include "clang/Basic/Diagnostic.h"
18#include "clang/Basic/LangOptions.h"
Sam McCallcf3a5852019-09-04 07:35:00 +000019#include "clang/Basic/SourceLocation.h"
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +020020#include "clang/Basic/SourceManager.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020021#include "clang/Basic/TokenKinds.h"
22#include "clang/Frontend/CompilerInvocation.h"
23#include "clang/Frontend/FrontendActions.h"
24#include "clang/Lex/Lexer.h"
Sam McCallcf3a5852019-09-04 07:35:00 +000025#include "clang/Lex/PPCallbacks.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020026#include "clang/Lex/Preprocessor.h"
Sam McCallcf3a5852019-09-04 07:35:00 +000027#include "clang/Lex/PreprocessorOptions.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020028#include "clang/Tooling/CompilationDatabase.h"
29#include "llvm/ADT/ArrayRef.h"
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +020030#include "llvm/ADT/DenseMap.h"
31#include "llvm/ADT/DenseSet.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020032#include "llvm/ADT/IntrusiveRefCntPtr.h"
33#include "llvm/ADT/STLExtras.h"
34#include "llvm/ADT/SmallString.h"
Kadir Cetinkaya717bef62020-04-23 17:44:51 +020035#include "llvm/ADT/StringExtras.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020036#include "llvm/ADT/StringRef.h"
37#include "llvm/ADT/StringSet.h"
38#include "llvm/Support/Error.h"
39#include "llvm/Support/ErrorHandling.h"
40#include "llvm/Support/FormatVariadic.h"
41#include "llvm/Support/MemoryBuffer.h"
42#include "llvm/Support/Path.h"
43#include "llvm/Support/VirtualFileSystem.h"
44#include "llvm/Support/raw_ostream.h"
45#include <iterator>
46#include <memory>
47#include <string>
48#include <system_error>
49#include <utility>
50#include <vector>
Sam McCallcf3a5852019-09-04 07:35:00 +000051
52namespace clang {
53namespace clangd {
54namespace {
Kadir Cetinkaya538c2752020-05-14 12:26:47 +020055constexpr llvm::StringLiteral PreamblePatchHeaderName = "__preamble_patch__.h";
Sam McCallcf3a5852019-09-04 07:35:00 +000056
57bool compileCommandsAreEqual(const tooling::CompileCommand &LHS,
58 const tooling::CompileCommand &RHS) {
59 // We don't check for Output, it should not matter to clangd.
60 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
61 llvm::makeArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
62}
63
Sam McCallcf3a5852019-09-04 07:35:00 +000064class CppFilePreambleCallbacks : public PreambleCallbacks {
65public:
66 CppFilePreambleCallbacks(PathRef File, PreambleParsedCallback ParsedCallback)
Haojian Wu7e3c74b2019-09-24 11:14:06 +000067 : File(File), ParsedCallback(ParsedCallback) {}
Sam McCallcf3a5852019-09-04 07:35:00 +000068
69 IncludeStructure takeIncludes() { return std::move(Includes); }
70
Haojian Wu7e3c74b2019-09-24 11:14:06 +000071 MainFileMacros takeMacros() { return std::move(Macros); }
Sam McCallcf3a5852019-09-04 07:35:00 +000072
73 CanonicalIncludes takeCanonicalIncludes() { return std::move(CanonIncludes); }
74
75 void AfterExecute(CompilerInstance &CI) override {
76 if (!ParsedCallback)
77 return;
78 trace::Span Tracer("Running PreambleCallback");
79 ParsedCallback(CI.getASTContext(), CI.getPreprocessorPtr(), CanonIncludes);
80 }
81
82 void BeforeExecute(CompilerInstance &CI) override {
Ilya Biryukov8b767092019-09-09 15:32:51 +000083 CanonIncludes.addSystemHeadersMapping(CI.getLangOpts());
Haojian Wu7e3c74b2019-09-24 11:14:06 +000084 LangOpts = &CI.getLangOpts();
Sam McCallcf3a5852019-09-04 07:35:00 +000085 SourceMgr = &CI.getSourceManager();
86 }
87
88 std::unique_ptr<PPCallbacks> createPPCallbacks() override {
Haojian Wu7e3c74b2019-09-24 11:14:06 +000089 assert(SourceMgr && LangOpts &&
90 "SourceMgr and LangOpts must be set at this point");
91
Sam McCallcf3a5852019-09-04 07:35:00 +000092 return std::make_unique<PPChainedCallbacks>(
93 collectIncludeStructureCallback(*SourceMgr, &Includes),
Kadir Cetinkaya37550392020-03-01 16:05:12 +010094 std::make_unique<CollectMainFileMacros>(*SourceMgr, Macros));
Sam McCallcf3a5852019-09-04 07:35:00 +000095 }
96
97 CommentHandler *getCommentHandler() override {
98 IWYUHandler = collectIWYUHeaderMaps(&CanonIncludes);
99 return IWYUHandler.get();
100 }
101
Sam McCall4160f4c2020-06-09 15:46:35 +0200102 bool shouldSkipFunctionBody(Decl *D) override {
103 // Generally we skip function bodies in preambles for speed.
104 // We can make exceptions for functions that are cheap to parse and
105 // instantiate, widely used, and valuable (e.g. commonly produce errors).
106 if (const auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
107 if (const auto *II = FT->getDeclName().getAsIdentifierInfo())
108 // std::make_unique is trivial, and we diagnose bad constructor calls.
109 if (II->isStr("make_unique") && FT->isInStdNamespace())
110 return false;
111 }
112 return true;
113 }
114
Sam McCallcf3a5852019-09-04 07:35:00 +0000115private:
116 PathRef File;
117 PreambleParsedCallback ParsedCallback;
118 IncludeStructure Includes;
119 CanonicalIncludes CanonIncludes;
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000120 MainFileMacros Macros;
Sam McCallcf3a5852019-09-04 07:35:00 +0000121 std::unique_ptr<CommentHandler> IWYUHandler = nullptr;
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000122 const clang::LangOptions *LangOpts = nullptr;
123 const SourceManager *SourceMgr = nullptr;
Sam McCallcf3a5852019-09-04 07:35:00 +0000124};
125
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200126// Represents directives other than includes, where basic textual information is
127// enough.
128struct TextualPPDirective {
129 unsigned DirectiveLine;
130 // Full text that's representing the directive, including the `#`.
131 std::string Text;
132
133 bool operator==(const TextualPPDirective &RHS) const {
134 return std::tie(DirectiveLine, Text) ==
135 std::tie(RHS.DirectiveLine, RHS.Text);
136 }
137};
138
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200139// Formats a PP directive consisting of Prefix (e.g. "#define ") and Body ("X
140// 10"). The formatting is copied so that the tokens in Body have PresumedLocs
141// with correct columns and lines.
142std::string spellDirective(llvm::StringRef Prefix,
143 CharSourceRange DirectiveRange,
144 const LangOptions &LangOpts, const SourceManager &SM,
145 unsigned &DirectiveLine) {
146 std::string SpelledDirective;
147 llvm::raw_string_ostream OS(SpelledDirective);
148 OS << Prefix;
149
150 // Make sure DirectiveRange is a char range and doesn't contain macro ids.
151 DirectiveRange = SM.getExpansionRange(DirectiveRange);
152 if (DirectiveRange.isTokenRange()) {
153 DirectiveRange.setEnd(
154 Lexer::getLocForEndOfToken(DirectiveRange.getEnd(), 0, SM, LangOpts));
155 }
156
157 auto DecompLoc = SM.getDecomposedLoc(DirectiveRange.getBegin());
158 DirectiveLine = SM.getLineNumber(DecompLoc.first, DecompLoc.second);
159 auto TargetColumn = SM.getColumnNumber(DecompLoc.first, DecompLoc.second) - 1;
160
161 // Pad with spaces before DirectiveRange to make sure it will be on right
162 // column when patched.
163 if (Prefix.size() <= TargetColumn) {
164 // There is enough space for Prefix and space before directive, use it.
165 // We try to squeeze the Prefix into the same line whenever we can, as
166 // putting onto a separate line won't work at the beginning of the file.
167 OS << std::string(TargetColumn - Prefix.size(), ' ');
168 } else {
169 // Prefix was longer than the space we had. We produce e.g.:
170 // #line N-1
171 // #define \
172 // X 10
173 OS << "\\\n" << std::string(TargetColumn, ' ');
174 // Decrement because we put an additional line break before
175 // DirectiveRange.begin().
176 --DirectiveLine;
177 }
178 OS << toSourceCode(SM, DirectiveRange.getAsRange());
179 return OS.str();
180}
181
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200182// Collects #define directives inside the main file.
183struct DirectiveCollector : public PPCallbacks {
184 DirectiveCollector(const Preprocessor &PP,
185 std::vector<TextualPPDirective> &TextualDirectives)
186 : LangOpts(PP.getLangOpts()), SM(PP.getSourceManager()),
187 TextualDirectives(TextualDirectives) {}
188
189 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
190 SrcMgr::CharacteristicKind FileType,
191 FileID PrevFID) override {
192 InMainFile = SM.isWrittenInMainFile(Loc);
193 }
194
195 void MacroDefined(const Token &MacroNameTok,
196 const MacroDirective *MD) override {
197 if (!InMainFile)
198 return;
199 TextualDirectives.emplace_back();
200 TextualPPDirective &TD = TextualDirectives.back();
201
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200202 const auto *MI = MD->getMacroInfo();
203 TD.Text =
204 spellDirective("#define ",
205 CharSourceRange::getTokenRange(
206 MI->getDefinitionLoc(), MI->getDefinitionEndLoc()),
207 LangOpts, SM, TD.DirectiveLine);
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200208 }
209
210private:
211 bool InMainFile = true;
212 const LangOptions &LangOpts;
213 const SourceManager &SM;
214 std::vector<TextualPPDirective> &TextualDirectives;
215};
216
217struct ScannedPreamble {
218 std::vector<Inclusion> Includes;
219 std::vector<TextualPPDirective> TextualDirectives;
Kadir Cetinkaya4317ee22020-06-16 21:21:45 +0200220 PreambleBounds Bounds = {0, false};
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200221};
222
223/// Scans the preprocessor directives in the preamble section of the file by
224/// running preprocessor over \p Contents. Returned includes do not contain
225/// resolved paths. \p VFS and \p Cmd is used to build the compiler invocation,
226/// which might stat/read files.
227llvm::Expected<ScannedPreamble>
228scanPreamble(llvm::StringRef Contents,
229 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
230 const tooling::CompileCommand &Cmd) {
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200231 // FIXME: Change PreambleStatCache to operate on FileSystemProvider rather
232 // than vfs::FileSystem, that way we can just use ParseInputs without this
233 // hack.
234 auto GetFSProvider = [](llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
235 class VFSProvider : public FileSystemProvider {
236 public:
237 VFSProvider(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
238 : VFS(std::move(FS)) {}
239 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
240 getFileSystem() const override {
241 return VFS;
242 }
243
244 private:
245 const llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS;
246 };
247 return std::make_unique<VFSProvider>(std::move(FS));
248 };
249 auto FSProvider = GetFSProvider(std::move(VFS));
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200250 // Build and run Preprocessor over the preamble.
251 ParseInputs PI;
252 PI.Contents = Contents.str();
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200253 PI.FSProvider = FSProvider.get();
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200254 PI.CompileCommand = Cmd;
255 IgnoringDiagConsumer IgnoreDiags;
256 auto CI = buildCompilerInvocation(PI, IgnoreDiags);
257 if (!CI)
258 return llvm::createStringError(llvm::inconvertibleErrorCode(),
259 "failed to create compiler invocation");
260 CI->getDiagnosticOpts().IgnoreWarnings = true;
261 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(Contents);
Kadir Cetinkaya34e39eb2020-05-05 17:55:11 +0200262 // This means we're scanning (though not preprocessing) the preamble section
263 // twice. However, it's important to precisely follow the preamble bounds used
264 // elsewhere.
265 auto Bounds =
266 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
267 auto PreambleContents =
268 llvm::MemoryBuffer::getMemBufferCopy(Contents.substr(0, Bounds.Size));
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200269 auto Clang = prepareCompilerInstance(
Kadir Cetinkaya34e39eb2020-05-05 17:55:11 +0200270 std::move(CI), nullptr, std::move(PreambleContents),
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200271 // Provide an empty FS to prevent preprocessor from performing IO. This
272 // also implies missing resolved paths for includes.
273 new llvm::vfs::InMemoryFileSystem, IgnoreDiags);
274 if (Clang->getFrontendOpts().Inputs.empty())
275 return llvm::createStringError(llvm::inconvertibleErrorCode(),
276 "compiler instance had no inputs");
277 // We are only interested in main file includes.
278 Clang->getPreprocessorOpts().SingleFileParseMode = true;
Kadir Cetinkaya34e39eb2020-05-05 17:55:11 +0200279 PreprocessOnlyAction Action;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200280 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
281 return llvm::createStringError(llvm::inconvertibleErrorCode(),
282 "failed BeginSourceFile");
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200283 const auto &SM = Clang->getSourceManager();
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200284 Preprocessor &PP = Clang->getPreprocessor();
285 IncludeStructure Includes;
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200286 PP.addPPCallbacks(collectIncludeStructureCallback(SM, &Includes));
287 ScannedPreamble SP;
Kadir Cetinkaya4317ee22020-06-16 21:21:45 +0200288 SP.Bounds = Bounds;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200289 PP.addPPCallbacks(
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200290 std::make_unique<DirectiveCollector>(PP, SP.TextualDirectives));
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200291 if (llvm::Error Err = Action.Execute())
292 return std::move(Err);
293 Action.EndSourceFile();
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200294 SP.Includes = std::move(Includes.MainFileIncludes);
295 return SP;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200296}
297
298const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
299 switch (IncludeDirective) {
300 case tok::pp_include:
301 return "include";
302 case tok::pp_import:
303 return "import";
304 case tok::pp_include_next:
305 return "include_next";
306 default:
307 break;
308 }
309 llvm_unreachable("not an include directive");
310}
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200311
312// Checks whether \p FileName is a valid spelling of main file.
313bool isMainFile(llvm::StringRef FileName, const SourceManager &SM) {
314 auto FE = SM.getFileManager().getFile(FileName);
315 return FE && *FE == SM.getFileEntryForID(SM.getMainFileID());
316}
317
Sam McCallcf3a5852019-09-04 07:35:00 +0000318} // namespace
319
Kadir Cetinkayaecd3e672020-03-11 16:34:01 +0100320PreambleData::PreambleData(const ParseInputs &Inputs,
Sam McCall2cd33e62020-03-04 00:33:29 +0100321 PrecompiledPreamble Preamble,
Sam McCallcf3a5852019-09-04 07:35:00 +0000322 std::vector<Diag> Diags, IncludeStructure Includes,
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000323 MainFileMacros Macros,
Sam McCallcf3a5852019-09-04 07:35:00 +0000324 std::unique_ptr<PreambleFileStatusCache> StatCache,
325 CanonicalIncludes CanonIncludes)
Kadir Cetinkayaecd3e672020-03-11 16:34:01 +0100326 : Version(Inputs.Version), CompileCommand(Inputs.CompileCommand),
327 Preamble(std::move(Preamble)), Diags(std::move(Diags)),
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000328 Includes(std::move(Includes)), Macros(std::move(Macros)),
Sam McCallcf3a5852019-09-04 07:35:00 +0000329 StatCache(std::move(StatCache)), CanonIncludes(std::move(CanonIncludes)) {
330}
331
332std::shared_ptr<const PreambleData>
Kadir Cetinkaya276a95b2020-03-13 11:52:19 +0100333buildPreamble(PathRef FileName, CompilerInvocation CI,
Sam McCallcf3a5852019-09-04 07:35:00 +0000334 const ParseInputs &Inputs, bool StoreInMemory,
335 PreambleParsedCallback PreambleCallback) {
336 // Note that we don't need to copy the input contents, preamble can live
337 // without those.
338 auto ContentsBuffer =
339 llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName);
340 auto Bounds =
341 ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
342
Sam McCallcf3a5852019-09-04 07:35:00 +0000343 trace::Span Tracer("BuildPreamble");
344 SPAN_ATTACH(Tracer, "File", FileName);
345 StoreDiags PreambleDiagnostics;
346 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
347 CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(),
348 &PreambleDiagnostics, false);
349
350 // Skip function bodies when building the preamble to speed up building
351 // the preamble and make it smaller.
352 assert(!CI.getFrontendOpts().SkipFunctionBodies);
353 CI.getFrontendOpts().SkipFunctionBodies = true;
354 // We don't want to write comment locations into PCH. They are racy and slow
355 // to read back. We rely on dynamic index for the comments instead.
356 CI.getPreprocessorOpts().WriteCommentListToPCH = false;
357
358 CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback);
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200359 auto VFS = Inputs.FSProvider->getFileSystem();
360 if (VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
Sam McCallcf3a5852019-09-04 07:35:00 +0000361 log("Couldn't set working directory when building the preamble.");
362 // We proceed anyway, our lit-tests rely on results for non-existing working
363 // dirs.
364 }
365
366 llvm::SmallString<32> AbsFileName(FileName);
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200367 VFS->makeAbsolute(AbsFileName);
Sam McCallcf3a5852019-09-04 07:35:00 +0000368 auto StatCache = std::make_unique<PreambleFileStatusCache>(AbsFileName);
369 auto BuiltPreamble = PrecompiledPreamble::Build(
370 CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine,
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200371 StatCache->getProducingFS(VFS),
Sam McCallcf3a5852019-09-04 07:35:00 +0000372 std::make_shared<PCHContainerOperations>(), StoreInMemory,
373 SerializedDeclsCollector);
374
375 // When building the AST for the main file, we do want the function
376 // bodies.
377 CI.getFrontendOpts().SkipFunctionBodies = false;
378
379 if (BuiltPreamble) {
Sam McCall2cd33e62020-03-04 00:33:29 +0100380 vlog("Built preamble of size {0} for file {1} version {2}",
381 BuiltPreamble->getSize(), FileName, Inputs.Version);
Sam McCallcf3a5852019-09-04 07:35:00 +0000382 std::vector<Diag> Diags = PreambleDiagnostics.take();
383 return std::make_shared<PreambleData>(
Kadir Cetinkayaecd3e672020-03-11 16:34:01 +0100384 Inputs, std::move(*BuiltPreamble), std::move(Diags),
Sam McCallcf3a5852019-09-04 07:35:00 +0000385 SerializedDeclsCollector.takeIncludes(),
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000386 SerializedDeclsCollector.takeMacros(), std::move(StatCache),
Sam McCallcf3a5852019-09-04 07:35:00 +0000387 SerializedDeclsCollector.takeCanonicalIncludes());
388 } else {
Adam Czachorowski55b92dc2020-03-19 15:09:28 +0100389 elog("Could not build a preamble for file {0} version {1}", FileName,
Sam McCall2cd33e62020-03-04 00:33:29 +0100390 Inputs.Version);
Sam McCallcf3a5852019-09-04 07:35:00 +0000391 return nullptr;
392 }
393}
394
Kadir Cetinkayac31367e2020-03-15 21:43:00 +0100395bool isPreambleCompatible(const PreambleData &Preamble,
396 const ParseInputs &Inputs, PathRef FileName,
397 const CompilerInvocation &CI) {
398 auto ContentsBuffer =
399 llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName);
400 auto Bounds =
401 ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
Kadir Cetinkaya37251422020-06-16 11:02:08 +0200402 auto VFS = Inputs.FSProvider->getFileSystem();
403 VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory);
Kadir Cetinkayac31367e2020-03-15 21:43:00 +0100404 return compileCommandsAreEqual(Inputs.CompileCommand,
405 Preamble.CompileCommand) &&
406 Preamble.Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds,
Kadir Cetinkaya37251422020-06-16 11:02:08 +0200407 VFS.get());
Kadir Cetinkayac31367e2020-03-15 21:43:00 +0100408}
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200409
Kadir Cetinkaya717bef62020-04-23 17:44:51 +0200410void escapeBackslashAndQuotes(llvm::StringRef Text, llvm::raw_ostream &OS) {
411 for (char C : Text) {
412 switch (C) {
413 case '\\':
414 case '"':
415 OS << '\\';
416 break;
417 default:
418 break;
419 }
420 OS << C;
421 }
422}
423
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200424PreamblePatch PreamblePatch::create(llvm::StringRef FileName,
425 const ParseInputs &Modified,
426 const PreambleData &Baseline) {
Kadir Cetinkaya20b2af32020-05-29 12:31:35 +0200427 trace::Span Tracer("CreatePreamblePatch");
428 SPAN_ATTACH(Tracer, "File", FileName);
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200429 assert(llvm::sys::path::is_absolute(FileName) && "relative FileName!");
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200430 auto VFS =
431 Baseline.StatCache->getConsumingFS(Modified.FSProvider->getFileSystem());
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200432 // First scan preprocessor directives in Baseline and Modified. These will be
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200433 // used to figure out newly added directives in Modified. Scanning can fail,
434 // the code just bails out and creates an empty patch in such cases, as:
435 // - If scanning for Baseline fails, no knowledge of existing includes hence
436 // patch will contain all the includes in Modified. Leading to rebuild of
437 // whole preamble, which is terribly slow.
438 // - If scanning for Modified fails, cannot figure out newly added ones so
439 // there's nothing to do but generate an empty patch.
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200440 auto BaselineScan = scanPreamble(
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200441 // Contents needs to be null-terminated.
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200442 Baseline.Preamble.getContents().str(), VFS, Modified.CompileCommand);
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200443 if (!BaselineScan) {
444 elog("Failed to scan baseline of {0}: {1}", FileName,
445 BaselineScan.takeError());
446 return PreamblePatch::unmodified(Baseline);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200447 }
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200448 auto ModifiedScan =
449 scanPreamble(Modified.Contents, std::move(VFS), Modified.CompileCommand);
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200450 if (!ModifiedScan) {
451 elog("Failed to scan modified contents of {0}: {1}", FileName,
452 ModifiedScan.takeError());
453 return PreamblePatch::unmodified(Baseline);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200454 }
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200455
456 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
457 bool DirectivesChanged =
458 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
459 if (!IncludesChanged && !DirectivesChanged)
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200460 return PreamblePatch::unmodified(Baseline);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200461
462 PreamblePatch PP;
463 // This shouldn't coincide with any real file name.
464 llvm::SmallString<128> PatchName;
465 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName),
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200466 PreamblePatchHeaderName);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200467 PP.PatchFileName = PatchName.str().str();
Kadir Cetinkaya4317ee22020-06-16 21:21:45 +0200468 PP.ModifiedBounds = ModifiedScan->Bounds;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200469
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200470 llvm::raw_string_ostream Patch(PP.PatchContents);
Kadir Cetinkaya717bef62020-04-23 17:44:51 +0200471 // Set default filename for subsequent #line directives
472 Patch << "#line 0 \"";
473 // FileName part of a line directive is subject to backslash escaping, which
474 // might lead to problems on windows especially.
475 escapeBackslashAndQuotes(FileName, Patch);
476 Patch << "\"\n";
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200477
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200478 if (IncludesChanged) {
479 // We are only interested in newly added includes, record the ones in
480 // Baseline for exclusion.
481 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
482 /*Resolved=*/llvm::StringRef>
483 ExistingIncludes;
484 for (const auto &Inc : Baseline.Includes.MainFileIncludes)
485 ExistingIncludes[{Inc.Directive, Inc.Written}] = Inc.Resolved;
486 // There might be includes coming from disabled regions, record these for
487 // exclusion too. note that we don't have resolved paths for those.
488 for (const auto &Inc : BaselineScan->Includes)
489 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
490 // Calculate extra includes that needs to be inserted.
491 for (auto &Inc : ModifiedScan->Includes) {
492 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
493 // Include already present in the baseline preamble. Set resolved path and
494 // put into preamble includes.
495 if (It != ExistingIncludes.end()) {
496 Inc.Resolved = It->second.str();
497 PP.PreambleIncludes.push_back(Inc);
498 continue;
499 }
500 // Include is new in the modified preamble. Inject it into the patch and
501 // use #line to set the presumed location to where it is spelled.
502 auto LineCol = offsetToClangLineColumn(Modified.Contents, Inc.HashOffset);
503 Patch << llvm::formatv("#line {0}\n", LineCol.first);
504 Patch << llvm::formatv(
505 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
506 }
507 }
508
509 if (DirectivesChanged) {
510 // We need to patch all the directives, since they are order dependent. e.g:
511 // #define BAR(X) NEW(X) // Newly introduced in Modified
512 // #define BAR(X) OLD(X) // Exists in the Baseline
513 //
514 // If we've patched only the first directive, the macro definition would've
515 // been wrong for the rest of the file, since patch is applied after the
516 // baseline preamble.
517 //
518 // Note that we deliberately ignore conditional directives and undefs to
519 // reduce complexity. The former might cause problems because scanning is
520 // imprecise and might pick directives from disabled regions.
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200521 for (const auto &TD : ModifiedScan->TextualDirectives) {
522 Patch << "#line " << TD.DirectiveLine << '\n';
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200523 Patch << TD.Text << '\n';
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200524 }
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200525 }
526 dlog("Created preamble patch: {0}", Patch.str());
527 Patch.flush();
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200528 return PP;
529}
530
531void PreamblePatch::apply(CompilerInvocation &CI) const {
532 // No need to map an empty file.
533 if (PatchContents.empty())
534 return;
535 auto &PPOpts = CI.getPreprocessorOpts();
536 auto PatchBuffer =
537 // we copy here to ensure contents are still valid if CI outlives the
538 // PreamblePatch.
539 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
540 // CI will take care of the lifetime of the buffer.
541 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
542 // The patch will be parsed after loading the preamble ast and before parsing
543 // the main file.
544 PPOpts.Includes.push_back(PatchFileName);
545}
546
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200547std::vector<Inclusion> PreamblePatch::preambleIncludes() const {
548 return PreambleIncludes;
549}
550
551PreamblePatch PreamblePatch::unmodified(const PreambleData &Preamble) {
552 PreamblePatch PP;
553 PP.PreambleIncludes = Preamble.Includes.MainFileIncludes;
Kadir Cetinkaya4317ee22020-06-16 21:21:45 +0200554 PP.ModifiedBounds = Preamble.Preamble.getBounds();
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200555 return PP;
556}
557
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200558SourceLocation translatePreamblePatchLocation(SourceLocation Loc,
559 const SourceManager &SM) {
560 auto DefFile = SM.getFileID(Loc);
561 if (auto *FE = SM.getFileEntryForID(DefFile)) {
562 auto IncludeLoc = SM.getIncludeLoc(DefFile);
563 // Preamble patch is included inside the builtin file.
564 if (IncludeLoc.isValid() && SM.isWrittenInBuiltinFile(IncludeLoc) &&
565 FE->getName().endswith(PreamblePatchHeaderName)) {
566 auto Presumed = SM.getPresumedLoc(Loc);
567 // Check that line directive is pointing at main file.
568 if (Presumed.isValid() && Presumed.getFileID().isInvalid() &&
569 isMainFile(Presumed.getFilename(), SM)) {
570 Loc = SM.translateLineCol(SM.getMainFileID(), Presumed.getLine(),
571 Presumed.getColumn());
572 }
573 }
574 }
575 return Loc;
576}
Sam McCallcf3a5852019-09-04 07:35:00 +0000577} // namespace clangd
578} // namespace clang