16 #include "clang/AST/DeclTemplate.h"
17 #include "clang/Basic/Diagnostic.h"
18 #include "clang/Basic/LangOptions.h"
19 #include "clang/Basic/SourceLocation.h"
20 #include "clang/Basic/SourceManager.h"
21 #include "clang/Basic/TokenKinds.h"
22 #include "clang/Frontend/CompilerInvocation.h"
23 #include "clang/Frontend/FrontendActions.h"
24 #include "clang/Lex/Lexer.h"
25 #include "clang/Lex/PPCallbacks.h"
26 #include "clang/Lex/Preprocessor.h"
27 #include "clang/Lex/PreprocessorOptions.h"
28 #include "clang/Tooling/CompilationDatabase.h"
29 #include "llvm/ADT/ArrayRef.h"
30 #include "llvm/ADT/DenseMap.h"
31 #include "llvm/ADT/DenseSet.h"
32 #include "llvm/ADT/IntrusiveRefCntPtr.h"
33 #include "llvm/ADT/None.h"
34 #include "llvm/ADT/Optional.h"
35 #include "llvm/ADT/STLExtras.h"
36 #include "llvm/ADT/SmallString.h"
37 #include "llvm/ADT/StringExtras.h"
38 #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"
50 #include <system_error>
57 constexpr llvm::StringLiteral PreamblePatchHeaderName =
"__preamble_patch__.h";
59 bool compileCommandsAreEqual(
const tooling::CompileCommand &LHS,
60 const tooling::CompileCommand &RHS) {
62 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
63 llvm::makeArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
66 class CppFilePreambleCallbacks :
public PreambleCallbacks {
69 :
File(
File), ParsedCallback(ParsedCallback) {}
71 IncludeStructure takeIncludes() {
return std::move(Includes); }
73 MainFileMacros takeMacros() {
return std::move(Macros); }
75 CanonicalIncludes takeCanonicalIncludes() {
return std::move(CanonIncludes); }
77 void AfterExecute(CompilerInstance &
CI)
override {
80 trace::Span
Tracer(
"Running PreambleCallback");
81 ParsedCallback(
CI.getASTContext(),
CI.getPreprocessorPtr(), CanonIncludes);
84 void BeforeExecute(CompilerInstance &
CI)
override {
85 CanonIncludes.addSystemHeadersMapping(
CI.getLangOpts());
86 LangOpts = &
CI.getLangOpts();
90 std::unique_ptr<PPCallbacks> createPPCallbacks()
override {
92 "SourceMgr and LangOpts must be set at this point");
94 return std::make_unique<PPChainedCallbacks>(
96 std::make_unique<CollectMainFileMacros>(*
SourceMgr, Macros));
99 CommentHandler *getCommentHandler()
override {
101 return IWYUHandler.get();
104 bool shouldSkipFunctionBody(
Decl *D)
override {
108 if (
const auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
109 if (
const auto *II = FT->getDeclName().getAsIdentifierInfo())
111 if (II->isStr(
"make_unique") && FT->isInStdNamespace())
120 IncludeStructure Includes;
121 CanonicalIncludes CanonIncludes;
122 MainFileMacros Macros;
123 std::unique_ptr<CommentHandler> IWYUHandler =
nullptr;
124 const clang::LangOptions *LangOpts =
nullptr;
125 const SourceManager *
SourceMgr =
nullptr;
130 struct TextualPPDirective {
135 bool operator==(
const TextualPPDirective &RHS)
const {
137 std::tie(RHS.DirectiveLine, RHS.Text);
144 std::string spellDirective(llvm::StringRef Prefix,
145 CharSourceRange DirectiveRange,
146 const LangOptions &LangOpts,
const SourceManager &SM,
148 std::string SpelledDirective;
149 llvm::raw_string_ostream
OS(SpelledDirective);
153 DirectiveRange = SM.getExpansionRange(DirectiveRange);
154 if (DirectiveRange.isTokenRange()) {
155 DirectiveRange.setEnd(
156 Lexer::getLocForEndOfToken(DirectiveRange.getEnd(), 0, SM, LangOpts));
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;
165 if (Prefix.size() <= TargetColumn) {
169 OS << std::string(TargetColumn - Prefix.size(),
' ');
175 OS <<
"\\\n" << std::string(TargetColumn,
' ');
186 DirectiveCollector(
const Preprocessor &
PP,
187 std::vector<TextualPPDirective> &TextualDirectives)
188 : LangOpts(
PP.getLangOpts()), SM(
PP.getSourceManager()),
189 TextualDirectives(TextualDirectives) {}
191 void FileChanged(SourceLocation
Loc, FileChangeReason Reason,
192 SrcMgr::CharacteristicKind FileType,
193 FileID PrevFID)
override {
194 InMainFile = SM.isWrittenInMainFile(
Loc);
197 void MacroDefined(
const Token &MacroNameTok,
198 const MacroDirective *
MD)
override {
201 TextualDirectives.emplace_back();
202 TextualPPDirective &TD = TextualDirectives.back();
204 const auto *MI =
MD->getMacroInfo();
206 spellDirective(
"#define ",
207 CharSourceRange::getTokenRange(
208 MI->getDefinitionLoc(), MI->getDefinitionEndLoc()),
209 LangOpts, SM, TD.DirectiveLine);
213 bool InMainFile =
true;
214 const LangOptions &LangOpts;
215 const SourceManager &SM;
216 std::vector<TextualPPDirective> &TextualDirectives;
219 struct ScannedPreamble {
220 std::vector<Inclusion> Includes;
221 std::vector<TextualPPDirective> TextualDirectives;
229 llvm::Expected<ScannedPreamble>
230 scanPreamble(llvm::StringRef
Contents,
const tooling::CompileCommand &Cmd) {
231 class EmptyFS :
public ThreadsafeFS {
233 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
242 PI.CompileCommand = Cmd;
246 return llvm::createStringError(llvm::inconvertibleErrorCode(),
247 "failed to create compiler invocation");
248 CI->getDiagnosticOpts().IgnoreWarnings =
true;
249 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(
Contents);
254 ComputePreambleBounds(*
CI->getLangOpts(), ContentsBuffer.get(), 0);
255 auto PreambleContents =
256 llvm::MemoryBuffer::getMemBufferCopy(
Contents.substr(0,
Bounds.Size));
258 std::move(
CI),
nullptr, std::move(PreambleContents),
262 if (Clang->getFrontendOpts().Inputs.empty())
263 return llvm::createStringError(llvm::inconvertibleErrorCode(),
264 "compiler instance had no inputs");
266 Clang->getPreprocessorOpts().SingleFileParseMode =
true;
267 PreprocessOnlyAction
Action;
268 if (!
Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
269 return llvm::createStringError(llvm::inconvertibleErrorCode(),
270 "failed BeginSourceFile");
271 const auto &SM = Clang->getSourceManager();
272 Preprocessor &
PP = Clang->getPreprocessor();
273 IncludeStructure Includes;
278 std::make_unique<DirectiveCollector>(
PP, SP.TextualDirectives));
280 return std::move(Err);
286 const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
287 switch (IncludeDirective) {
288 case tok::pp_include:
292 case tok::pp_include_next:
293 return "include_next";
297 llvm_unreachable(
"not an include directive");
301 bool isMainFile(llvm::StringRef
FileName,
const SourceManager &SM) {
302 auto FE = SM.getFileManager().getFile(
FileName);
303 return FE && *FE == SM.getFileEntryForID(SM.getMainFileID());
312 std::unique_ptr<PreambleFileStatusCache> StatCache,
314 : Version(
Inputs.Version), CompileCommand(
Inputs.CompileCommand),
316 Includes(std::move(Includes)), Macros(std::move(Macros)),
317 StatCache(std::move(StatCache)), CanonIncludes(std::move(CanonIncludes)) {
320 std::shared_ptr<const PreambleData>
326 auto ContentsBuffer =
329 ComputePreambleBounds(*
CI.getLangOpts(), ContentsBuffer.get(), 0);
334 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
335 CompilerInstance::createDiagnostics(&
CI.getDiagnosticOpts(),
336 &PreambleDiagnostics,
false);
340 assert(!
CI.getFrontendOpts().SkipFunctionBodies);
341 CI.getFrontendOpts().SkipFunctionBodies =
true;
344 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
346 CppFilePreambleCallbacks SerializedDeclsCollector(
FileName, PreambleCallback);
348 llvm::SmallString<32> AbsFileName(
FileName);
349 VFS->makeAbsolute(AbsFileName);
350 auto StatCache = std::make_unique<PreambleFileStatusCache>(AbsFileName);
351 auto BuiltPreamble = PrecompiledPreamble::Build(
352 CI, ContentsBuffer.get(),
Bounds, *PreambleDiagsEngine,
353 StatCache->getProducingFS(VFS),
354 std::make_shared<PCHContainerOperations>(), StoreInMemory,
355 SerializedDeclsCollector);
359 CI.getFrontendOpts().SkipFunctionBodies =
false;
362 vlog(
"Built preamble of size {0} for file {1} version {2}",
364 std::vector<Diag>
Diags = PreambleDiagnostics.
take();
365 return std::make_shared<PreambleData>(
366 Inputs, std::move(*BuiltPreamble), std::move(
Diags),
367 SerializedDeclsCollector.takeIncludes(),
368 SerializedDeclsCollector.takeMacros(), std::move(StatCache),
369 SerializedDeclsCollector.takeCanonicalIncludes());
371 elog(
"Could not build a preamble for file {0} version {1}",
FileName,
379 const CompilerInvocation &
CI) {
380 auto ContentsBuffer =
383 ComputePreambleBounds(*
CI.getLangOpts(), ContentsBuffer.get(), 0);
392 for (
char C :
Text) {
410 assert(llvm::sys::path::is_absolute(
FileName) &&
"relative FileName!");
419 auto BaselineScan = scanPreamble(
424 BaselineScan.takeError());
429 elog(
"Failed to scan modified contents of {0}: {1}",
FileName,
430 ModifiedScan.takeError());
434 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
435 bool DirectivesChanged =
436 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
437 if (!IncludesChanged && !DirectivesChanged)
442 llvm::SmallString<128> PatchName;
443 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(
FileName),
444 PreamblePatchHeaderName);
445 PP.PatchFileName = PatchName.str().str();
446 PP.ModifiedBounds = ModifiedScan->Bounds;
448 llvm::raw_string_ostream
Patch(
PP.PatchContents);
450 Patch <<
"#line 0 \"";
456 if (IncludesChanged) {
459 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
463 ExistingIncludes[{Inc.Directive, Inc.Written}] = Inc.Resolved;
466 for (
const auto &Inc : BaselineScan->Includes)
467 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
469 for (
auto &Inc : ModifiedScan->Includes) {
470 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
473 if (It != ExistingIncludes.end()) {
474 Inc.Resolved = It->second.str();
475 PP.PreambleIncludes.push_back(Inc);
481 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
482 Patch << llvm::formatv(
483 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
487 if (DirectivesChanged) {
499 for (
const auto &TD : ModifiedScan->TextualDirectives) {
500 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
501 Patch << TD.Text <<
'\n';
504 dlog(
"Created preamble patch: {0}",
Patch.str());
511 if (PatchContents.empty())
513 auto &PPOpts =
CI.getPreprocessorOpts();
517 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
519 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
522 PPOpts.Includes.push_back(PatchFileName);
526 return PreambleIncludes;
531 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
532 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
537 const SourceManager &SM) {
538 auto DefFile = SM.getFileID(
Loc);
539 if (
auto *FE = SM.getFileEntryForID(DefFile)) {
540 auto IncludeLoc = SM.getIncludeLoc(DefFile);
542 if (IncludeLoc.isValid() && SM.isWrittenInBuiltinFile(IncludeLoc) &&
543 FE->getName().endswith(PreamblePatchHeaderName)) {
544 auto Presumed = SM.getPresumedLoc(
Loc);
546 if (Presumed.isValid() && Presumed.getFileID().isInvalid() &&
547 isMainFile(Presumed.getFilename(), SM)) {
548 Loc = SM.translateLineCol(SM.getMainFileID(), Presumed.getLine(),
549 Presumed.getColumn());