blob: 667fa04ff345838d8c3d38944a524b4a80dd5253 [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"
Sam McCallad97ccf2020-04-28 17:49:17 +020013#include "support/Logger.h"
14#include "support/Trace.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020015#include "clang/Basic/Diagnostic.h"
16#include "clang/Basic/LangOptions.h"
Sam McCallcf3a5852019-09-04 07:35:00 +000017#include "clang/Basic/SourceLocation.h"
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +020018#include "clang/Basic/SourceManager.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020019#include "clang/Basic/TokenKinds.h"
20#include "clang/Frontend/CompilerInvocation.h"
21#include "clang/Frontend/FrontendActions.h"
22#include "clang/Lex/Lexer.h"
Sam McCallcf3a5852019-09-04 07:35:00 +000023#include "clang/Lex/PPCallbacks.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020024#include "clang/Lex/Preprocessor.h"
Sam McCallcf3a5852019-09-04 07:35:00 +000025#include "clang/Lex/PreprocessorOptions.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020026#include "clang/Tooling/CompilationDatabase.h"
27#include "llvm/ADT/ArrayRef.h"
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +020028#include "llvm/ADT/DenseMap.h"
29#include "llvm/ADT/DenseSet.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020030#include "llvm/ADT/IntrusiveRefCntPtr.h"
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/SmallString.h"
Kadir Cetinkaya717bef62020-04-23 17:44:51 +020033#include "llvm/ADT/StringExtras.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020034#include "llvm/ADT/StringRef.h"
35#include "llvm/ADT/StringSet.h"
36#include "llvm/Support/Error.h"
37#include "llvm/Support/ErrorHandling.h"
38#include "llvm/Support/FormatVariadic.h"
39#include "llvm/Support/MemoryBuffer.h"
40#include "llvm/Support/Path.h"
41#include "llvm/Support/VirtualFileSystem.h"
42#include "llvm/Support/raw_ostream.h"
43#include <iterator>
44#include <memory>
45#include <string>
46#include <system_error>
47#include <utility>
48#include <vector>
Sam McCallcf3a5852019-09-04 07:35:00 +000049
50namespace clang {
51namespace clangd {
52namespace {
Kadir Cetinkaya538c2752020-05-14 12:26:47 +020053constexpr llvm::StringLiteral PreamblePatchHeaderName = "__preamble_patch__.h";
Sam McCallcf3a5852019-09-04 07:35:00 +000054
55bool compileCommandsAreEqual(const tooling::CompileCommand &LHS,
56 const tooling::CompileCommand &RHS) {
57 // We don't check for Output, it should not matter to clangd.
58 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
59 llvm::makeArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
60}
61
Sam McCallcf3a5852019-09-04 07:35:00 +000062class CppFilePreambleCallbacks : public PreambleCallbacks {
63public:
64 CppFilePreambleCallbacks(PathRef File, PreambleParsedCallback ParsedCallback)
Haojian Wu7e3c74b2019-09-24 11:14:06 +000065 : File(File), ParsedCallback(ParsedCallback) {}
Sam McCallcf3a5852019-09-04 07:35:00 +000066
67 IncludeStructure takeIncludes() { return std::move(Includes); }
68
Haojian Wu7e3c74b2019-09-24 11:14:06 +000069 MainFileMacros takeMacros() { return std::move(Macros); }
Sam McCallcf3a5852019-09-04 07:35:00 +000070
71 CanonicalIncludes takeCanonicalIncludes() { return std::move(CanonIncludes); }
72
73 void AfterExecute(CompilerInstance &CI) override {
74 if (!ParsedCallback)
75 return;
76 trace::Span Tracer("Running PreambleCallback");
77 ParsedCallback(CI.getASTContext(), CI.getPreprocessorPtr(), CanonIncludes);
78 }
79
80 void BeforeExecute(CompilerInstance &CI) override {
Ilya Biryukov8b767092019-09-09 15:32:51 +000081 CanonIncludes.addSystemHeadersMapping(CI.getLangOpts());
Haojian Wu7e3c74b2019-09-24 11:14:06 +000082 LangOpts = &CI.getLangOpts();
Sam McCallcf3a5852019-09-04 07:35:00 +000083 SourceMgr = &CI.getSourceManager();
84 }
85
86 std::unique_ptr<PPCallbacks> createPPCallbacks() override {
Haojian Wu7e3c74b2019-09-24 11:14:06 +000087 assert(SourceMgr && LangOpts &&
88 "SourceMgr and LangOpts must be set at this point");
89
Sam McCallcf3a5852019-09-04 07:35:00 +000090 return std::make_unique<PPChainedCallbacks>(
91 collectIncludeStructureCallback(*SourceMgr, &Includes),
Kadir Cetinkaya37550392020-03-01 16:05:12 +010092 std::make_unique<CollectMainFileMacros>(*SourceMgr, Macros));
Sam McCallcf3a5852019-09-04 07:35:00 +000093 }
94
95 CommentHandler *getCommentHandler() override {
96 IWYUHandler = collectIWYUHeaderMaps(&CanonIncludes);
97 return IWYUHandler.get();
98 }
99
100private:
101 PathRef File;
102 PreambleParsedCallback ParsedCallback;
103 IncludeStructure Includes;
104 CanonicalIncludes CanonIncludes;
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000105 MainFileMacros Macros;
Sam McCallcf3a5852019-09-04 07:35:00 +0000106 std::unique_ptr<CommentHandler> IWYUHandler = nullptr;
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000107 const clang::LangOptions *LangOpts = nullptr;
108 const SourceManager *SourceMgr = nullptr;
Sam McCallcf3a5852019-09-04 07:35:00 +0000109};
110
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200111// Represents directives other than includes, where basic textual information is
112// enough.
113struct TextualPPDirective {
114 unsigned DirectiveLine;
115 // Full text that's representing the directive, including the `#`.
116 std::string Text;
117
118 bool operator==(const TextualPPDirective &RHS) const {
119 return std::tie(DirectiveLine, Text) ==
120 std::tie(RHS.DirectiveLine, RHS.Text);
121 }
122};
123
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200124// Formats a PP directive consisting of Prefix (e.g. "#define ") and Body ("X
125// 10"). The formatting is copied so that the tokens in Body have PresumedLocs
126// with correct columns and lines.
127std::string spellDirective(llvm::StringRef Prefix,
128 CharSourceRange DirectiveRange,
129 const LangOptions &LangOpts, const SourceManager &SM,
130 unsigned &DirectiveLine) {
131 std::string SpelledDirective;
132 llvm::raw_string_ostream OS(SpelledDirective);
133 OS << Prefix;
134
135 // Make sure DirectiveRange is a char range and doesn't contain macro ids.
136 DirectiveRange = SM.getExpansionRange(DirectiveRange);
137 if (DirectiveRange.isTokenRange()) {
138 DirectiveRange.setEnd(
139 Lexer::getLocForEndOfToken(DirectiveRange.getEnd(), 0, SM, LangOpts));
140 }
141
142 auto DecompLoc = SM.getDecomposedLoc(DirectiveRange.getBegin());
143 DirectiveLine = SM.getLineNumber(DecompLoc.first, DecompLoc.second);
144 auto TargetColumn = SM.getColumnNumber(DecompLoc.first, DecompLoc.second) - 1;
145
146 // Pad with spaces before DirectiveRange to make sure it will be on right
147 // column when patched.
148 if (Prefix.size() <= TargetColumn) {
149 // There is enough space for Prefix and space before directive, use it.
150 // We try to squeeze the Prefix into the same line whenever we can, as
151 // putting onto a separate line won't work at the beginning of the file.
152 OS << std::string(TargetColumn - Prefix.size(), ' ');
153 } else {
154 // Prefix was longer than the space we had. We produce e.g.:
155 // #line N-1
156 // #define \
157 // X 10
158 OS << "\\\n" << std::string(TargetColumn, ' ');
159 // Decrement because we put an additional line break before
160 // DirectiveRange.begin().
161 --DirectiveLine;
162 }
163 OS << toSourceCode(SM, DirectiveRange.getAsRange());
164 return OS.str();
165}
166
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200167// Collects #define directives inside the main file.
168struct DirectiveCollector : public PPCallbacks {
169 DirectiveCollector(const Preprocessor &PP,
170 std::vector<TextualPPDirective> &TextualDirectives)
171 : LangOpts(PP.getLangOpts()), SM(PP.getSourceManager()),
172 TextualDirectives(TextualDirectives) {}
173
174 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
175 SrcMgr::CharacteristicKind FileType,
176 FileID PrevFID) override {
177 InMainFile = SM.isWrittenInMainFile(Loc);
178 }
179
180 void MacroDefined(const Token &MacroNameTok,
181 const MacroDirective *MD) override {
182 if (!InMainFile)
183 return;
184 TextualDirectives.emplace_back();
185 TextualPPDirective &TD = TextualDirectives.back();
186
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200187 const auto *MI = MD->getMacroInfo();
188 TD.Text =
189 spellDirective("#define ",
190 CharSourceRange::getTokenRange(
191 MI->getDefinitionLoc(), MI->getDefinitionEndLoc()),
192 LangOpts, SM, TD.DirectiveLine);
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200193 }
194
195private:
196 bool InMainFile = true;
197 const LangOptions &LangOpts;
198 const SourceManager &SM;
199 std::vector<TextualPPDirective> &TextualDirectives;
200};
201
202struct ScannedPreamble {
203 std::vector<Inclusion> Includes;
204 std::vector<TextualPPDirective> TextualDirectives;
205};
206
207/// Scans the preprocessor directives in the preamble section of the file by
208/// running preprocessor over \p Contents. Returned includes do not contain
209/// resolved paths. \p VFS and \p Cmd is used to build the compiler invocation,
210/// which might stat/read files.
211llvm::Expected<ScannedPreamble>
212scanPreamble(llvm::StringRef Contents,
213 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
214 const tooling::CompileCommand &Cmd) {
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200215 // Build and run Preprocessor over the preamble.
216 ParseInputs PI;
217 PI.Contents = Contents.str();
218 PI.FS = std::move(VFS);
219 PI.CompileCommand = Cmd;
220 IgnoringDiagConsumer IgnoreDiags;
221 auto CI = buildCompilerInvocation(PI, IgnoreDiags);
222 if (!CI)
223 return llvm::createStringError(llvm::inconvertibleErrorCode(),
224 "failed to create compiler invocation");
225 CI->getDiagnosticOpts().IgnoreWarnings = true;
226 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(Contents);
Kadir Cetinkaya34e39eb2020-05-05 17:55:11 +0200227 // This means we're scanning (though not preprocessing) the preamble section
228 // twice. However, it's important to precisely follow the preamble bounds used
229 // elsewhere.
230 auto Bounds =
231 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
232 auto PreambleContents =
233 llvm::MemoryBuffer::getMemBufferCopy(Contents.substr(0, Bounds.Size));
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200234 auto Clang = prepareCompilerInstance(
Kadir Cetinkaya34e39eb2020-05-05 17:55:11 +0200235 std::move(CI), nullptr, std::move(PreambleContents),
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200236 // Provide an empty FS to prevent preprocessor from performing IO. This
237 // also implies missing resolved paths for includes.
238 new llvm::vfs::InMemoryFileSystem, IgnoreDiags);
239 if (Clang->getFrontendOpts().Inputs.empty())
240 return llvm::createStringError(llvm::inconvertibleErrorCode(),
241 "compiler instance had no inputs");
242 // We are only interested in main file includes.
243 Clang->getPreprocessorOpts().SingleFileParseMode = true;
Kadir Cetinkaya34e39eb2020-05-05 17:55:11 +0200244 PreprocessOnlyAction Action;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200245 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
246 return llvm::createStringError(llvm::inconvertibleErrorCode(),
247 "failed BeginSourceFile");
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200248 const auto &SM = Clang->getSourceManager();
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200249 Preprocessor &PP = Clang->getPreprocessor();
250 IncludeStructure Includes;
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200251 PP.addPPCallbacks(collectIncludeStructureCallback(SM, &Includes));
252 ScannedPreamble SP;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200253 PP.addPPCallbacks(
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200254 std::make_unique<DirectiveCollector>(PP, SP.TextualDirectives));
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200255 if (llvm::Error Err = Action.Execute())
256 return std::move(Err);
257 Action.EndSourceFile();
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200258 SP.Includes = std::move(Includes.MainFileIncludes);
259 return SP;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200260}
261
262const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
263 switch (IncludeDirective) {
264 case tok::pp_include:
265 return "include";
266 case tok::pp_import:
267 return "import";
268 case tok::pp_include_next:
269 return "include_next";
270 default:
271 break;
272 }
273 llvm_unreachable("not an include directive");
274}
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200275
276// Checks whether \p FileName is a valid spelling of main file.
277bool isMainFile(llvm::StringRef FileName, const SourceManager &SM) {
278 auto FE = SM.getFileManager().getFile(FileName);
279 return FE && *FE == SM.getFileEntryForID(SM.getMainFileID());
280}
281
Sam McCallcf3a5852019-09-04 07:35:00 +0000282} // namespace
283
Kadir Cetinkayaecd3e672020-03-11 16:34:01 +0100284PreambleData::PreambleData(const ParseInputs &Inputs,
Sam McCall2cd33e62020-03-04 00:33:29 +0100285 PrecompiledPreamble Preamble,
Sam McCallcf3a5852019-09-04 07:35:00 +0000286 std::vector<Diag> Diags, IncludeStructure Includes,
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000287 MainFileMacros Macros,
Sam McCallcf3a5852019-09-04 07:35:00 +0000288 std::unique_ptr<PreambleFileStatusCache> StatCache,
289 CanonicalIncludes CanonIncludes)
Kadir Cetinkayaecd3e672020-03-11 16:34:01 +0100290 : Version(Inputs.Version), CompileCommand(Inputs.CompileCommand),
291 Preamble(std::move(Preamble)), Diags(std::move(Diags)),
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000292 Includes(std::move(Includes)), Macros(std::move(Macros)),
Sam McCallcf3a5852019-09-04 07:35:00 +0000293 StatCache(std::move(StatCache)), CanonIncludes(std::move(CanonIncludes)) {
294}
295
296std::shared_ptr<const PreambleData>
Kadir Cetinkaya276a95b2020-03-13 11:52:19 +0100297buildPreamble(PathRef FileName, CompilerInvocation CI,
Sam McCallcf3a5852019-09-04 07:35:00 +0000298 const ParseInputs &Inputs, bool StoreInMemory,
299 PreambleParsedCallback PreambleCallback) {
300 // Note that we don't need to copy the input contents, preamble can live
301 // without those.
302 auto ContentsBuffer =
303 llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName);
304 auto Bounds =
305 ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
306
Sam McCallcf3a5852019-09-04 07:35:00 +0000307 trace::Span Tracer("BuildPreamble");
308 SPAN_ATTACH(Tracer, "File", FileName);
309 StoreDiags PreambleDiagnostics;
310 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
311 CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(),
312 &PreambleDiagnostics, false);
313
314 // Skip function bodies when building the preamble to speed up building
315 // the preamble and make it smaller.
316 assert(!CI.getFrontendOpts().SkipFunctionBodies);
317 CI.getFrontendOpts().SkipFunctionBodies = true;
318 // We don't want to write comment locations into PCH. They are racy and slow
319 // to read back. We rely on dynamic index for the comments instead.
320 CI.getPreprocessorOpts().WriteCommentListToPCH = false;
321
322 CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback);
323 if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
324 log("Couldn't set working directory when building the preamble.");
325 // We proceed anyway, our lit-tests rely on results for non-existing working
326 // dirs.
327 }
328
329 llvm::SmallString<32> AbsFileName(FileName);
330 Inputs.FS->makeAbsolute(AbsFileName);
331 auto StatCache = std::make_unique<PreambleFileStatusCache>(AbsFileName);
332 auto BuiltPreamble = PrecompiledPreamble::Build(
333 CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine,
334 StatCache->getProducingFS(Inputs.FS),
335 std::make_shared<PCHContainerOperations>(), StoreInMemory,
336 SerializedDeclsCollector);
337
338 // When building the AST for the main file, we do want the function
339 // bodies.
340 CI.getFrontendOpts().SkipFunctionBodies = false;
341
342 if (BuiltPreamble) {
Sam McCall2cd33e62020-03-04 00:33:29 +0100343 vlog("Built preamble of size {0} for file {1} version {2}",
344 BuiltPreamble->getSize(), FileName, Inputs.Version);
Sam McCallcf3a5852019-09-04 07:35:00 +0000345 std::vector<Diag> Diags = PreambleDiagnostics.take();
346 return std::make_shared<PreambleData>(
Kadir Cetinkayaecd3e672020-03-11 16:34:01 +0100347 Inputs, std::move(*BuiltPreamble), std::move(Diags),
Sam McCallcf3a5852019-09-04 07:35:00 +0000348 SerializedDeclsCollector.takeIncludes(),
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000349 SerializedDeclsCollector.takeMacros(), std::move(StatCache),
Sam McCallcf3a5852019-09-04 07:35:00 +0000350 SerializedDeclsCollector.takeCanonicalIncludes());
351 } else {
Adam Czachorowski55b92dc2020-03-19 15:09:28 +0100352 elog("Could not build a preamble for file {0} version {1}", FileName,
Sam McCall2cd33e62020-03-04 00:33:29 +0100353 Inputs.Version);
Sam McCallcf3a5852019-09-04 07:35:00 +0000354 return nullptr;
355 }
356}
357
Kadir Cetinkayac31367e2020-03-15 21:43:00 +0100358bool isPreambleCompatible(const PreambleData &Preamble,
359 const ParseInputs &Inputs, PathRef FileName,
360 const CompilerInvocation &CI) {
361 auto ContentsBuffer =
362 llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName);
363 auto Bounds =
364 ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
365 return compileCommandsAreEqual(Inputs.CompileCommand,
366 Preamble.CompileCommand) &&
367 Preamble.Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds,
368 Inputs.FS.get());
369}
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200370
Kadir Cetinkaya717bef62020-04-23 17:44:51 +0200371void escapeBackslashAndQuotes(llvm::StringRef Text, llvm::raw_ostream &OS) {
372 for (char C : Text) {
373 switch (C) {
374 case '\\':
375 case '"':
376 OS << '\\';
377 break;
378 default:
379 break;
380 }
381 OS << C;
382 }
383}
384
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200385PreamblePatch PreamblePatch::create(llvm::StringRef FileName,
386 const ParseInputs &Modified,
387 const PreambleData &Baseline) {
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200388 assert(llvm::sys::path::is_absolute(FileName) && "relative FileName!");
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200389 // First scan preprocessor directives in Baseline and Modified. These will be
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200390 // used to figure out newly added directives in Modified. Scanning can fail,
391 // the code just bails out and creates an empty patch in such cases, as:
392 // - If scanning for Baseline fails, no knowledge of existing includes hence
393 // patch will contain all the includes in Modified. Leading to rebuild of
394 // whole preamble, which is terribly slow.
395 // - If scanning for Modified fails, cannot figure out newly added ones so
396 // there's nothing to do but generate an empty patch.
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200397 auto BaselineScan = scanPreamble(
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200398 // Contents needs to be null-terminated.
399 Baseline.Preamble.getContents().str(),
400 Baseline.StatCache->getConsumingFS(Modified.FS), Modified.CompileCommand);
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200401 if (!BaselineScan) {
402 elog("Failed to scan baseline of {0}: {1}", FileName,
403 BaselineScan.takeError());
404 return PreamblePatch::unmodified(Baseline);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200405 }
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200406 auto ModifiedScan = scanPreamble(
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200407 Modified.Contents, Baseline.StatCache->getConsumingFS(Modified.FS),
408 Modified.CompileCommand);
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200409 if (!ModifiedScan) {
410 elog("Failed to scan modified contents of {0}: {1}", FileName,
411 ModifiedScan.takeError());
412 return PreamblePatch::unmodified(Baseline);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200413 }
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200414
415 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
416 bool DirectivesChanged =
417 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
418 if (!IncludesChanged && !DirectivesChanged)
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200419 return PreamblePatch::unmodified(Baseline);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200420
421 PreamblePatch PP;
422 // This shouldn't coincide with any real file name.
423 llvm::SmallString<128> PatchName;
424 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName),
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200425 PreamblePatchHeaderName);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200426 PP.PatchFileName = PatchName.str().str();
427
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200428 llvm::raw_string_ostream Patch(PP.PatchContents);
Kadir Cetinkaya717bef62020-04-23 17:44:51 +0200429 // Set default filename for subsequent #line directives
430 Patch << "#line 0 \"";
431 // FileName part of a line directive is subject to backslash escaping, which
432 // might lead to problems on windows especially.
433 escapeBackslashAndQuotes(FileName, Patch);
434 Patch << "\"\n";
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200435
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200436 if (IncludesChanged) {
437 // We are only interested in newly added includes, record the ones in
438 // Baseline for exclusion.
439 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
440 /*Resolved=*/llvm::StringRef>
441 ExistingIncludes;
442 for (const auto &Inc : Baseline.Includes.MainFileIncludes)
443 ExistingIncludes[{Inc.Directive, Inc.Written}] = Inc.Resolved;
444 // There might be includes coming from disabled regions, record these for
445 // exclusion too. note that we don't have resolved paths for those.
446 for (const auto &Inc : BaselineScan->Includes)
447 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
448 // Calculate extra includes that needs to be inserted.
449 for (auto &Inc : ModifiedScan->Includes) {
450 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
451 // Include already present in the baseline preamble. Set resolved path and
452 // put into preamble includes.
453 if (It != ExistingIncludes.end()) {
454 Inc.Resolved = It->second.str();
455 PP.PreambleIncludes.push_back(Inc);
456 continue;
457 }
458 // Include is new in the modified preamble. Inject it into the patch and
459 // use #line to set the presumed location to where it is spelled.
460 auto LineCol = offsetToClangLineColumn(Modified.Contents, Inc.HashOffset);
461 Patch << llvm::formatv("#line {0}\n", LineCol.first);
462 Patch << llvm::formatv(
463 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
464 }
465 }
466
467 if (DirectivesChanged) {
468 // We need to patch all the directives, since they are order dependent. e.g:
469 // #define BAR(X) NEW(X) // Newly introduced in Modified
470 // #define BAR(X) OLD(X) // Exists in the Baseline
471 //
472 // If we've patched only the first directive, the macro definition would've
473 // been wrong for the rest of the file, since patch is applied after the
474 // baseline preamble.
475 //
476 // Note that we deliberately ignore conditional directives and undefs to
477 // reduce complexity. The former might cause problems because scanning is
478 // imprecise and might pick directives from disabled regions.
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200479 for (const auto &TD : ModifiedScan->TextualDirectives) {
480 Patch << "#line " << TD.DirectiveLine << '\n';
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200481 Patch << TD.Text << '\n';
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200482 }
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200483 }
484 dlog("Created preamble patch: {0}", Patch.str());
485 Patch.flush();
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200486 return PP;
487}
488
489void PreamblePatch::apply(CompilerInvocation &CI) const {
490 // No need to map an empty file.
491 if (PatchContents.empty())
492 return;
493 auto &PPOpts = CI.getPreprocessorOpts();
494 auto PatchBuffer =
495 // we copy here to ensure contents are still valid if CI outlives the
496 // PreamblePatch.
497 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
498 // CI will take care of the lifetime of the buffer.
499 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
500 // The patch will be parsed after loading the preamble ast and before parsing
501 // the main file.
502 PPOpts.Includes.push_back(PatchFileName);
503}
504
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200505std::vector<Inclusion> PreamblePatch::preambleIncludes() const {
506 return PreambleIncludes;
507}
508
509PreamblePatch PreamblePatch::unmodified(const PreambleData &Preamble) {
510 PreamblePatch PP;
511 PP.PreambleIncludes = Preamble.Includes.MainFileIncludes;
512 return PP;
513}
514
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200515SourceLocation translatePreamblePatchLocation(SourceLocation Loc,
516 const SourceManager &SM) {
517 auto DefFile = SM.getFileID(Loc);
518 if (auto *FE = SM.getFileEntryForID(DefFile)) {
519 auto IncludeLoc = SM.getIncludeLoc(DefFile);
520 // Preamble patch is included inside the builtin file.
521 if (IncludeLoc.isValid() && SM.isWrittenInBuiltinFile(IncludeLoc) &&
522 FE->getName().endswith(PreamblePatchHeaderName)) {
523 auto Presumed = SM.getPresumedLoc(Loc);
524 // Check that line directive is pointing at main file.
525 if (Presumed.isValid() && Presumed.getFileID().isInvalid() &&
526 isMainFile(Presumed.getFilename(), SM)) {
527 Loc = SM.translateLineCol(SM.getMainFileID(), Presumed.getLine(),
528 Presumed.getColumn());
529 }
530 }
531 }
532 return Loc;
533}
Sam McCallcf3a5852019-09-04 07:35:00 +0000534} // namespace clangd
535} // namespace clang