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> scanPreamble(llvm::StringRef Contents,
324 const tooling::CompileCommand &Cmd,
325 bool SkipPreambleBuild) {
328 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
329 return new llvm::vfs::InMemoryFileSystem;
339 PI.CompileCommand = Cmd;
340 IgnoringDiagConsumer IgnoreDiags;
343 return error(
"failed to create compiler invocation");
344 CI->getDiagnosticOpts().IgnoreWarnings =
true;
345 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(PI.Contents);
351 auto PreambleContents = llvm::MemoryBuffer::getMemBufferCopy(
352 llvm::StringRef(PI.Contents).take_front(Bounds.Size));
354 std::move(CI),
nullptr, std::move(PreambleContents),
357 FS.view(std::nullopt), IgnoreDiags);
358 if (Clang->getFrontendOpts().Inputs.empty())
359 return error(
"compiler instance had no inputs");
361 Clang->getPreprocessorOpts().SingleFileParseMode =
true;
362 Clang->getPreprocessorOpts().UsePredefines =
false;
363 PreprocessOnlyAction Action;
364 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
365 return error(
"failed BeginSourceFile");
366 Preprocessor &PP = Clang->getPreprocessor();
367 const auto &SM = PP.getSourceManager();
373 std::make_unique<DirectiveCollector>(PP, SP.TextualDirectives));
375 PP.addPPCallbacks(std::make_unique<CollectMainFileMacros>(PP, SP.Macros));
376 if (llvm::Error Err = Action.Execute())
377 return std::move(Err);
378 Action.EndSourceFile();
379 SP.Includes = std::move(Includes.MainFileIncludes);
380 llvm::append_range(SP.Lines, llvm::split(Contents,
"\n"));
384const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
385 switch (IncludeDirective) {
386 case tok::pp_include:
390 case tok::pp_include_next:
391 return "include_next";
395 llvm_unreachable(
"not an include directive");
404 WallTimer() : TotalTime(std::chrono::steady_clock::duration::zero()) {}
406 void startTimer() { StartTime = std::chrono::steady_clock::now(); }
409 TotalTime += std::chrono::steady_clock::now() - StartTime;
412 double getTime() {
return std::chrono::duration<double>(TotalTime).count(); }
415 std::chrono::steady_clock::duration TotalTime;
416 std::chrono::steady_clock::time_point StartTime;
419class WallTimerRegion {
421 WallTimerRegion(WallTimer &T) : T(T) { T.startTimer(); }
422 ~WallTimerRegion() { T.stopTimer(); }
430class TimerFile :
public llvm::vfs::File {
432 TimerFile(WallTimer &Timer, std::unique_ptr<File> InnerFile)
433 : Timer(Timer), InnerFile(std::move(InnerFile)) {}
435 llvm::ErrorOr<llvm::vfs::Status> status()
override {
436 WallTimerRegion
T(Timer);
437 return InnerFile->status();
439 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
440 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
441 bool IsVolatile)
override {
442 WallTimerRegion
T(Timer);
443 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
446 std::error_code close()
override {
447 WallTimerRegion
T(Timer);
448 return InnerFile->close();
453 std::unique_ptr<llvm::vfs::File> InnerFile;
458class TimerFS :
public llvm::vfs::ProxyFileSystem {
460 TimerFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
461 : ProxyFileSystem(std::move(FS)) {}
463 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
464 openFileForRead(
const llvm::Twine &
Path)
override {
465 WallTimerRegion
T(Timer);
466 auto FileOr = getUnderlyingFS().openFileForRead(
Path);
469 return std::make_unique<TimerFile>(Timer, std::move(FileOr.get()));
472 llvm::ErrorOr<llvm::vfs::Status> status(
const llvm::Twine &
Path)
override {
473 WallTimerRegion
T(Timer);
474 return getUnderlyingFS().status(
Path);
477 double getTime() {
return Timer.getTime(); }
485 llvm::ArrayRef<llvm::StringRef> OldLines;
486 llvm::ArrayRef<llvm::StringRef> CurrentLines;
487 llvm::StringMap<llvm::SmallVector<int>> CurrentContentsToLine;
493 bool translateRange(Range &R) {
494 int OldStart = R.start.line;
495 int OldEnd = R.end.line;
496 assert(OldStart <= OldEnd);
498 size_t RangeLen = OldEnd - OldStart + 1;
499 auto RangeContents = OldLines.slice(OldStart).take_front(RangeLen);
501 if (RangeContents.size() < RangeLen)
504 std::optional<int> Closest;
505 for (
int AlternateLine : CurrentContentsToLine.lookup(RangeContents[0])) {
508 CurrentLines.slice(AlternateLine).take_front(RangeLen))
510 int Delta = AlternateLine - OldStart;
511 if (!Closest.has_value() || abs(Delta) < abs(*Closest))
515 if (!Closest.has_value())
517 R.start.line += *Closest;
518 R.end.line += *Closest;
524 bool translateNote(Note &N) {
525 if (!N.InsideMainFile)
527 if (translateRange(N.Range))
534 bool translateFix(
Fix &F) {
536 F.Edits, [
this](TextEdit &E) { return translateRange(E.range); });
540 DiagPatcher(llvm::ArrayRef<llvm::StringRef> OldLines,
541 llvm::ArrayRef<llvm::StringRef> CurrentLines) {
542 this->OldLines = OldLines;
543 this->CurrentLines = CurrentLines;
544 for (
int Line = 0, E = CurrentLines.size(); Line != E; ++Line) {
545 llvm::StringRef Contents = CurrentLines[Line];
546 CurrentContentsToLine[Contents].push_back(Line);
553 std::optional<Diag> translateDiag(
const Diag &D) {
554 Range NewRange =
D.Range;
556 if (
D.InsideMainFile && !translateRange(NewRange)) {
562 NewD.Range = NewRange;
565 llvm::erase_if(NewD.Notes, [
this](Note &N) { return !translateNote(N); });
566 llvm::erase_if(NewD.Fixes, [
this](
Fix &F) { return !translateFix(F); });
572std::shared_ptr<const PreambleData>
579 auto ContentsBuffer =
580 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
586 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
589 if (
auto Listener = M.astListeners())
590 ASTListeners.emplace_back(std::move(Listener));
596 for (
const auto &L : ASTListeners)
597 L->sawDiagnostic(D,
Diag);
600 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
601 CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
602 &PreambleDiagnostics,
604 PreambleDiagnostics.
setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
605 const clang::Diagnostic &
Info) {
606 switch (
Info.getID()) {
607 case diag::warn_no_newline_eof:
610 return Bounds.Size != ContentsBuffer->getBufferSize()
611 ? DiagnosticsEngine::Level::Ignored
619 assert(!CI.getFrontendOpts().SkipFunctionBodies);
620 CI.getFrontendOpts().SkipFunctionBodies =
true;
623 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
625 CppFilePreambleCallbacks CapturedInfo(
627 [&ASTListeners](CompilerInstance &CI) {
628 for (const auto &L : ASTListeners)
629 L->beforeExecute(CI);
631 llvm::SmallString<32> AbsFileName(FileName);
632 VFS->makeAbsolute(AbsFileName);
633 auto StatCache = std::make_shared<PreambleFileStatusCache>(AbsFileName);
634 auto StatCacheFS = StatCache->getProducingFS(VFS);
635 llvm::IntrusiveRefCntPtr<TimerFS> TimedFS(
new TimerFS(StatCacheFS));
637 WallTimer PreambleTimer;
638 PreambleTimer.startTimer();
639 auto BuiltPreamble = PrecompiledPreamble::Build(
640 CI, ContentsBuffer.get(), Bounds, PreambleDiagsEngine,
641 Stats ? TimedFS : StatCacheFS, std::make_shared<PCHContainerOperations>(),
642 StoreInMemory,
"", CapturedInfo);
644 PreambleTimer.stopTimer();
648 PreambleDiagsEngine->setClient(
new IgnoringDiagConsumer,
true);
651 PreambleDiagsEngine.reset();
655 CI.getFrontendOpts().SkipFunctionBodies =
false;
657 if (Stats !=
nullptr) {
660 Stats->
SerializedSize = BuiltPreamble ? BuiltPreamble->getSize() : 0;
664 log(
"Built preamble of size {0} for file {1} version {2} in {3} seconds",
665 BuiltPreamble->getSize(), FileName, Inputs.
Version,
666 PreambleTimer.getTime());
667 std::vector<Diag> Diags = PreambleDiagnostics.
take();
668 auto Result = std::make_shared<PreambleData>(std::move(*BuiltPreamble));
669 Result->Version = Inputs.
Version;
671 Result->Diags = std::move(Diags);
672 Result->Includes = CapturedInfo.takeIncludes();
673 Result->Pragmas = std::make_shared<const include_cleaner::PragmaIncludes>(
674 CapturedInfo.takePragmaIncludes());
677 WallTimer PrerequisiteModuleTimer;
678 PrerequisiteModuleTimer.startTimer();
679 Result->RequiredModules =
682 PrerequisiteModuleTimer.stopTimer();
684 log(
"Built prerequisite modules for file {0} in {1} seconds", FileName,
685 PrerequisiteModuleTimer.getTime());
688 Result->Macros = CapturedInfo.takeMacros();
689 Result->Marks = CapturedInfo.takeMarks();
690 Result->StatCache = std::move(StatCache);
691 Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
695 std::make_unique<TargetOptions>(std::move(CI.getTargetOpts()));
696 if (PreambleCallback) {
698 auto Ctx = CapturedInfo.takeLife();
701 Ctx->getFileManager().setVirtualFileSystem(
702 Result->StatCache->getConsumingFS(VFS));
705 Ctx->setStatCache(Result->StatCache);
707 PreambleCallback(std::move(*Ctx), Result->Pragmas);
712 elog(
"Could not build a preamble for file {0} version {1}: {2}", FileName,
713 Inputs.
Version, BuiltPreamble.getError().message());
714 for (
const Diag &D : PreambleDiagnostics.
take()) {
715 if (D.Severity < DiagnosticsEngine::Error)
718 elog(
" error: {0}", D.Message);
725 const CompilerInvocation &CI) {
726 auto ContentsBuffer =
727 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
733 Preamble.Preamble.CanReuse(CI, *ContentsBuffer, Bounds, *VFS) &&
735 Preamble.RequiredModules->canReuse(CI, VFS));
739 for (
char C :
Text) {
754static std::vector<Diag>
patchDiags(llvm::ArrayRef<Diag> BaselineDiags,
755 const ScannedPreamble &BaselineScan,
756 const ScannedPreamble &ModifiedScan) {
757 std::vector<Diag> PatchedDiags;
758 if (BaselineDiags.empty())
760 DiagPatcher Patcher(BaselineScan.Lines, ModifiedScan.Lines);
761 for (
auto &D : BaselineDiags) {
762 if (
auto NewD = Patcher.translateDiag(D))
763 PatchedDiags.emplace_back(std::move(*NewD));
770 llvm::SmallString<128> PatchName;
771 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName),
773 return PatchName.str().str();
776PreamblePatch PreamblePatch::create(llvm::StringRef FileName,
777 const ParseInputs &Modified,
778 const PreambleData &Baseline,
779 PatchType PatchType) {
780 trace::Span Tracer(
"CreatePreamblePatch");
782 assert(llvm::sys::path::is_absolute(FileName) &&
"relative FileName!");
792 scanPreamble(Baseline.Preamble.getContents(), Modified.CompileCommand,
793 Modified.Opts.SkipPreambleBuild);
795 elog(
"Failed to scan baseline of {0}: {1}", FileName,
796 BaselineScan.takeError());
799 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand,
800 Modified.Opts.SkipPreambleBuild);
802 elog(
"Failed to scan modified contents of {0}: {1}", FileName,
803 ModifiedScan.takeError());
807 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
808 bool DirectivesChanged =
809 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
815 PP.Baseline = &Baseline;
817 PP.ModifiedBounds = ModifiedScan->Bounds;
819 llvm::raw_string_ostream Patch(PP.PatchContents);
821 Patch <<
"#line 0 \"";
830 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
833 for (
const auto &Inc : Baseline.Includes.MainFileIncludes)
834 ExistingIncludes[{Inc.Directive, Inc.Written}] = &Inc;
837 for (
const auto &Inc : BaselineScan->Includes)
838 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
840 for (
auto &Inc : ModifiedScan->Includes) {
841 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
844 if (It != ExistingIncludes.end()) {
848 auto &PatchedInc = PP.PreambleIncludes.emplace_back();
851 PatchedInc = *It->second;
852 PatchedInc.HashLine = Inc.HashLine;
853 PatchedInc.HashOffset = Inc.HashOffset;
860 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
861 Patch << llvm::formatv(
862 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
868 PP.PreambleIncludes = Baseline.Includes.MainFileIncludes;
871 if (DirectivesChanged) {
883 for (
const auto &TD : ModifiedScan->TextualDirectives) {
886 if (TD.Directive == tok::pp_define)
887 Patch <<
"#undef " << TD.MacroName <<
'\n';
888 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
889 Patch << TD.Text <<
'\n';
893 PP.PatchedDiags =
patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan);
894 PP.PatchedMarks = std::move(ModifiedScan->Marks);
895 PP.PatchedMacros = std::move(ModifiedScan->Macros);
896 dlog(
"Created preamble patch: {0}", Patch.str());
919 CI.getTargetOpts() = *Baseline->TargetOpts;
922 if (PatchContents.empty())
924 auto &PPOpts = CI.getPreprocessorOpts();
928 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
930 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
933 PPOpts.Includes.push_back(PatchFileName);
937 return PreambleIncludes;
943 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
944 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
950 if (PatchContents.empty())
951 return Baseline->Marks;
956 if (PatchContents.empty())
957 return Baseline->Macros;
958 return PatchedMacros;
962 const SourceManager &SM) {
964 return SM.getFileManager().getOptionalFileRef(PatchFilePath);
968 const llvm::MemoryBufferRef &Buffer,
969 bool SkipPreambleBuild) {
970 return SkipPreambleBuild ? PreambleBounds(0,
false)
971 : ComputePreambleBounds(LangOpts, Buffer, 0);
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 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)
PreambleBounds computePreambleBounds(const LangOptions &LangOpts, const llvm::MemoryBufferRef &Buffer, bool SkipPreambleBuild)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
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.