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 {
238 tok::PPKeywordKind
Directive = tok::PPKeywordKind::pp_not_keyword;
242 bool operator==(
const TextualPPDirective &RHS)
const {
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,
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,
' ');
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;
335 std::vector<PragmaMark> Marks;
336 MainFileMacros Macros;
343llvm::Expected<ScannedPreamble>
344scanPreamble(llvm::StringRef Contents,
const tooling::CompileCommand &Cmd) {
345 class EmptyFS :
public ThreadsafeFS {
347 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
348 return new llvm::vfs::InMemoryFileSystem;
356 PI.Contents = Contents.str();
358 PI.CompileCommand = Cmd;
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),
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;
383 return error(
"failed BeginSourceFile");
384 Preprocessor &PP =
Clang->getPreprocessor();
385 const auto &SM = PP.getSourceManager();
386 IncludeStructure Includes;
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);
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 =
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);
616 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
617 CompilerInstance::createDiagnostics(&
CI.getDiagnosticOpts(),
618 &PreambleDiagnostics,
621 PreambleDiagnostics.
setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
622 const clang::Diagnostic &
Info) {
626 return DiagnosticsEngine::Ignored;
627 switch (
Info.getID()) {
628 case diag::warn_no_newline_eof:
629 case diag::warn_cxx98_compat_no_newline_eof:
630 case diag::ext_no_newline_eof:
633 return Bounds.Size != ContentsBuffer->getBufferSize()
634 ? DiagnosticsEngine::Level::Ignored
642 assert(!
CI.getFrontendOpts().SkipFunctionBodies);
643 CI.getFrontendOpts().SkipFunctionBodies =
true;
646 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
648 CppFilePreambleCallbacks CapturedInfo(
650 [&ASTListeners](CompilerInstance &
CI) {
651 for (const auto &L : ASTListeners)
652 L->beforeExecute(CI);
655 llvm::SmallString<32> AbsFileName(
FileName);
656 VFS->makeAbsolute(AbsFileName);
657 auto StatCache = std::make_shared<PreambleFileStatusCache>(AbsFileName);
658 auto StatCacheFS = StatCache->getProducingFS(VFS);
659 llvm::IntrusiveRefCntPtr<TimerFS> TimedFS(
new TimerFS(StatCacheFS));
661 WallTimer PreambleTimer;
662 PreambleTimer.startTimer();
663 auto BuiltPreamble = PrecompiledPreamble::Build(
664 CI, ContentsBuffer.get(),
Bounds, *PreambleDiagsEngine,
665 Stats ? TimedFS : StatCacheFS, std::make_shared<PCHContainerOperations>(),
666 StoreInMemory,
"", CapturedInfo);
667 PreambleTimer.stopTimer();
671 PreambleDiagsEngine->setClient(
new IgnoringDiagConsumer,
true);
674 PreambleDiagsEngine.reset();
675 CI.DiagnosticOpts.reset();
679 CI.getFrontendOpts().SkipFunctionBodies =
false;
681 if (Stats !=
nullptr) {
684 Stats->
SerializedSize = BuiltPreamble ? BuiltPreamble->getSize() : 0;
688 log(
"Built preamble of size {0} for file {1} version {2} in {3} seconds",
690 PreambleTimer.getTime());
691 std::vector<Diag> Diags = PreambleDiagnostics.
take();
692 auto Result = std::make_shared<PreambleData>(std::move(*BuiltPreamble));
693 Result->Version = Inputs.
Version;
695 Result->Diags = std::move(Diags);
696 Result->Includes = CapturedInfo.takeIncludes();
697 Result->Pragmas = std::make_shared<const include_cleaner::PragmaIncludes>(
698 CapturedInfo.takePragmaIncludes());
699 Result->Macros = CapturedInfo.takeMacros();
700 Result->Marks = CapturedInfo.takeMarks();
701 Result->StatCache = StatCache;
702 Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
703 Result->TargetOpts =
CI.TargetOpts;
704 if (PreambleCallback) {
706 auto Ctx = CapturedInfo.takeLife();
709 Ctx->getFileManager().setVirtualFileSystem(
710 Result->StatCache->getConsumingFS(VFS));
713 Ctx->setStatCache(Result->StatCache);
715 PreambleCallback(std::move(*Ctx), Result->Pragmas);
720 elog(
"Could not build a preamble for file {0} version {1}: {2}",
FileName,
721 Inputs.
Version, BuiltPreamble.getError().message());
722 for (
const Diag &D : PreambleDiagnostics.
take()) {
723 if (D.Severity < DiagnosticsEngine::Error)
726 elog(
" error: {0}", D.Message);
733 const CompilerInvocation &
CI) {
734 auto ContentsBuffer =
736 auto Bounds = ComputePreambleBounds(
CI.getLangOpts(), *ContentsBuffer, 0);
744 for (
char C :
Text) {
759static std::vector<Diag>
patchDiags(llvm::ArrayRef<Diag> BaselineDiags,
760 const ScannedPreamble &BaselineScan,
761 const ScannedPreamble &ModifiedScan) {
762 std::vector<Diag> PatchedDiags;
763 if (BaselineDiags.empty())
765 DiagPatcher Patcher(BaselineScan.Lines, ModifiedScan.Lines);
766 for (
auto &D : BaselineDiags) {
767 if (
auto NewD = Patcher.translateDiag(D))
768 PatchedDiags.emplace_back(std::move(*NewD));
775 llvm::SmallString<128> PatchName;
776 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(
FileName),
778 return PatchName.str().str();
781PreamblePatch PreamblePatch::create(llvm::StringRef
FileName,
782 const ParseInputs &Modified,
783 const PreambleData &Baseline,
784 PatchType PatchType) {
785 trace::Span Tracer(
"CreatePreamblePatch");
787 assert(llvm::sys::path::is_absolute(
FileName) &&
"relative FileName!");
797 scanPreamble(Baseline.Preamble.getContents(), Modified.CompileCommand);
799 elog(
"Failed to scan baseline of {0}: {1}",
FileName,
800 BaselineScan.takeError());
803 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand);
805 elog(
"Failed to scan modified contents of {0}: {1}",
FileName,
806 ModifiedScan.takeError());
810 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
811 bool DirectivesChanged =
812 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
818 PP.Baseline = &Baseline;
820 PP.ModifiedBounds = ModifiedScan->Bounds;
822 llvm::raw_string_ostream
Patch(PP.PatchContents);
824 Patch <<
"#line 0 \"";
833 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
836 for (
const auto &Inc : Baseline.Includes.MainFileIncludes)
837 ExistingIncludes[{Inc.Directive, Inc.Written}] = &Inc;
840 for (
const auto &Inc : BaselineScan->Includes)
841 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
843 for (
auto &Inc : ModifiedScan->Includes) {
844 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
847 if (It != ExistingIncludes.end()) {
851 auto &PatchedInc = PP.PreambleIncludes.emplace_back();
854 PatchedInc = *It->second;
855 PatchedInc.HashLine = Inc.HashLine;
856 PatchedInc.HashOffset = Inc.HashOffset;
863 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
864 Patch << llvm::formatv(
865 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
871 PP.PreambleIncludes = Baseline.Includes.MainFileIncludes;
874 if (DirectivesChanged) {
886 for (
const auto &TD : ModifiedScan->TextualDirectives) {
889 if (TD.Directive == tok::pp_define)
890 Patch <<
"#undef " << TD.MacroName <<
'\n';
891 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
892 Patch << TD.Text <<
'\n';
896 PP.PatchedDiags =
patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan);
897 PP.PatchedMarks = std::move(ModifiedScan->Marks);
898 PP.PatchedMacros = std::move(ModifiedScan->Macros);
899 dlog(
"Created preamble patch: {0}",
Patch.str());
921 CI.TargetOpts = Baseline->TargetOpts;
924 if (PatchContents.empty())
926 auto &PPOpts =
CI.getPreprocessorOpts();
930 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
932 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
935 PPOpts.Includes.push_back(PatchFileName);
939 return PreambleIncludes;
945 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
946 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
952 if (PatchContents.empty())
953 return Baseline->Marks;
958 if (PatchContents.empty())
959 return Baseline->Macros;
960 return PatchedMacros;
964 const SourceManager &SM) {
966 return SM.getFileManager().getOptionalFileRef(PatchFilePath);
const FunctionDecl * Decl
llvm::SmallString< 256U > Name
const std::optional< PreamblePatch > Patch
CharSourceRange Range
SourceRange for the file name.
const MacroDirective * Directive
const google::protobuf::Message & M
std::unique_ptr< CompilerInvocation > CI
llvm::raw_string_ostream OS
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
std::vector< Inclusion > MainFileIncludes
void collect(const CompilerInstance &CI)
Stores information required to parse a TU using a (possibly stale) Baseline preamble.
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.
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.
std::function< void(CapturedASTCtx ASTCtx, std::shared_ptr< const include_cleaner::PragmaIncludes >)> PreambleParsedCallback
@ Info
An information message.
static std::string getPatchName(llvm::StringRef FileName)
std::string Path
A typedef to represent a file path.
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)
bool isBuiltinDiagnosticSuppressed(unsigned ID, const llvm::StringSet<> &Suppress, const LangOptions &LangOpts)
Determine whether a (non-clang-tidy) diagnostic is suppressed by config.
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.
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)
llvm::StringRef PathRef
A typedef to represent a ref to file path.
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::@4 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.