19#include "clang-include-cleaner/Record.h"
24#include "clang/AST/DeclTemplate.h"
25#include "clang/AST/Type.h"
26#include "clang/Basic/Diagnostic.h"
27#include "clang/Basic/DiagnosticLex.h"
28#include "clang/Basic/DiagnosticOptions.h"
29#include "clang/Basic/LangOptions.h"
30#include "clang/Basic/SourceLocation.h"
31#include "clang/Basic/SourceManager.h"
32#include "clang/Basic/TargetInfo.h"
33#include "clang/Basic/TokenKinds.h"
34#include "clang/Frontend/CompilerInstance.h"
35#include "clang/Frontend/CompilerInvocation.h"
36#include "clang/Frontend/FrontendActions.h"
37#include "clang/Frontend/PrecompiledPreamble.h"
38#include "clang/Lex/HeaderSearch.h"
39#include "clang/Lex/Lexer.h"
40#include "clang/Lex/PPCallbacks.h"
41#include "clang/Lex/Preprocessor.h"
42#include "clang/Lex/PreprocessorOptions.h"
43#include "clang/Serialization/ASTReader.h"
44#include "clang/Tooling/CompilationDatabase.h"
45#include "llvm/ADT/ArrayRef.h"
46#include "llvm/ADT/DenseMap.h"
47#include "llvm/ADT/IntrusiveRefCntPtr.h"
48#include "llvm/ADT/STLExtras.h"
49#include "llvm/ADT/SmallString.h"
50#include "llvm/ADT/SmallVector.h"
51#include "llvm/ADT/StringExtras.h"
52#include "llvm/ADT/StringMap.h"
53#include "llvm/ADT/StringRef.h"
54#include "llvm/Support/Casting.h"
55#include "llvm/Support/Error.h"
56#include "llvm/Support/ErrorHandling.h"
57#include "llvm/Support/ErrorOr.h"
58#include "llvm/Support/FormatVariadic.h"
59#include "llvm/Support/MemoryBuffer.h"
60#include "llvm/Support/Path.h"
61#include "llvm/Support/VirtualFileSystem.h"
62#include "llvm/Support/raw_ostream.h"
72#include <system_error>
81bool compileCommandsAreEqual(
const tooling::CompileCommand &LHS,
82 const tooling::CompileCommand &RHS) {
84 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
85 llvm::ArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
88class CppFilePreambleCallbacks :
public PreambleCallbacks {
90 CppFilePreambleCallbacks(
91 PathRef File, PreambleBuildStats *Stats,
bool ParseForwardingFunctions,
92 std::function<
void(CompilerInstance &)> BeforeExecuteCallback)
93 : File(File), Stats(Stats),
94 ParseForwardingFunctions(ParseForwardingFunctions),
95 BeforeExecuteCallback(std::move(BeforeExecuteCallback)) {}
97 IncludeStructure takeIncludes() {
return std::move(Includes); }
99 MainFileMacros takeMacros() {
return std::move(Macros); }
101 std::vector<PragmaMark> takeMarks() {
return std::move(Marks); }
103 include_cleaner::PragmaIncludes takePragmaIncludes() {
104 return std::move(Pragmas);
107 std::optional<CapturedASTCtx> takeLife() {
return std::move(CapturedCtx); }
109 bool isMainFileIncludeGuarded()
const {
return IsMainFileIncludeGuarded; }
111 void AfterExecute(CompilerInstance &CI)
override {
116 if (CI.getASTReader()) {
117 CI.getASTReader()->setDeserializationListener(
nullptr);
119 CI.getASTReader()->StartTranslationUnit(
nullptr);
121 CI.getASTContext().setASTMutationListener(
nullptr);
122 CapturedCtx.emplace(CI);
124 const SourceManager &SM = CI.getSourceManager();
125 OptionalFileEntryRef MainFE = SM.getFileEntryRefForID(SM.getMainFileID());
126 IsMainFileIncludeGuarded =
127 CI.getPreprocessor().getHeaderSearchInfo().isFileMultipleIncludeGuarded(
131 const ASTContext &
AST = CI.getASTContext();
132 Stats->BuildSize =
AST.getASTAllocatedMemory();
133 Stats->BuildSize +=
AST.getSideTableAllocatedMemory();
134 Stats->BuildSize +=
AST.Idents.getAllocator().getTotalMemory();
135 Stats->BuildSize +=
AST.Selectors.getTotalMemory();
137 Stats->BuildSize +=
AST.getSourceManager().getContentCacheSize();
138 Stats->BuildSize +=
AST.getSourceManager().getDataStructureSizes();
140 AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
142 const Preprocessor &PP = CI.getPreprocessor();
143 Stats->BuildSize += PP.getTotalMemory();
144 if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
145 Stats->BuildSize += PRec->getTotalMemory();
146 Stats->BuildSize += PP.getHeaderSearchInfo().getTotalMemory();
150 void BeforeExecute(CompilerInstance &CI)
override {
151 LangOpts = &CI.getLangOpts();
152 SourceMgr = &CI.getSourceManager();
153 PP = &CI.getPreprocessor();
154 Includes.collect(CI);
156 if (BeforeExecuteCallback)
157 BeforeExecuteCallback(CI);
160 std::unique_ptr<PPCallbacks> createPPCallbacks()
override {
161 assert(SourceMgr && LangOpts && PP &&
162 "SourceMgr, LangOpts and PP must be set at this point");
164 return std::make_unique<PPChainedCallbacks>(
165 std::make_unique<CollectMainFileMacros>(*PP, Macros),
169 static bool isLikelyForwardingFunction(FunctionTemplateDecl *FT) {
170 const auto *FD = FT->getTemplatedDecl();
171 const auto NumParams = FD->getNumParams();
174 const auto *LastParam = FD->getParamDecl(NumParams - 1);
175 if (
const auto *PET = dyn_cast<PackExpansionType>(LastParam->getType())) {
177 const auto BaseType = PET->getPattern().getNonReferenceType();
178 if (
const auto *TTPT =
179 dyn_cast<TemplateTypeParmType>(BaseType.getTypePtr())) {
181 if (FT->getTemplateParameters()->getDepth() == TTPT->getDepth()) {
190 bool shouldSkipFunctionBody(Decl *D)
override {
198 if (
auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
199 if (ParseForwardingFunctions) {
201 if (isLikelyForwardingFunction(FT))
206 if (
const auto *II = FT->getDeclName().getAsIdentifierInfo()) {
207 if (II->isStr(
"make_unique") && FT->isInStdNamespace())
217 IncludeStructure Includes;
218 include_cleaner::PragmaIncludes Pragmas;
219 MainFileMacros Macros;
220 std::vector<PragmaMark> Marks;
221 bool IsMainFileIncludeGuarded =
false;
222 const clang::LangOptions *LangOpts =
nullptr;
223 const SourceManager *SourceMgr =
nullptr;
224 const Preprocessor *PP =
nullptr;
225 PreambleBuildStats *Stats;
226 bool ParseForwardingFunctions;
227 std::function<void(CompilerInstance &)> BeforeExecuteCallback;
228 std::optional<CapturedASTCtx> CapturedCtx;
233struct TextualPPDirective {
234 unsigned DirectiveLine;
238 tok::PPKeywordKind Directive = tok::PPKeywordKind::pp_not_keyword;
240 std::string MacroName;
242 bool operator==(
const TextualPPDirective &RHS)
const {
243 return std::tie(DirectiveLine, Offset, Text) ==
244 std::tie(RHS.DirectiveLine, RHS.Offset, RHS.Text);
251std::string spellDirective(llvm::StringRef Prefix,
252 CharSourceRange DirectiveRange,
253 const LangOptions &LangOpts,
const SourceManager &SM,
254 unsigned &DirectiveLine,
unsigned &Offset) {
255 std::string SpelledDirective;
256 llvm::raw_string_ostream OS(SpelledDirective);
260 DirectiveRange = SM.getExpansionRange(DirectiveRange);
261 if (DirectiveRange.isTokenRange()) {
262 DirectiveRange.setEnd(
263 Lexer::getLocForEndOfToken(DirectiveRange.getEnd(), 0, SM, LangOpts));
266 auto DecompLoc = SM.getDecomposedLoc(DirectiveRange.getBegin());
267 DirectiveLine = SM.getLineNumber(DecompLoc.first, DecompLoc.second);
268 Offset = DecompLoc.second;
269 auto TargetColumn = SM.getColumnNumber(DecompLoc.first, DecompLoc.second) - 1;
273 if (Prefix.size() <= TargetColumn) {
277 OS << std::string(TargetColumn - Prefix.size(),
' ');
283 OS <<
"\\\n" << std::string(TargetColumn,
' ');
293struct DirectiveCollector :
public PPCallbacks {
294 DirectiveCollector(
const Preprocessor &PP,
295 std::vector<TextualPPDirective> &TextualDirectives)
296 : LangOpts(PP.getLangOpts()), SM(PP.getSourceManager()),
297 TextualDirectives(TextualDirectives) {}
299 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
300 SrcMgr::CharacteristicKind FileType,
301 FileID PrevFID)
override {
302 InMainFile = SM.isWrittenInMainFile(Loc);
305 void MacroDefined(
const Token &MacroNameTok,
306 const MacroDirective *MD)
override {
309 TextualDirectives.emplace_back();
310 TextualPPDirective &TD = TextualDirectives.back();
311 TD.Directive = tok::pp_define;
312 TD.MacroName = MacroNameTok.getIdentifierInfo()->getName().str();
314 const auto *MI = MD->getMacroInfo();
316 spellDirective(
"#define ",
317 CharSourceRange::getTokenRange(
318 MI->getDefinitionLoc(), MI->getDefinitionEndLoc()),
319 LangOpts, SM, TD.DirectiveLine, TD.Offset);
323 bool InMainFile =
true;
324 const LangOptions &LangOpts;
325 const SourceManager &SM;
326 std::vector<TextualPPDirective> &TextualDirectives;
329struct ScannedPreamble {
330 std::vector<Inclusion> Includes;
331 std::vector<TextualPPDirective> TextualDirectives;
333 std::vector<llvm::StringRef> Lines;
334 PreambleBounds Bounds = {0,
false};
335 std::vector<PragmaMark> Marks;
336 MainFileMacros Macros;
343llvm::Expected<ScannedPreamble>
344scanPreamble(llvm::StringRef Contents,
const tooling::CompileCommand &Cmd) {
347 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
348 return new llvm::vfs::InMemoryFileSystem;
358 PI.CompileCommand = Cmd;
359 IgnoringDiagConsumer IgnoreDiags;
362 return error(
"failed to create compiler invocation");
363 CI->getDiagnosticOpts().IgnoreWarnings =
true;
364 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(PI.Contents);
368 auto Bounds = ComputePreambleBounds(CI->getLangOpts(), *ContentsBuffer, 0);
369 auto PreambleContents = llvm::MemoryBuffer::getMemBufferCopy(
370 llvm::StringRef(PI.Contents).take_front(Bounds.Size));
372 std::move(CI),
nullptr, std::move(PreambleContents),
375 FS.view(std::nullopt), IgnoreDiags);
376 if (Clang->getFrontendOpts().Inputs.empty())
377 return error(
"compiler instance had no inputs");
379 Clang->getPreprocessorOpts().SingleFileParseMode =
true;
380 Clang->getPreprocessorOpts().UsePredefines =
false;
381 PreprocessOnlyAction Action;
382 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
383 return error(
"failed BeginSourceFile");
384 Preprocessor &PP = Clang->getPreprocessor();
385 const auto &SM = PP.getSourceManager();
391 std::make_unique<DirectiveCollector>(PP, SP.TextualDirectives));
393 PP.addPPCallbacks(std::make_unique<CollectMainFileMacros>(PP, SP.Macros));
394 if (llvm::Error Err = Action.Execute())
395 return std::move(Err);
396 Action.EndSourceFile();
397 SP.Includes = std::move(Includes.MainFileIncludes);
398 llvm::append_range(SP.Lines, llvm::split(Contents,
"\n"));
402const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
403 switch (IncludeDirective) {
404 case tok::pp_include:
408 case tok::pp_include_next:
409 return "include_next";
413 llvm_unreachable(
"not an include directive");
422 WallTimer() : TotalTime(std::chrono::steady_clock::duration::zero()) {}
424 void startTimer() { StartTime = std::chrono::steady_clock::now(); }
427 TotalTime += std::chrono::steady_clock::now() - StartTime;
430 double getTime() {
return std::chrono::duration<double>(TotalTime).count(); }
433 std::chrono::steady_clock::duration TotalTime;
434 std::chrono::steady_clock::time_point StartTime;
437class WallTimerRegion {
439 WallTimerRegion(WallTimer &T) : T(T) { T.startTimer(); }
440 ~WallTimerRegion() { T.stopTimer(); }
448class TimerFile :
public llvm::vfs::File {
450 TimerFile(WallTimer &Timer, std::unique_ptr<File> InnerFile)
451 : Timer(Timer), InnerFile(std::move(InnerFile)) {}
453 llvm::ErrorOr<llvm::vfs::Status> status()
override {
454 WallTimerRegion
T(Timer);
455 return InnerFile->status();
457 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
458 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
459 bool IsVolatile)
override {
460 WallTimerRegion
T(Timer);
461 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
464 std::error_code close()
override {
465 WallTimerRegion
T(Timer);
466 return InnerFile->close();
471 std::unique_ptr<llvm::vfs::File> InnerFile;
476class TimerFS :
public llvm::vfs::ProxyFileSystem {
478 TimerFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
479 : ProxyFileSystem(std::move(FS)) {}
481 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
482 openFileForRead(
const llvm::Twine &
Path)
override {
483 WallTimerRegion
T(Timer);
484 auto FileOr = getUnderlyingFS().openFileForRead(
Path);
487 return std::make_unique<TimerFile>(Timer, std::move(FileOr.get()));
490 llvm::ErrorOr<llvm::vfs::Status> status(
const llvm::Twine &
Path)
override {
491 WallTimerRegion
T(Timer);
492 return getUnderlyingFS().status(
Path);
495 double getTime() {
return Timer.getTime(); }
503 llvm::ArrayRef<llvm::StringRef> OldLines;
504 llvm::ArrayRef<llvm::StringRef> CurrentLines;
505 llvm::StringMap<llvm::SmallVector<int>> CurrentContentsToLine;
511 bool translateRange(Range &R) {
512 int OldStart = R.start.line;
513 int OldEnd = R.end.line;
514 assert(OldStart <= OldEnd);
516 size_t RangeLen = OldEnd - OldStart + 1;
517 auto RangeContents = OldLines.slice(OldStart).take_front(RangeLen);
519 if (RangeContents.size() < RangeLen)
522 std::optional<int> Closest;
523 for (
int AlternateLine : CurrentContentsToLine.lookup(RangeContents[0])) {
526 CurrentLines.slice(AlternateLine).take_front(RangeLen))
528 int Delta = AlternateLine - OldStart;
529 if (!Closest.has_value() || abs(Delta) < abs(*Closest))
533 if (!Closest.has_value())
535 R.start.line += *Closest;
536 R.end.line += *Closest;
542 bool translateNote(Note &N) {
543 if (!N.InsideMainFile)
545 if (translateRange(N.Range))
552 bool translateFix(
Fix &F) {
554 F.Edits, [
this](TextEdit &E) { return translateRange(E.range); });
558 DiagPatcher(llvm::ArrayRef<llvm::StringRef> OldLines,
559 llvm::ArrayRef<llvm::StringRef> CurrentLines) {
560 this->OldLines = OldLines;
561 this->CurrentLines = CurrentLines;
562 for (
int Line = 0, E = CurrentLines.size(); Line != E; ++Line) {
563 llvm::StringRef Contents = CurrentLines[Line];
564 CurrentContentsToLine[Contents].push_back(Line);
571 std::optional<Diag> translateDiag(
const Diag &D) {
572 Range NewRange =
D.Range;
574 if (
D.InsideMainFile && !translateRange(NewRange)) {
580 NewD.Range = NewRange;
583 llvm::erase_if(NewD.Notes, [
this](Note &N) { return !translateNote(N); });
584 llvm::erase_if(NewD.Fixes, [
this](
Fix &F) { return !translateFix(F); });
590std::shared_ptr<const PreambleData>
597 auto ContentsBuffer =
598 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
599 auto Bounds = ComputePreambleBounds(CI.getLangOpts(), *ContentsBuffer, 0);
603 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
606 if (
auto Listener = M.astListeners())
607 ASTListeners.emplace_back(std::move(Listener));
613 for (
const auto &L : ASTListeners)
614 L->sawDiagnostic(D,
Diag);
617 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
618 CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
619 &PreambleDiagnostics,
622 PreambleDiagnostics.
setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
623 const clang::Diagnostic &
Info) {
627 return DiagnosticsEngine::Ignored;
628 switch (
Info.getID()) {
629 case diag::warn_no_newline_eof:
632 return Bounds.Size != ContentsBuffer->getBufferSize()
633 ? DiagnosticsEngine::Level::Ignored
641 assert(!CI.getFrontendOpts().SkipFunctionBodies);
642 CI.getFrontendOpts().SkipFunctionBodies =
true;
645 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
647 CppFilePreambleCallbacks CapturedInfo(
649 [&ASTListeners](CompilerInstance &CI) {
650 for (const auto &L : ASTListeners)
651 L->beforeExecute(CI);
653 llvm::SmallString<32> AbsFileName(FileName);
654 VFS->makeAbsolute(AbsFileName);
655 auto StatCache = std::make_shared<PreambleFileStatusCache>(AbsFileName);
656 auto StatCacheFS = StatCache->getProducingFS(VFS);
657 llvm::IntrusiveRefCntPtr<TimerFS> TimedFS(
new TimerFS(StatCacheFS));
659 WallTimer PreambleTimer;
660 PreambleTimer.startTimer();
661 auto BuiltPreamble = PrecompiledPreamble::Build(
662 CI, ContentsBuffer.get(), Bounds, PreambleDiagsEngine,
663 Stats ? TimedFS : StatCacheFS, std::make_shared<PCHContainerOperations>(),
664 StoreInMemory,
"", CapturedInfo);
666 PreambleTimer.stopTimer();
670 PreambleDiagsEngine->setClient(
new IgnoringDiagConsumer,
true);
673 PreambleDiagsEngine.reset();
677 CI.getFrontendOpts().SkipFunctionBodies =
false;
679 if (Stats !=
nullptr) {
682 Stats->
SerializedSize = BuiltPreamble ? BuiltPreamble->getSize() : 0;
686 log(
"Built preamble of size {0} for file {1} version {2} in {3} seconds",
687 BuiltPreamble->getSize(), FileName, Inputs.
Version,
688 PreambleTimer.getTime());
689 std::vector<Diag> Diags = PreambleDiagnostics.
take();
690 auto Result = std::make_shared<PreambleData>(std::move(*BuiltPreamble));
691 Result->Version = Inputs.
Version;
693 Result->Diags = std::move(Diags);
694 Result->Includes = CapturedInfo.takeIncludes();
695 Result->Pragmas = std::make_shared<const include_cleaner::PragmaIncludes>(
696 CapturedInfo.takePragmaIncludes());
699 WallTimer PrerequisiteModuleTimer;
700 PrerequisiteModuleTimer.startTimer();
701 Result->RequiredModules =
704 PrerequisiteModuleTimer.stopTimer();
706 log(
"Built prerequisite modules for file {0} in {1} seconds", FileName,
707 PrerequisiteModuleTimer.getTime());
710 Result->Macros = CapturedInfo.takeMacros();
711 Result->Marks = CapturedInfo.takeMarks();
712 Result->StatCache = StatCache;
713 Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
717 std::make_unique<TargetOptions>(std::move(CI.getTargetOpts()));
718 if (PreambleCallback) {
720 auto Ctx = CapturedInfo.takeLife();
723 Ctx->getFileManager().setVirtualFileSystem(
724 Result->StatCache->getConsumingFS(VFS));
727 Ctx->setStatCache(Result->StatCache);
729 PreambleCallback(std::move(*Ctx), Result->Pragmas);
734 elog(
"Could not build a preamble for file {0} version {1}: {2}", FileName,
735 Inputs.
Version, BuiltPreamble.getError().message());
736 for (
const Diag &D : PreambleDiagnostics.
take()) {
737 if (D.Severity < DiagnosticsEngine::Error)
740 elog(
" error: {0}", D.Message);
747 const CompilerInvocation &CI) {
748 auto ContentsBuffer =
749 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
750 auto Bounds = ComputePreambleBounds(CI.getLangOpts(), *ContentsBuffer, 0);
754 Preamble.Preamble.CanReuse(CI, *ContentsBuffer, Bounds, *VFS) &&
756 Preamble.RequiredModules->canReuse(CI, VFS));
760 for (
char C :
Text) {
775static std::vector<Diag>
patchDiags(llvm::ArrayRef<Diag> BaselineDiags,
776 const ScannedPreamble &BaselineScan,
777 const ScannedPreamble &ModifiedScan) {
778 std::vector<Diag> PatchedDiags;
779 if (BaselineDiags.empty())
781 DiagPatcher Patcher(BaselineScan.Lines, ModifiedScan.Lines);
782 for (
auto &D : BaselineDiags) {
783 if (
auto NewD = Patcher.translateDiag(D))
784 PatchedDiags.emplace_back(std::move(*NewD));
791 llvm::SmallString<128> PatchName;
792 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName),
794 return PatchName.str().str();
797PreamblePatch PreamblePatch::create(llvm::StringRef FileName,
798 const ParseInputs &Modified,
799 const PreambleData &Baseline,
800 PatchType PatchType) {
801 trace::Span Tracer(
"CreatePreamblePatch");
803 assert(llvm::sys::path::is_absolute(FileName) &&
"relative FileName!");
813 scanPreamble(Baseline.Preamble.getContents(), Modified.CompileCommand);
815 elog(
"Failed to scan baseline of {0}: {1}", FileName,
816 BaselineScan.takeError());
819 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand);
821 elog(
"Failed to scan modified contents of {0}: {1}", FileName,
822 ModifiedScan.takeError());
826 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
827 bool DirectivesChanged =
828 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
834 PP.Baseline = &Baseline;
836 PP.ModifiedBounds = ModifiedScan->Bounds;
838 llvm::raw_string_ostream Patch(PP.PatchContents);
840 Patch <<
"#line 0 \"";
849 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
852 for (
const auto &Inc : Baseline.Includes.MainFileIncludes)
853 ExistingIncludes[{Inc.Directive, Inc.Written}] = &Inc;
856 for (
const auto &Inc : BaselineScan->Includes)
857 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
859 for (
auto &Inc : ModifiedScan->Includes) {
860 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
863 if (It != ExistingIncludes.end()) {
867 auto &PatchedInc = PP.PreambleIncludes.emplace_back();
870 PatchedInc = *It->second;
871 PatchedInc.HashLine = Inc.HashLine;
872 PatchedInc.HashOffset = Inc.HashOffset;
879 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
880 Patch << llvm::formatv(
881 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
887 PP.PreambleIncludes = Baseline.Includes.MainFileIncludes;
890 if (DirectivesChanged) {
902 for (
const auto &TD : ModifiedScan->TextualDirectives) {
905 if (TD.Directive == tok::pp_define)
906 Patch <<
"#undef " << TD.MacroName <<
'\n';
907 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
908 Patch << TD.Text <<
'\n';
912 PP.PatchedDiags =
patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan);
913 PP.PatchedMarks = std::move(ModifiedScan->Marks);
914 PP.PatchedMacros = std::move(ModifiedScan->Macros);
915 dlog(
"Created preamble patch: {0}", Patch.str());
938 CI.getTargetOpts() = *Baseline->TargetOpts;
941 if (PatchContents.empty())
943 auto &PPOpts = CI.getPreprocessorOpts();
947 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
949 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
952 PPOpts.Includes.push_back(PatchFileName);
956 return PreambleIncludes;
962 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
963 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
969 if (PatchContents.empty())
970 return Baseline->Marks;
975 if (PatchContents.empty())
976 return Baseline->Macros;
977 return PatchedMacros;
981 const SourceManager &SM) {
983 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.
@ 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::@224206046260313204212274150166346126315121140114 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.