blob: 8e1ad7242eb010609c288785c7db4e934e25232e [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"
Kadir Cetinkaya06287052020-06-17 11:53:32 +020014#include "support/ThreadsafeFS.h"
Sam McCallad97ccf2020-04-28 17:49:17 +020015#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"
Kadir Cetinkaya2dc2e472020-06-16 12:16:24 +020033#include "llvm/ADT/None.h"
34#include "llvm/ADT/Optional.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020035#include "llvm/ADT/STLExtras.h"
36#include "llvm/ADT/SmallString.h"
Kadir Cetinkaya717bef62020-04-23 17:44:51 +020037#include "llvm/ADT/StringExtras.h"
Kadir Cetinkaya2214b902020-04-02 10:53:23 +020038#include "llvm/ADT/StringRef.h"
39#include "llvm/ADT/StringSet.h"
40#include "llvm/Support/Error.h"
41#include "llvm/Support/ErrorHandling.h"
42#include "llvm/Support/FormatVariadic.h"
43#include "llvm/Support/MemoryBuffer.h"
44#include "llvm/Support/Path.h"
45#include "llvm/Support/VirtualFileSystem.h"
46#include "llvm/Support/raw_ostream.h"
47#include <iterator>
48#include <memory>
49#include <string>
50#include <system_error>
51#include <utility>
52#include <vector>
Sam McCallcf3a5852019-09-04 07:35:00 +000053
54namespace clang {
55namespace clangd {
56namespace {
Kadir Cetinkaya538c2752020-05-14 12:26:47 +020057constexpr llvm::StringLiteral PreamblePatchHeaderName = "__preamble_patch__.h";
Sam McCallcf3a5852019-09-04 07:35:00 +000058
59bool compileCommandsAreEqual(const tooling::CompileCommand &LHS,
60 const tooling::CompileCommand &RHS) {
61 // We don't check for Output, it should not matter to clangd.
62 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
63 llvm::makeArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
64}
65
Sam McCallcf3a5852019-09-04 07:35:00 +000066class CppFilePreambleCallbacks : public PreambleCallbacks {
67public:
68 CppFilePreambleCallbacks(PathRef File, PreambleParsedCallback ParsedCallback)
Haojian Wu7e3c74b2019-09-24 11:14:06 +000069 : File(File), ParsedCallback(ParsedCallback) {}
Sam McCallcf3a5852019-09-04 07:35:00 +000070
71 IncludeStructure takeIncludes() { return std::move(Includes); }
72
Haojian Wu7e3c74b2019-09-24 11:14:06 +000073 MainFileMacros takeMacros() { return std::move(Macros); }
Sam McCallcf3a5852019-09-04 07:35:00 +000074
75 CanonicalIncludes takeCanonicalIncludes() { return std::move(CanonIncludes); }
76
77 void AfterExecute(CompilerInstance &CI) override {
78 if (!ParsedCallback)
79 return;
80 trace::Span Tracer("Running PreambleCallback");
81 ParsedCallback(CI.getASTContext(), CI.getPreprocessorPtr(), CanonIncludes);
82 }
83
84 void BeforeExecute(CompilerInstance &CI) override {
Ilya Biryukov8b767092019-09-09 15:32:51 +000085 CanonIncludes.addSystemHeadersMapping(CI.getLangOpts());
Haojian Wu7e3c74b2019-09-24 11:14:06 +000086 LangOpts = &CI.getLangOpts();
Sam McCallcf3a5852019-09-04 07:35:00 +000087 SourceMgr = &CI.getSourceManager();
88 }
89
90 std::unique_ptr<PPCallbacks> createPPCallbacks() override {
Haojian Wu7e3c74b2019-09-24 11:14:06 +000091 assert(SourceMgr && LangOpts &&
92 "SourceMgr and LangOpts must be set at this point");
93
Sam McCallcf3a5852019-09-04 07:35:00 +000094 return std::make_unique<PPChainedCallbacks>(
95 collectIncludeStructureCallback(*SourceMgr, &Includes),
Kadir Cetinkaya37550392020-03-01 16:05:12 +010096 std::make_unique<CollectMainFileMacros>(*SourceMgr, Macros));
Sam McCallcf3a5852019-09-04 07:35:00 +000097 }
98
99 CommentHandler *getCommentHandler() override {
100 IWYUHandler = collectIWYUHeaderMaps(&CanonIncludes);
101 return IWYUHandler.get();
102 }
103
Sam McCall4160f4c2020-06-09 15:46:35 +0200104 bool shouldSkipFunctionBody(Decl *D) override {
105 // Generally we skip function bodies in preambles for speed.
106 // We can make exceptions for functions that are cheap to parse and
107 // instantiate, widely used, and valuable (e.g. commonly produce errors).
108 if (const auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
109 if (const auto *II = FT->getDeclName().getAsIdentifierInfo())
110 // std::make_unique is trivial, and we diagnose bad constructor calls.
111 if (II->isStr("make_unique") && FT->isInStdNamespace())
112 return false;
113 }
114 return true;
115 }
116
Sam McCallcf3a5852019-09-04 07:35:00 +0000117private:
118 PathRef File;
119 PreambleParsedCallback ParsedCallback;
120 IncludeStructure Includes;
121 CanonicalIncludes CanonIncludes;
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000122 MainFileMacros Macros;
Sam McCallcf3a5852019-09-04 07:35:00 +0000123 std::unique_ptr<CommentHandler> IWYUHandler = nullptr;
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000124 const clang::LangOptions *LangOpts = nullptr;
125 const SourceManager *SourceMgr = nullptr;
Sam McCallcf3a5852019-09-04 07:35:00 +0000126};
127
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200128// Represents directives other than includes, where basic textual information is
129// enough.
130struct TextualPPDirective {
131 unsigned DirectiveLine;
132 // Full text that's representing the directive, including the `#`.
133 std::string Text;
134
135 bool operator==(const TextualPPDirective &RHS) const {
136 return std::tie(DirectiveLine, Text) ==
137 std::tie(RHS.DirectiveLine, RHS.Text);
138 }
139};
140
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200141// Formats a PP directive consisting of Prefix (e.g. "#define ") and Body ("X
142// 10"). The formatting is copied so that the tokens in Body have PresumedLocs
143// with correct columns and lines.
144std::string spellDirective(llvm::StringRef Prefix,
145 CharSourceRange DirectiveRange,
146 const LangOptions &LangOpts, const SourceManager &SM,
147 unsigned &DirectiveLine) {
148 std::string SpelledDirective;
149 llvm::raw_string_ostream OS(SpelledDirective);
150 OS << Prefix;
151
152 // Make sure DirectiveRange is a char range and doesn't contain macro ids.
153 DirectiveRange = SM.getExpansionRange(DirectiveRange);
154 if (DirectiveRange.isTokenRange()) {
155 DirectiveRange.setEnd(
156 Lexer::getLocForEndOfToken(DirectiveRange.getEnd(), 0, SM, LangOpts));
157 }
158
159 auto DecompLoc = SM.getDecomposedLoc(DirectiveRange.getBegin());
160 DirectiveLine = SM.getLineNumber(DecompLoc.first, DecompLoc.second);
161 auto TargetColumn = SM.getColumnNumber(DecompLoc.first, DecompLoc.second) - 1;
162
163 // Pad with spaces before DirectiveRange to make sure it will be on right
164 // column when patched.
165 if (Prefix.size() <= TargetColumn) {
166 // There is enough space for Prefix and space before directive, use it.
167 // We try to squeeze the Prefix into the same line whenever we can, as
168 // putting onto a separate line won't work at the beginning of the file.
169 OS << std::string(TargetColumn - Prefix.size(), ' ');
170 } else {
171 // Prefix was longer than the space we had. We produce e.g.:
172 // #line N-1
173 // #define \
174 // X 10
175 OS << "\\\n" << std::string(TargetColumn, ' ');
176 // Decrement because we put an additional line break before
177 // DirectiveRange.begin().
178 --DirectiveLine;
179 }
180 OS << toSourceCode(SM, DirectiveRange.getAsRange());
181 return OS.str();
182}
183
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200184// Collects #define directives inside the main file.
185struct DirectiveCollector : public PPCallbacks {
186 DirectiveCollector(const Preprocessor &PP,
187 std::vector<TextualPPDirective> &TextualDirectives)
188 : LangOpts(PP.getLangOpts()), SM(PP.getSourceManager()),
189 TextualDirectives(TextualDirectives) {}
190
191 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
192 SrcMgr::CharacteristicKind FileType,
193 FileID PrevFID) override {
194 InMainFile = SM.isWrittenInMainFile(Loc);
195 }
196
197 void MacroDefined(const Token &MacroNameTok,
198 const MacroDirective *MD) override {
199 if (!InMainFile)
200 return;
201 TextualDirectives.emplace_back();
202 TextualPPDirective &TD = TextualDirectives.back();
203
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200204 const auto *MI = MD->getMacroInfo();
205 TD.Text =
206 spellDirective("#define ",
207 CharSourceRange::getTokenRange(
208 MI->getDefinitionLoc(), MI->getDefinitionEndLoc()),
209 LangOpts, SM, TD.DirectiveLine);
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200210 }
211
212private:
213 bool InMainFile = true;
214 const LangOptions &LangOpts;
215 const SourceManager &SM;
216 std::vector<TextualPPDirective> &TextualDirectives;
217};
218
219struct ScannedPreamble {
220 std::vector<Inclusion> Includes;
221 std::vector<TextualPPDirective> TextualDirectives;
Kadir Cetinkaya4317ee22020-06-16 21:21:45 +0200222 PreambleBounds Bounds = {0, false};
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200223};
224
225/// Scans the preprocessor directives in the preamble section of the file by
226/// running preprocessor over \p Contents. Returned includes do not contain
Kadir Cetinkayad2fcc582020-06-17 18:09:54 +0200227/// resolved paths. \p Cmd is used to build the compiler invocation, which might
228/// stat/read files.
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200229llvm::Expected<ScannedPreamble>
Kadir Cetinkayad2fcc582020-06-17 18:09:54 +0200230scanPreamble(llvm::StringRef Contents, const tooling::CompileCommand &Cmd) {
231 class EmptyFS : public ThreadsafeFS {
Sam McCall72568982020-06-29 19:52:09 +0200232 private:
233 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl() const override {
Kadir Cetinkayad2fcc582020-06-17 18:09:54 +0200234 return new llvm::vfs::InMemoryFileSystem;
235 }
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200236 };
Kadir Cetinkayad2fcc582020-06-17 18:09:54 +0200237 EmptyFS FS;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200238 // Build and run Preprocessor over the preamble.
239 ParseInputs PI;
240 PI.Contents = Contents.str();
Kadir Cetinkayad2fcc582020-06-17 18:09:54 +0200241 PI.TFS = &FS;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200242 PI.CompileCommand = Cmd;
243 IgnoringDiagConsumer IgnoreDiags;
244 auto CI = buildCompilerInvocation(PI, IgnoreDiags);
245 if (!CI)
Sam McCall687e1d72020-09-14 11:33:12 +0200246 return error("failed to create compiler invocation");
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200247 CI->getDiagnosticOpts().IgnoreWarnings = true;
248 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(Contents);
Kadir Cetinkaya34e39eb2020-05-05 17:55:11 +0200249 // This means we're scanning (though not preprocessing) the preamble section
250 // twice. However, it's important to precisely follow the preamble bounds used
251 // elsewhere.
252 auto Bounds =
253 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
254 auto PreambleContents =
255 llvm::MemoryBuffer::getMemBufferCopy(Contents.substr(0, Bounds.Size));
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200256 auto Clang = prepareCompilerInstance(
Kadir Cetinkaya34e39eb2020-05-05 17:55:11 +0200257 std::move(CI), nullptr, std::move(PreambleContents),
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200258 // Provide an empty FS to prevent preprocessor from performing IO. This
259 // also implies missing resolved paths for includes.
Kadir Cetinkayad2fcc582020-06-17 18:09:54 +0200260 FS.view(llvm::None), IgnoreDiags);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200261 if (Clang->getFrontendOpts().Inputs.empty())
Sam McCall687e1d72020-09-14 11:33:12 +0200262 return error("compiler instance had no inputs");
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200263 // We are only interested in main file includes.
264 Clang->getPreprocessorOpts().SingleFileParseMode = true;
Kadir Cetinkaya34e39eb2020-05-05 17:55:11 +0200265 PreprocessOnlyAction Action;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200266 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
Sam McCall687e1d72020-09-14 11:33:12 +0200267 return error("failed BeginSourceFile");
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200268 const auto &SM = Clang->getSourceManager();
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200269 Preprocessor &PP = Clang->getPreprocessor();
270 IncludeStructure Includes;
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200271 PP.addPPCallbacks(collectIncludeStructureCallback(SM, &Includes));
272 ScannedPreamble SP;
Kadir Cetinkaya4317ee22020-06-16 21:21:45 +0200273 SP.Bounds = Bounds;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200274 PP.addPPCallbacks(
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200275 std::make_unique<DirectiveCollector>(PP, SP.TextualDirectives));
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200276 if (llvm::Error Err = Action.Execute())
277 return std::move(Err);
278 Action.EndSourceFile();
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200279 SP.Includes = std::move(Includes.MainFileIncludes);
280 return SP;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200281}
282
283const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
284 switch (IncludeDirective) {
285 case tok::pp_include:
286 return "include";
287 case tok::pp_import:
288 return "import";
289 case tok::pp_include_next:
290 return "include_next";
291 default:
292 break;
293 }
294 llvm_unreachable("not an include directive");
295}
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200296
297// Checks whether \p FileName is a valid spelling of main file.
298bool isMainFile(llvm::StringRef FileName, const SourceManager &SM) {
299 auto FE = SM.getFileManager().getFile(FileName);
300 return FE && *FE == SM.getFileEntryForID(SM.getMainFileID());
301}
302
Sam McCallcf3a5852019-09-04 07:35:00 +0000303} // namespace
304
Kadir Cetinkayaecd3e672020-03-11 16:34:01 +0100305PreambleData::PreambleData(const ParseInputs &Inputs,
Sam McCall2cd33e62020-03-04 00:33:29 +0100306 PrecompiledPreamble Preamble,
Sam McCallcf3a5852019-09-04 07:35:00 +0000307 std::vector<Diag> Diags, IncludeStructure Includes,
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000308 MainFileMacros Macros,
Sam McCallcf3a5852019-09-04 07:35:00 +0000309 std::unique_ptr<PreambleFileStatusCache> StatCache,
310 CanonicalIncludes CanonIncludes)
Kadir Cetinkayaecd3e672020-03-11 16:34:01 +0100311 : Version(Inputs.Version), CompileCommand(Inputs.CompileCommand),
312 Preamble(std::move(Preamble)), Diags(std::move(Diags)),
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000313 Includes(std::move(Includes)), Macros(std::move(Macros)),
Sam McCallcf3a5852019-09-04 07:35:00 +0000314 StatCache(std::move(StatCache)), CanonIncludes(std::move(CanonIncludes)) {
315}
316
317std::shared_ptr<const PreambleData>
Kadir Cetinkaya276a95b2020-03-13 11:52:19 +0100318buildPreamble(PathRef FileName, CompilerInvocation CI,
Sam McCallcf3a5852019-09-04 07:35:00 +0000319 const ParseInputs &Inputs, bool StoreInMemory,
320 PreambleParsedCallback PreambleCallback) {
321 // Note that we don't need to copy the input contents, preamble can live
322 // without those.
323 auto ContentsBuffer =
324 llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName);
325 auto Bounds =
326 ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
327
Sam McCallcf3a5852019-09-04 07:35:00 +0000328 trace::Span Tracer("BuildPreamble");
329 SPAN_ATTACH(Tracer, "File", FileName);
330 StoreDiags PreambleDiagnostics;
331 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
332 CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(),
333 &PreambleDiagnostics, false);
334
335 // Skip function bodies when building the preamble to speed up building
336 // the preamble and make it smaller.
337 assert(!CI.getFrontendOpts().SkipFunctionBodies);
338 CI.getFrontendOpts().SkipFunctionBodies = true;
339 // We don't want to write comment locations into PCH. They are racy and slow
340 // to read back. We rely on dynamic index for the comments instead.
341 CI.getPreprocessorOpts().WriteCommentListToPCH = false;
342
343 CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback);
Kadir Cetinkaya8d654df2020-06-17 18:09:54 +0200344 auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
Sam McCallcf3a5852019-09-04 07:35:00 +0000345 llvm::SmallString<32> AbsFileName(FileName);
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200346 VFS->makeAbsolute(AbsFileName);
Sam McCallcf3a5852019-09-04 07:35:00 +0000347 auto StatCache = std::make_unique<PreambleFileStatusCache>(AbsFileName);
348 auto BuiltPreamble = PrecompiledPreamble::Build(
349 CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine,
Kadir Cetinkayaf693ce42020-06-04 18:26:52 +0200350 StatCache->getProducingFS(VFS),
Sam McCallcf3a5852019-09-04 07:35:00 +0000351 std::make_shared<PCHContainerOperations>(), StoreInMemory,
352 SerializedDeclsCollector);
353
354 // When building the AST for the main file, we do want the function
355 // bodies.
356 CI.getFrontendOpts().SkipFunctionBodies = false;
357
358 if (BuiltPreamble) {
Sam McCall2cd33e62020-03-04 00:33:29 +0100359 vlog("Built preamble of size {0} for file {1} version {2}",
360 BuiltPreamble->getSize(), FileName, Inputs.Version);
Sam McCallcf3a5852019-09-04 07:35:00 +0000361 std::vector<Diag> Diags = PreambleDiagnostics.take();
362 return std::make_shared<PreambleData>(
Kadir Cetinkayaecd3e672020-03-11 16:34:01 +0100363 Inputs, std::move(*BuiltPreamble), std::move(Diags),
Sam McCallcf3a5852019-09-04 07:35:00 +0000364 SerializedDeclsCollector.takeIncludes(),
Haojian Wu7e3c74b2019-09-24 11:14:06 +0000365 SerializedDeclsCollector.takeMacros(), std::move(StatCache),
Sam McCallcf3a5852019-09-04 07:35:00 +0000366 SerializedDeclsCollector.takeCanonicalIncludes());
367 } else {
Adam Czachorowski55b92dc2020-03-19 15:09:28 +0100368 elog("Could not build a preamble for file {0} version {1}", FileName,
Sam McCall2cd33e62020-03-04 00:33:29 +0100369 Inputs.Version);
Sam McCallcf3a5852019-09-04 07:35:00 +0000370 return nullptr;
371 }
372}
373
Kadir Cetinkayac31367e2020-03-15 21:43:00 +0100374bool isPreambleCompatible(const PreambleData &Preamble,
375 const ParseInputs &Inputs, PathRef FileName,
376 const CompilerInvocation &CI) {
377 auto ContentsBuffer =
378 llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName);
379 auto Bounds =
380 ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
Kadir Cetinkaya8d654df2020-06-17 18:09:54 +0200381 auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
Kadir Cetinkayac31367e2020-03-15 21:43:00 +0100382 return compileCommandsAreEqual(Inputs.CompileCommand,
383 Preamble.CompileCommand) &&
384 Preamble.Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds,
Kadir Cetinkaya37251422020-06-16 11:02:08 +0200385 VFS.get());
Kadir Cetinkayac31367e2020-03-15 21:43:00 +0100386}
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200387
Kadir Cetinkaya717bef62020-04-23 17:44:51 +0200388void escapeBackslashAndQuotes(llvm::StringRef Text, llvm::raw_ostream &OS) {
389 for (char C : Text) {
390 switch (C) {
391 case '\\':
392 case '"':
393 OS << '\\';
394 break;
395 default:
396 break;
397 }
398 OS << C;
399 }
400}
401
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200402PreamblePatch PreamblePatch::create(llvm::StringRef FileName,
403 const ParseInputs &Modified,
404 const PreambleData &Baseline) {
Kadir Cetinkaya20b2af32020-05-29 12:31:35 +0200405 trace::Span Tracer("CreatePreamblePatch");
406 SPAN_ATTACH(Tracer, "File", FileName);
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200407 assert(llvm::sys::path::is_absolute(FileName) && "relative FileName!");
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200408 // First scan preprocessor directives in Baseline and Modified. These will be
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200409 // used to figure out newly added directives in Modified. Scanning can fail,
410 // the code just bails out and creates an empty patch in such cases, as:
411 // - If scanning for Baseline fails, no knowledge of existing includes hence
412 // patch will contain all the includes in Modified. Leading to rebuild of
413 // whole preamble, which is terribly slow.
414 // - If scanning for Modified fails, cannot figure out newly added ones so
415 // there's nothing to do but generate an empty patch.
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200416 auto BaselineScan = scanPreamble(
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200417 // Contents needs to be null-terminated.
Kadir Cetinkayad2fcc582020-06-17 18:09:54 +0200418 Baseline.Preamble.getContents().str(), Modified.CompileCommand);
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200419 if (!BaselineScan) {
420 elog("Failed to scan baseline of {0}: {1}", FileName,
421 BaselineScan.takeError());
422 return PreamblePatch::unmodified(Baseline);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200423 }
Kadir Cetinkayad2fcc582020-06-17 18:09:54 +0200424 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand);
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200425 if (!ModifiedScan) {
426 elog("Failed to scan modified contents of {0}: {1}", FileName,
427 ModifiedScan.takeError());
428 return PreamblePatch::unmodified(Baseline);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200429 }
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200430
431 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
432 bool DirectivesChanged =
433 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
434 if (!IncludesChanged && !DirectivesChanged)
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200435 return PreamblePatch::unmodified(Baseline);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200436
437 PreamblePatch PP;
438 // This shouldn't coincide with any real file name.
439 llvm::SmallString<128> PatchName;
440 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName),
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200441 PreamblePatchHeaderName);
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200442 PP.PatchFileName = PatchName.str().str();
Kadir Cetinkaya4317ee22020-06-16 21:21:45 +0200443 PP.ModifiedBounds = ModifiedScan->Bounds;
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200444
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200445 llvm::raw_string_ostream Patch(PP.PatchContents);
Kadir Cetinkaya717bef62020-04-23 17:44:51 +0200446 // Set default filename for subsequent #line directives
447 Patch << "#line 0 \"";
448 // FileName part of a line directive is subject to backslash escaping, which
449 // might lead to problems on windows especially.
450 escapeBackslashAndQuotes(FileName, Patch);
451 Patch << "\"\n";
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200452
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200453 if (IncludesChanged) {
454 // We are only interested in newly added includes, record the ones in
455 // Baseline for exclusion.
456 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
457 /*Resolved=*/llvm::StringRef>
458 ExistingIncludes;
459 for (const auto &Inc : Baseline.Includes.MainFileIncludes)
460 ExistingIncludes[{Inc.Directive, Inc.Written}] = Inc.Resolved;
461 // There might be includes coming from disabled regions, record these for
462 // exclusion too. note that we don't have resolved paths for those.
463 for (const auto &Inc : BaselineScan->Includes)
464 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
465 // Calculate extra includes that needs to be inserted.
466 for (auto &Inc : ModifiedScan->Includes) {
467 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
468 // Include already present in the baseline preamble. Set resolved path and
469 // put into preamble includes.
470 if (It != ExistingIncludes.end()) {
471 Inc.Resolved = It->second.str();
472 PP.PreambleIncludes.push_back(Inc);
473 continue;
474 }
475 // Include is new in the modified preamble. Inject it into the patch and
476 // use #line to set the presumed location to where it is spelled.
477 auto LineCol = offsetToClangLineColumn(Modified.Contents, Inc.HashOffset);
478 Patch << llvm::formatv("#line {0}\n", LineCol.first);
479 Patch << llvm::formatv(
480 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
481 }
482 }
483
484 if (DirectivesChanged) {
485 // We need to patch all the directives, since they are order dependent. e.g:
486 // #define BAR(X) NEW(X) // Newly introduced in Modified
487 // #define BAR(X) OLD(X) // Exists in the Baseline
488 //
489 // If we've patched only the first directive, the macro definition would've
490 // been wrong for the rest of the file, since patch is applied after the
491 // baseline preamble.
492 //
493 // Note that we deliberately ignore conditional directives and undefs to
494 // reduce complexity. The former might cause problems because scanning is
495 // imprecise and might pick directives from disabled regions.
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200496 for (const auto &TD : ModifiedScan->TextualDirectives) {
497 Patch << "#line " << TD.DirectiveLine << '\n';
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200498 Patch << TD.Text << '\n';
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200499 }
Kadir Cetinkayafcde3d52020-05-14 12:20:33 +0200500 }
501 dlog("Created preamble patch: {0}", Patch.str());
502 Patch.flush();
Kadir Cetinkaya2214b902020-04-02 10:53:23 +0200503 return PP;
504}
505
506void PreamblePatch::apply(CompilerInvocation &CI) const {
507 // No need to map an empty file.
508 if (PatchContents.empty())
509 return;
510 auto &PPOpts = CI.getPreprocessorOpts();
511 auto PatchBuffer =
512 // we copy here to ensure contents are still valid if CI outlives the
513 // PreamblePatch.
514 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
515 // CI will take care of the lifetime of the buffer.
516 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
517 // The patch will be parsed after loading the preamble ast and before parsing
518 // the main file.
519 PPOpts.Includes.push_back(PatchFileName);
520}
521
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200522std::vector<Inclusion> PreamblePatch::preambleIncludes() const {
523 return PreambleIncludes;
524}
525
526PreamblePatch PreamblePatch::unmodified(const PreambleData &Preamble) {
527 PreamblePatch PP;
528 PP.PreambleIncludes = Preamble.Includes.MainFileIncludes;
Kadir Cetinkaya4317ee22020-06-16 21:21:45 +0200529 PP.ModifiedBounds = Preamble.Preamble.getBounds();
Kadir Cetinkayab742eaa2020-04-02 10:53:45 +0200530 return PP;
531}
532
Kadir Cetinkaya538c2752020-05-14 12:26:47 +0200533SourceLocation translatePreamblePatchLocation(SourceLocation Loc,
534 const SourceManager &SM) {
535 auto DefFile = SM.getFileID(Loc);
536 if (auto *FE = SM.getFileEntryForID(DefFile)) {
537 auto IncludeLoc = SM.getIncludeLoc(DefFile);
538 // Preamble patch is included inside the builtin file.
539 if (IncludeLoc.isValid() && SM.isWrittenInBuiltinFile(IncludeLoc) &&
540 FE->getName().endswith(PreamblePatchHeaderName)) {
541 auto Presumed = SM.getPresumedLoc(Loc);
542 // Check that line directive is pointing at main file.
543 if (Presumed.isValid() && Presumed.getFileID().isInvalid() &&
544 isMainFile(Presumed.getFilename(), SM)) {
545 Loc = SM.translateLineCol(SM.getMainFileID(), Presumed.getLine(),
546 Presumed.getColumn());
547 }
548 }
549 }
550 return Loc;
551}
Sam McCallcf3a5852019-09-04 07:35:00 +0000552} // namespace clangd
553} // namespace clang