20#include "clang-include-cleaner/Record.h"
25#include "clang/AST/DeclTemplate.h"
26#include "clang/AST/Type.h"
27#include "clang/Basic/Diagnostic.h"
28#include "clang/Basic/DiagnosticLex.h"
29#include "clang/Basic/DiagnosticOptions.h"
30#include "clang/Basic/LangOptions.h"
31#include "clang/Basic/SourceLocation.h"
32#include "clang/Basic/SourceManager.h"
33#include "clang/Basic/TargetInfo.h"
34#include "clang/Basic/TokenKinds.h"
35#include "clang/Frontend/CompilerInstance.h"
36#include "clang/Frontend/CompilerInvocation.h"
37#include "clang/Frontend/FrontendActions.h"
38#include "clang/Frontend/PrecompiledPreamble.h"
39#include "clang/Lex/HeaderSearch.h"
40#include "clang/Lex/Lexer.h"
41#include "clang/Lex/PPCallbacks.h"
42#include "clang/Lex/Preprocessor.h"
43#include "clang/Lex/PreprocessorOptions.h"
44#include "clang/Serialization/ASTReader.h"
45#include "clang/Tooling/CompilationDatabase.h"
46#include "llvm/ADT/ArrayRef.h"
47#include "llvm/ADT/DenseMap.h"
48#include "llvm/ADT/IntrusiveRefCntPtr.h"
49#include "llvm/ADT/STLExtras.h"
50#include "llvm/ADT/SmallString.h"
51#include "llvm/ADT/SmallVector.h"
52#include "llvm/ADT/StringExtras.h"
53#include "llvm/ADT/StringMap.h"
54#include "llvm/ADT/StringRef.h"
55#include "llvm/Support/Casting.h"
56#include "llvm/Support/Error.h"
57#include "llvm/Support/ErrorHandling.h"
58#include "llvm/Support/ErrorOr.h"
59#include "llvm/Support/FormatVariadic.h"
60#include "llvm/Support/MemoryBuffer.h"
61#include "llvm/Support/Path.h"
62#include "llvm/Support/VirtualFileSystem.h"
63#include "llvm/Support/raw_ostream.h"
73#include <system_error>
82bool compileCommandsAreEqual(
const tooling::CompileCommand &LHS,
83 const tooling::CompileCommand &RHS) {
85 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
86 llvm::ArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
89class CppFilePreambleCallbacks :
public PreambleCallbacks {
91 CppFilePreambleCallbacks(
92 PathRef File, PreambleBuildStats *Stats,
bool ParseForwardingFunctions,
93 std::function<
void(CompilerInstance &)> BeforeExecuteCallback)
94 : File(File), Stats(Stats),
95 ParseForwardingFunctions(ParseForwardingFunctions),
96 BeforeExecuteCallback(std::move(BeforeExecuteCallback)) {}
98 IncludeStructure takeIncludes() {
return std::move(Includes); }
100 MainFileMacros takeMacros() {
return std::move(Macros); }
102 std::vector<PragmaMark> takeMarks() {
return std::move(Marks); }
104 include_cleaner::PragmaIncludes takePragmaIncludes() {
105 return std::move(Pragmas);
108 std::optional<CapturedASTCtx> takeLife() {
return std::move(CapturedCtx); }
110 bool isMainFileIncludeGuarded()
const {
return IsMainFileIncludeGuarded; }
112 void AfterExecute(CompilerInstance &CI)
override {
117 if (CI.getASTReader()) {
118 CI.getASTReader()->setDeserializationListener(
nullptr);
120 CI.getASTReader()->StartTranslationUnit(
nullptr);
122 CI.getASTContext().setASTMutationListener(
nullptr);
123 CapturedCtx.emplace(CI);
125 const SourceManager &SM = CI.getSourceManager();
126 OptionalFileEntryRef MainFE = SM.getFileEntryRefForID(SM.getMainFileID());
127 IsMainFileIncludeGuarded =
128 CI.getPreprocessor().getHeaderSearchInfo().isFileMultipleIncludeGuarded(
132 const ASTContext &
AST = CI.getASTContext();
133 Stats->BuildSize =
AST.getASTAllocatedMemory();
134 Stats->BuildSize +=
AST.getSideTableAllocatedMemory();
135 Stats->BuildSize +=
AST.Idents.getAllocator().getTotalMemory();
136 Stats->BuildSize +=
AST.Selectors.getTotalMemory();
138 Stats->BuildSize +=
AST.getSourceManager().getContentCacheSize();
139 Stats->BuildSize +=
AST.getSourceManager().getDataStructureSizes();
141 AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
143 const Preprocessor &PP = CI.getPreprocessor();
144 Stats->BuildSize += PP.getTotalMemory();
145 if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
146 Stats->BuildSize += PRec->getTotalMemory();
147 Stats->BuildSize += PP.getHeaderSearchInfo().getTotalMemory();
151 void BeforeExecute(CompilerInstance &CI)
override {
152 LangOpts = &CI.getLangOpts();
153 SourceMgr = &CI.getSourceManager();
154 PP = &CI.getPreprocessor();
155 Includes.collect(CI);
157 if (BeforeExecuteCallback)
158 BeforeExecuteCallback(CI);
161 std::unique_ptr<PPCallbacks> createPPCallbacks()
override {
162 assert(SourceMgr && LangOpts && PP &&
163 "SourceMgr, LangOpts and PP must be set at this point");
165 return std::make_unique<PPChainedCallbacks>(
166 std::make_unique<CollectMainFileMacros>(*PP, Macros),
170 bool shouldSkipFunctionBody(Decl *D)
override {
178 if (
auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
179 if (ParseForwardingFunctions) {
186 if (
const auto *II = FT->getDeclName().getAsIdentifierInfo()) {
187 if (II->isStr(
"make_unique") && FT->isInStdNamespace())
197 IncludeStructure Includes;
198 include_cleaner::PragmaIncludes Pragmas;
199 MainFileMacros Macros;
200 std::vector<PragmaMark> Marks;
201 bool IsMainFileIncludeGuarded =
false;
202 const clang::LangOptions *LangOpts =
nullptr;
203 const SourceManager *SourceMgr =
nullptr;
204 const Preprocessor *PP =
nullptr;
205 PreambleBuildStats *Stats;
206 bool ParseForwardingFunctions;
207 std::function<void(CompilerInstance &)> BeforeExecuteCallback;
208 std::optional<CapturedASTCtx> CapturedCtx;
213struct TextualPPDirective {
214 unsigned DirectiveLine;
218 tok::PPKeywordKind Directive = tok::PPKeywordKind::pp_not_keyword;
220 std::string MacroName;
222 bool operator==(
const TextualPPDirective &RHS)
const {
223 return std::tie(DirectiveLine, Offset, Text) ==
224 std::tie(RHS.DirectiveLine, RHS.Offset, RHS.Text);
231std::string spellDirective(llvm::StringRef Prefix,
232 CharSourceRange DirectiveRange,
233 const LangOptions &LangOpts,
const SourceManager &SM,
234 unsigned &DirectiveLine,
unsigned &Offset) {
235 std::string SpelledDirective;
236 llvm::raw_string_ostream OS(SpelledDirective);
240 DirectiveRange = SM.getExpansionRange(DirectiveRange);
241 if (DirectiveRange.isTokenRange()) {
242 DirectiveRange.setEnd(
243 Lexer::getLocForEndOfToken(DirectiveRange.getEnd(), 0, SM, LangOpts));
246 auto DecompLoc = SM.getDecomposedLoc(DirectiveRange.getBegin());
247 DirectiveLine = SM.getLineNumber(DecompLoc.first, DecompLoc.second);
248 Offset = DecompLoc.second;
249 auto TargetColumn = SM.getColumnNumber(DecompLoc.first, DecompLoc.second) - 1;
253 if (Prefix.size() <= TargetColumn) {
257 OS << std::string(TargetColumn - Prefix.size(),
' ');
263 OS <<
"\\\n" << std::string(TargetColumn,
' ');
273struct DirectiveCollector :
public PPCallbacks {
274 DirectiveCollector(
const Preprocessor &PP,
275 std::vector<TextualPPDirective> &TextualDirectives)
276 : LangOpts(PP.getLangOpts()), SM(PP.getSourceManager()),
277 TextualDirectives(TextualDirectives) {}
279 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
280 SrcMgr::CharacteristicKind FileType,
281 FileID PrevFID)
override {
282 InMainFile = SM.isWrittenInMainFile(Loc);
285 void MacroDefined(
const Token &MacroNameTok,
286 const MacroDirective *MD)
override {
289 TextualDirectives.emplace_back();
290 TextualPPDirective &TD = TextualDirectives.back();
291 TD.Directive = tok::pp_define;
292 TD.MacroName = MacroNameTok.getIdentifierInfo()->getName().str();
294 const auto *MI = MD->getMacroInfo();
296 spellDirective(
"#define ",
297 CharSourceRange::getTokenRange(
298 MI->getDefinitionLoc(), MI->getDefinitionEndLoc()),
299 LangOpts, SM, TD.DirectiveLine, TD.Offset);
303 bool InMainFile =
true;
304 const LangOptions &LangOpts;
305 const SourceManager &SM;
306 std::vector<TextualPPDirective> &TextualDirectives;
309struct ScannedPreamble {
310 std::vector<Inclusion> Includes;
311 std::vector<TextualPPDirective> TextualDirectives;
313 std::vector<llvm::StringRef> Lines;
314 PreambleBounds Bounds = {0,
false};
315 std::vector<PragmaMark> Marks;
316 MainFileMacros Macros;
323llvm::Expected<ScannedPreamble>
324scanPreamble(llvm::StringRef Contents,
const tooling::CompileCommand &Cmd) {
327 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
328 return new llvm::vfs::InMemoryFileSystem;
338 PI.CompileCommand = Cmd;
339 IgnoringDiagConsumer IgnoreDiags;
342 return error(
"failed to create compiler invocation");
343 CI->getDiagnosticOpts().IgnoreWarnings =
true;
344 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(PI.Contents);
348 auto Bounds = ComputePreambleBounds(CI->getLangOpts(), *ContentsBuffer, 0);
349 auto PreambleContents = llvm::MemoryBuffer::getMemBufferCopy(
350 llvm::StringRef(PI.Contents).take_front(Bounds.Size));
352 std::move(CI),
nullptr, std::move(PreambleContents),
355 FS.view(std::nullopt), IgnoreDiags);
356 if (Clang->getFrontendOpts().Inputs.empty())
357 return error(
"compiler instance had no inputs");
359 Clang->getPreprocessorOpts().SingleFileParseMode =
true;
360 Clang->getPreprocessorOpts().UsePredefines =
false;
361 PreprocessOnlyAction Action;
362 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
363 return error(
"failed BeginSourceFile");
364 Preprocessor &PP = Clang->getPreprocessor();
365 const auto &SM = PP.getSourceManager();
371 std::make_unique<DirectiveCollector>(PP, SP.TextualDirectives));
373 PP.addPPCallbacks(std::make_unique<CollectMainFileMacros>(PP, SP.Macros));
374 if (llvm::Error Err = Action.Execute())
375 return std::move(Err);
376 Action.EndSourceFile();
377 SP.Includes = std::move(Includes.MainFileIncludes);
378 llvm::append_range(SP.Lines, llvm::split(Contents,
"\n"));
382const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
383 switch (IncludeDirective) {
384 case tok::pp_include:
388 case tok::pp_include_next:
389 return "include_next";
393 llvm_unreachable(
"not an include directive");
402 WallTimer() : TotalTime(std::chrono::steady_clock::duration::zero()) {}
404 void startTimer() { StartTime = std::chrono::steady_clock::now(); }
407 TotalTime += std::chrono::steady_clock::now() - StartTime;
410 double getTime() {
return std::chrono::duration<double>(TotalTime).count(); }
413 std::chrono::steady_clock::duration TotalTime;
414 std::chrono::steady_clock::time_point StartTime;
417class WallTimerRegion {
419 WallTimerRegion(WallTimer &T) : T(T) { T.startTimer(); }
420 ~WallTimerRegion() { T.stopTimer(); }
428class TimerFile :
public llvm::vfs::File {
430 TimerFile(WallTimer &Timer, std::unique_ptr<File> InnerFile)
431 : Timer(Timer), InnerFile(std::move(InnerFile)) {}
433 llvm::ErrorOr<llvm::vfs::Status> status()
override {
434 WallTimerRegion
T(Timer);
435 return InnerFile->status();
437 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
438 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
439 bool IsVolatile)
override {
440 WallTimerRegion
T(Timer);
441 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
444 std::error_code close()
override {
445 WallTimerRegion
T(Timer);
446 return InnerFile->close();
451 std::unique_ptr<llvm::vfs::File> InnerFile;
456class TimerFS :
public llvm::vfs::ProxyFileSystem {
458 TimerFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
459 : ProxyFileSystem(std::move(FS)) {}
461 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
462 openFileForRead(
const llvm::Twine &
Path)
override {
463 WallTimerRegion
T(Timer);
464 auto FileOr = getUnderlyingFS().openFileForRead(
Path);
467 return std::make_unique<TimerFile>(Timer, std::move(FileOr.get()));
470 llvm::ErrorOr<llvm::vfs::Status> status(
const llvm::Twine &
Path)
override {
471 WallTimerRegion
T(Timer);
472 return getUnderlyingFS().status(
Path);
475 double getTime() {
return Timer.getTime(); }
483 llvm::ArrayRef<llvm::StringRef> OldLines;
484 llvm::ArrayRef<llvm::StringRef> CurrentLines;
485 llvm::StringMap<llvm::SmallVector<int>> CurrentContentsToLine;
491 bool translateRange(Range &R) {
492 int OldStart = R.start.line;
493 int OldEnd = R.end.line;
494 assert(OldStart <= OldEnd);
496 size_t RangeLen = OldEnd - OldStart + 1;
497 auto RangeContents = OldLines.slice(OldStart).take_front(RangeLen);
499 if (RangeContents.size() < RangeLen)
502 std::optional<int> Closest;
503 for (
int AlternateLine : CurrentContentsToLine.lookup(RangeContents[0])) {
506 CurrentLines.slice(AlternateLine).take_front(RangeLen))
508 int Delta = AlternateLine - OldStart;
509 if (!Closest.has_value() || abs(Delta) < abs(*Closest))
513 if (!Closest.has_value())
515 R.start.line += *Closest;
516 R.end.line += *Closest;
522 bool translateNote(Note &N) {
523 if (!N.InsideMainFile)
525 if (translateRange(N.Range))
532 bool translateFix(
Fix &F) {
534 F.Edits, [
this](TextEdit &E) { return translateRange(E.range); });
538 DiagPatcher(llvm::ArrayRef<llvm::StringRef> OldLines,
539 llvm::ArrayRef<llvm::StringRef> CurrentLines) {
540 this->OldLines = OldLines;
541 this->CurrentLines = CurrentLines;
542 for (
int Line = 0, E = CurrentLines.size(); Line != E; ++Line) {
543 llvm::StringRef Contents = CurrentLines[Line];
544 CurrentContentsToLine[Contents].push_back(Line);
551 std::optional<Diag> translateDiag(
const Diag &D) {
552 Range NewRange =
D.Range;
554 if (
D.InsideMainFile && !translateRange(NewRange)) {
560 NewD.Range = NewRange;
563 llvm::erase_if(NewD.Notes, [
this](Note &N) { return !translateNote(N); });
564 llvm::erase_if(NewD.Fixes, [
this](
Fix &F) { return !translateFix(F); });
570std::shared_ptr<const PreambleData>
577 auto ContentsBuffer =
578 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
579 auto Bounds = ComputePreambleBounds(CI.getLangOpts(), *ContentsBuffer, 0);
583 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
586 if (
auto Listener = M.astListeners())
587 ASTListeners.emplace_back(std::move(Listener));
593 for (
const auto &L : ASTListeners)
594 L->sawDiagnostic(D,
Diag);
597 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
598 CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
599 &PreambleDiagnostics,
602 PreambleDiagnostics.
setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
603 const clang::Diagnostic &
Info) {
607 return DiagnosticsEngine::Ignored;
608 switch (
Info.getID()) {
609 case diag::warn_no_newline_eof:
612 return Bounds.Size != ContentsBuffer->getBufferSize()
613 ? DiagnosticsEngine::Level::Ignored
621 assert(!CI.getFrontendOpts().SkipFunctionBodies);
622 CI.getFrontendOpts().SkipFunctionBodies =
true;
625 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
627 CppFilePreambleCallbacks CapturedInfo(
629 [&ASTListeners](CompilerInstance &CI) {
630 for (const auto &L : ASTListeners)
631 L->beforeExecute(CI);
633 llvm::SmallString<32> AbsFileName(FileName);
634 VFS->makeAbsolute(AbsFileName);
635 auto StatCache = std::make_shared<PreambleFileStatusCache>(AbsFileName);
636 auto StatCacheFS = StatCache->getProducingFS(VFS);
637 llvm::IntrusiveRefCntPtr<TimerFS> TimedFS(
new TimerFS(StatCacheFS));
639 WallTimer PreambleTimer;
640 PreambleTimer.startTimer();
641 auto BuiltPreamble = PrecompiledPreamble::Build(
642 CI, ContentsBuffer.get(), Bounds, PreambleDiagsEngine,
643 Stats ? TimedFS : StatCacheFS, std::make_shared<PCHContainerOperations>(),
644 StoreInMemory,
"", CapturedInfo);
646 PreambleTimer.stopTimer();
650 PreambleDiagsEngine->setClient(
new IgnoringDiagConsumer,
true);
653 PreambleDiagsEngine.reset();
657 CI.getFrontendOpts().SkipFunctionBodies =
false;
659 if (Stats !=
nullptr) {
662 Stats->
SerializedSize = BuiltPreamble ? BuiltPreamble->getSize() : 0;
666 log(
"Built preamble of size {0} for file {1} version {2} in {3} seconds",
667 BuiltPreamble->getSize(), FileName, Inputs.
Version,
668 PreambleTimer.getTime());
669 std::vector<Diag> Diags = PreambleDiagnostics.
take();
670 auto Result = std::make_shared<PreambleData>(std::move(*BuiltPreamble));
671 Result->Version = Inputs.
Version;
673 Result->Diags = std::move(Diags);
674 Result->Includes = CapturedInfo.takeIncludes();
675 Result->Pragmas = std::make_shared<const include_cleaner::PragmaIncludes>(
676 CapturedInfo.takePragmaIncludes());
679 WallTimer PrerequisiteModuleTimer;
680 PrerequisiteModuleTimer.startTimer();
681 Result->RequiredModules =
684 PrerequisiteModuleTimer.stopTimer();
686 log(
"Built prerequisite modules for file {0} in {1} seconds", FileName,
687 PrerequisiteModuleTimer.getTime());
690 Result->Macros = CapturedInfo.takeMacros();
691 Result->Marks = CapturedInfo.takeMarks();
692 Result->StatCache = StatCache;
693 Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
697 std::make_unique<TargetOptions>(std::move(CI.getTargetOpts()));
698 if (PreambleCallback) {
700 auto Ctx = CapturedInfo.takeLife();
703 Ctx->getFileManager().setVirtualFileSystem(
704 Result->StatCache->getConsumingFS(VFS));
707 Ctx->setStatCache(Result->StatCache);
709 PreambleCallback(std::move(*Ctx), Result->Pragmas);
714 elog(
"Could not build a preamble for file {0} version {1}: {2}", FileName,
715 Inputs.
Version, BuiltPreamble.getError().message());
716 for (
const Diag &D : PreambleDiagnostics.
take()) {
717 if (D.Severity < DiagnosticsEngine::Error)
720 elog(
" error: {0}", D.Message);
727 const CompilerInvocation &CI) {
728 auto ContentsBuffer =
729 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
730 auto Bounds = ComputePreambleBounds(CI.getLangOpts(), *ContentsBuffer, 0);
734 Preamble.Preamble.CanReuse(CI, *ContentsBuffer, Bounds, *VFS) &&
736 Preamble.RequiredModules->canReuse(CI, VFS));
740 for (
char C :
Text) {
755static std::vector<Diag>
patchDiags(llvm::ArrayRef<Diag> BaselineDiags,
756 const ScannedPreamble &BaselineScan,
757 const ScannedPreamble &ModifiedScan) {
758 std::vector<Diag> PatchedDiags;
759 if (BaselineDiags.empty())
761 DiagPatcher Patcher(BaselineScan.Lines, ModifiedScan.Lines);
762 for (
auto &D : BaselineDiags) {
763 if (
auto NewD = Patcher.translateDiag(D))
764 PatchedDiags.emplace_back(std::move(*NewD));
771 llvm::SmallString<128> PatchName;
772 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName),
774 return PatchName.str().str();
777PreamblePatch PreamblePatch::create(llvm::StringRef FileName,
778 const ParseInputs &Modified,
779 const PreambleData &Baseline,
780 PatchType PatchType) {
781 trace::Span Tracer(
"CreatePreamblePatch");
783 assert(llvm::sys::path::is_absolute(FileName) &&
"relative FileName!");
793 scanPreamble(Baseline.Preamble.getContents(), Modified.CompileCommand);
795 elog(
"Failed to scan baseline of {0}: {1}", FileName,
796 BaselineScan.takeError());
799 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand);
801 elog(
"Failed to scan modified contents of {0}: {1}", FileName,
802 ModifiedScan.takeError());
806 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
807 bool DirectivesChanged =
808 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
814 PP.Baseline = &Baseline;
816 PP.ModifiedBounds = ModifiedScan->Bounds;
818 llvm::raw_string_ostream Patch(PP.PatchContents);
820 Patch <<
"#line 0 \"";
829 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
832 for (
const auto &Inc : Baseline.Includes.MainFileIncludes)
833 ExistingIncludes[{Inc.Directive, Inc.Written}] = &Inc;
836 for (
const auto &Inc : BaselineScan->Includes)
837 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
839 for (
auto &Inc : ModifiedScan->Includes) {
840 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
843 if (It != ExistingIncludes.end()) {
847 auto &PatchedInc = PP.PreambleIncludes.emplace_back();
850 PatchedInc = *It->second;
851 PatchedInc.HashLine = Inc.HashLine;
852 PatchedInc.HashOffset = Inc.HashOffset;
859 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
860 Patch << llvm::formatv(
861 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
867 PP.PreambleIncludes = Baseline.Includes.MainFileIncludes;
870 if (DirectivesChanged) {
882 for (
const auto &TD : ModifiedScan->TextualDirectives) {
885 if (TD.Directive == tok::pp_define)
886 Patch <<
"#undef " << TD.MacroName <<
'\n';
887 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
888 Patch << TD.Text <<
'\n';
892 PP.PatchedDiags =
patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan);
893 PP.PatchedMarks = std::move(ModifiedScan->Marks);
894 PP.PatchedMacros = std::move(ModifiedScan->Macros);
895 dlog(
"Created preamble patch: {0}", Patch.str());
918 CI.getTargetOpts() = *Baseline->TargetOpts;
921 if (PatchContents.empty())
923 auto &PPOpts = CI.getPreprocessorOpts();
927 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
929 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
932 PPOpts.Includes.push_back(PatchFileName);
936 return PreambleIncludes;
942 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
943 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
949 if (PatchContents.empty())
950 return Baseline->Marks;
955 if (PatchContents.empty())
956 return Baseline->Macros;
957 return PatchedMacros;
961 const SourceManager &SM) {
963 return SM.getFileManager().getOptionalFileRef(PatchFilePath);
static cl::opt< bool > Fix("fix", desc(R"(
Apply suggested fixes. Without -fix-errors
clang-tidy will bail out if any compilation
errors were found.
)"), cl::init(false), cl::cat(ClangTidyCategory))
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
void collect(const CompilerInstance &CI)
std::unique_ptr< PrerequisiteModules > buildPrerequisiteModulesFor(PathRef File, const ThreadsafeFS &TFS)
static OptionalFileEntryRef getPatchEntry(llvm::StringRef MainFilePath, const SourceManager &SM)
Returns the FileEntry for the preamble patch of MainFilePath in SM, if any.
const MainFileMacros & mainFileMacros() const
llvm::ArrayRef< PragmaMark > marks() const
void apply(CompilerInvocation &CI) const
Adjusts CI (which compiles the modified inputs) to be used with the baseline preamble.
static PreamblePatch unmodified(const PreambleData &Preamble)
Preamble is used verbatim.
static PreamblePatch createMacroPatch(llvm::StringRef FileName, const ParseInputs &Modified, const PreambleData &Baseline)
static PreamblePatch createFullPatch(llvm::StringRef FileName, const ParseInputs &Modified, const PreambleData &Baseline)
Builds a patch that contains new PP directives introduced to the preamble section of Modified compare...
static constexpr llvm::StringLiteral HeaderName
std::vector< Inclusion > preambleIncludes() const
Returns include directives from the Modified preamble that were resolved using the Baseline preamble.
StoreDiags collects the diagnostics that can later be reported by clangd.
void setLevelAdjuster(LevelAdjuster Adjuster)
If set, this allows the client of this class to adjust the level of diagnostics, such as promoting wa...
std::vector< Diag > take(const clang::tidy::ClangTidyContext *Tidy=nullptr)
void setDiagCallback(DiagCallback CB)
Invokes a callback every time a diagnostics is completely formed.
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
Records an event whose duration is the lifetime of the Span object.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
bool isDiagnosticSuppressed(const clang::Diagnostic &Diag, const llvm::StringSet<> &Suppress, const LangOptions &LangOpts)
Determine whether a (non-clang-tidy) diagnostic is suppressed by config.
bool isLikelyForwardingFunction(const FunctionTemplateDecl *FT)
Heuristic that checks if FT is likely to be forwarding a parameter pack to another function (e....
@ Info
An information message.
static std::string getPatchName(llvm::StringRef FileName)
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
bool operator==(const Inclusion &LHS, const Inclusion &RHS)
std::unique_ptr< PPCallbacks > collectPragmaMarksCallback(const SourceManager &SM, std::vector< PragmaMark > &Out)
Collect all pragma marks from the main file.
bool isPreambleCompatible(const PreambleData &Preamble, const ParseInputs &Inputs, PathRef FileName, const CompilerInvocation &CI)
Returns true if Preamble is reusable for Inputs.
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation CI, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback, PreambleBuildStats *Stats)
Build a preamble for the new inputs unless an old one can be reused.
std::unique_ptr< CompilerInstance > prepareCompilerInstance(std::unique_ptr< clang::CompilerInvocation > CI, const PrecompiledPreamble *Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, DiagnosticConsumer &DiagsClient)
void log(const char *Fmt, Ts &&... Vals)
llvm::StringRef toSourceCode(const SourceManager &SM, SourceRange R)
Returns the source code covered by the source range.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
std::string Path
A typedef to represent a file path.
std::pair< size_t, size_t > offsetToClangLineColumn(llvm::StringRef Code, size_t Offset)
static std::vector< Diag > patchDiags(llvm::ArrayRef< Diag > BaselineDiags, const ScannedPreamble &BaselineScan, const ScannedPreamble &ModifiedScan)
void escapeBackslashAndQuotes(llvm::StringRef Text, llvm::raw_ostream &OS)
std::function< void(CapturedASTCtx ASTCtx, std::shared_ptr< const include_cleaner::PragmaIncludes >)> PreambleParsedCallback
void elog(const char *Fmt, Ts &&... Vals)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Settings that express user/project preferences and control clangd behavior.
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
struct clang::clangd::Config::@343034053122374337352226322054223376344037116252 Diagnostics
Controls warnings and errors when parsing code.
A top-level diagnostic that may have Notes and Fixes.
bool PreambleParseForwardingFunctions
Timings and statistics from the premble build.
double FileSystemTime
Time spent in filesystem operations during the build, in seconds.
double TotalBuildTime
Total wall time it took to build preamble, in seconds.
size_t SerializedSize
The serialized size of the preamble.
The parsed preamble and associated data.