17#include "clang-include-cleaner/Record.h"
23#include "clang/AST/DeclTemplate.h"
24#include "clang/Basic/Diagnostic.h"
25#include "clang/Basic/DiagnosticLex.h"
26#include "clang/Basic/LangOptions.h"
27#include "clang/Basic/SourceLocation.h"
28#include "clang/Basic/SourceManager.h"
29#include "clang/Basic/TokenKinds.h"
30#include "clang/Frontend/CompilerInvocation.h"
31#include "clang/Frontend/FrontendActions.h"
32#include "clang/Frontend/PrecompiledPreamble.h"
33#include "clang/Lex/HeaderSearch.h"
34#include "clang/Lex/Lexer.h"
35#include "clang/Lex/PPCallbacks.h"
36#include "clang/Lex/Preprocessor.h"
37#include "clang/Lex/PreprocessorOptions.h"
38#include "clang/Tooling/CompilationDatabase.h"
39#include "llvm/ADT/ArrayRef.h"
40#include "llvm/ADT/DenseMap.h"
41#include "llvm/ADT/IntrusiveRefCntPtr.h"
42#include "llvm/ADT/STLExtras.h"
43#include "llvm/ADT/SmallString.h"
44#include "llvm/ADT/SmallVector.h"
45#include "llvm/ADT/StringExtras.h"
46#include "llvm/ADT/StringMap.h"
47#include "llvm/ADT/StringRef.h"
48#include "llvm/Support/Casting.h"
49#include "llvm/Support/Error.h"
50#include "llvm/Support/ErrorHandling.h"
51#include "llvm/Support/FormatVariadic.h"
52#include "llvm/Support/MemoryBuffer.h"
53#include "llvm/Support/Path.h"
54#include "llvm/Support/VirtualFileSystem.h"
55#include "llvm/Support/raw_ostream.h"
61#include <system_error>
70bool compileCommandsAreEqual(
const tooling::CompileCommand &LHS,
71 const tooling::CompileCommand &RHS) {
73 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
74 llvm::ArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
77class CppFilePreambleCallbacks :
public PreambleCallbacks {
79 CppFilePreambleCallbacks(
81 PreambleBuildStats *Stats,
bool ParseForwardingFunctions,
82 std::function<
void(CompilerInstance &)> BeforeExecuteCallback)
83 : File(File), ParsedCallback(ParsedCallback), Stats(Stats),
84 ParseForwardingFunctions(ParseForwardingFunctions),
85 BeforeExecuteCallback(std::move(BeforeExecuteCallback)) {}
87 IncludeStructure takeIncludes() {
return std::move(Includes); }
89 MainFileMacros takeMacros() {
return std::move(Macros); }
91 std::vector<PragmaMark> takeMarks() {
return std::move(Marks); }
93 include_cleaner::PragmaIncludes takePragmaIncludes() {
94 return std::move(Pragmas);
96 CanonicalIncludes takeCanonicalIncludes() {
return std::move(CanonIncludes); }
98 bool isMainFileIncludeGuarded()
const {
return IsMainFileIncludeGuarded; }
100 void AfterExecute(CompilerInstance &
CI)
override {
101 if (ParsedCallback) {
102 trace::Span Tracer(
"Running PreambleCallback");
103 ParsedCallback(
CI.getASTContext(),
CI.getPreprocessor(), CanonIncludes);
106 const SourceManager &SM =
CI.getSourceManager();
107 const FileEntry *MainFE = SM.getFileEntryForID(SM.getMainFileID());
108 IsMainFileIncludeGuarded =
109 CI.getPreprocessor().getHeaderSearchInfo().isFileMultipleIncludeGuarded(
113 const ASTContext &
AST =
CI.getASTContext();
114 Stats->BuildSize =
AST.getASTAllocatedMemory();
115 Stats->BuildSize +=
AST.getSideTableAllocatedMemory();
116 Stats->BuildSize +=
AST.Idents.getAllocator().getTotalMemory();
117 Stats->BuildSize +=
AST.Selectors.getTotalMemory();
119 Stats->BuildSize +=
AST.getSourceManager().getContentCacheSize();
120 Stats->BuildSize +=
AST.getSourceManager().getDataStructureSizes();
122 AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
124 const Preprocessor &PP =
CI.getPreprocessor();
125 Stats->BuildSize += PP.getTotalMemory();
126 if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
127 Stats->BuildSize += PRec->getTotalMemory();
128 Stats->BuildSize += PP.getHeaderSearchInfo().getTotalMemory();
132 void BeforeExecute(CompilerInstance &
CI)
override {
133 CanonIncludes.addSystemHeadersMapping(
CI.getLangOpts());
134 LangOpts = &
CI.getLangOpts();
135 SourceMgr = &
CI.getSourceManager();
136 PP = &
CI.getPreprocessor();
137 Includes.collect(
CI);
139 if (BeforeExecuteCallback)
140 BeforeExecuteCallback(
CI);
143 std::unique_ptr<PPCallbacks> createPPCallbacks()
override {
144 assert(SourceMgr && LangOpts && PP &&
145 "SourceMgr, LangOpts and PP must be set at this point");
147 return std::make_unique<PPChainedCallbacks>(
148 std::make_unique<CollectMainFileMacros>(*PP, Macros),
154 return IWYUHandler.get();
157 static bool isLikelyForwardingFunction(FunctionTemplateDecl *FT) {
158 const auto *FD = FT->getTemplatedDecl();
159 const auto NumParams = FD->getNumParams();
162 const auto *LastParam = FD->getParamDecl(NumParams - 1);
163 if (
const auto *PET = dyn_cast<PackExpansionType>(LastParam->getType())) {
165 const auto BaseType = PET->getPattern().getNonReferenceType();
166 if (
const auto *TTPT =
167 dyn_cast<TemplateTypeParmType>(BaseType.getTypePtr())) {
169 if (FT->getTemplateParameters()->getDepth() == TTPT->getDepth()) {
178 bool shouldSkipFunctionBody(
Decl *D)
override {
186 if (
auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
187 if (ParseForwardingFunctions) {
189 if (isLikelyForwardingFunction(FT))
194 if (
const auto *II = FT->getDeclName().getAsIdentifierInfo()) {
195 if (II->isStr(
"make_unique") && FT->isInStdNamespace())
206 IncludeStructure Includes;
207 CanonicalIncludes CanonIncludes;
208 include_cleaner::PragmaIncludes Pragmas;
209 MainFileMacros Macros;
210 std::vector<PragmaMark> Marks;
211 bool IsMainFileIncludeGuarded =
false;
212 std::unique_ptr<CommentHandler> IWYUHandler =
nullptr;
213 const clang::LangOptions *LangOpts =
nullptr;
214 const SourceManager *SourceMgr =
nullptr;
215 const Preprocessor *PP =
nullptr;
216 PreambleBuildStats *Stats;
217 bool ParseForwardingFunctions;
218 std::function<void(CompilerInstance &)> BeforeExecuteCallback;
223struct TextualPPDirective {
228 tok::PPKeywordKind
Directive = tok::PPKeywordKind::pp_not_keyword;
232 bool operator==(
const TextualPPDirective &RHS)
const {
234 std::tie(RHS.DirectiveLine, RHS.Offset, RHS.Text);
241std::string spellDirective(llvm::StringRef Prefix,
242 CharSourceRange DirectiveRange,
243 const LangOptions &LangOpts,
const SourceManager &SM,
245 std::string SpelledDirective;
246 llvm::raw_string_ostream
OS(SpelledDirective);
250 DirectiveRange = SM.getExpansionRange(DirectiveRange);
251 if (DirectiveRange.isTokenRange()) {
252 DirectiveRange.setEnd(
253 Lexer::getLocForEndOfToken(DirectiveRange.getEnd(), 0, SM, LangOpts));
256 auto DecompLoc = SM.getDecomposedLoc(DirectiveRange.getBegin());
257 DirectiveLine = SM.getLineNumber(DecompLoc.first, DecompLoc.second);
258 Offset = DecompLoc.second;
259 auto TargetColumn = SM.getColumnNumber(DecompLoc.first, DecompLoc.second) - 1;
263 if (Prefix.size() <= TargetColumn) {
267 OS << std::string(TargetColumn - Prefix.size(),
' ');
273 OS <<
"\\\n" << std::string(TargetColumn,
' ');
284 DirectiveCollector(
const Preprocessor &PP,
285 std::vector<TextualPPDirective> &TextualDirectives)
286 : LangOpts(PP.getLangOpts()), SM(PP.getSourceManager()),
287 TextualDirectives(TextualDirectives) {}
289 void FileChanged(SourceLocation
Loc, FileChangeReason Reason,
290 SrcMgr::CharacteristicKind FileType,
291 FileID PrevFID)
override {
292 InMainFile = SM.isWrittenInMainFile(
Loc);
295 void MacroDefined(
const Token &MacroNameTok,
296 const MacroDirective *MD)
override {
299 TextualDirectives.emplace_back();
300 TextualPPDirective &TD = TextualDirectives.back();
301 TD.Directive = tok::pp_define;
302 TD.MacroName = MacroNameTok.getIdentifierInfo()->getName().str();
304 const auto *MI = MD->getMacroInfo();
306 spellDirective(
"#define ",
307 CharSourceRange::getTokenRange(
308 MI->getDefinitionLoc(), MI->getDefinitionEndLoc()),
309 LangOpts, SM, TD.DirectiveLine, TD.Offset);
313 bool InMainFile =
true;
314 const LangOptions &LangOpts;
315 const SourceManager &SM;
316 std::vector<TextualPPDirective> &TextualDirectives;
319struct ScannedPreamble {
320 std::vector<Inclusion> Includes;
321 std::vector<TextualPPDirective> TextualDirectives;
325 std::vector<PragmaMark> Marks;
326 MainFileMacros Macros;
333llvm::Expected<ScannedPreamble>
334scanPreamble(llvm::StringRef Contents,
const tooling::CompileCommand &Cmd) {
335 class EmptyFS :
public ThreadsafeFS {
337 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
338 return new llvm::vfs::InMemoryFileSystem;
346 PI.Contents = Contents.str();
348 PI.CompileCommand = Cmd;
352 return error(
"failed to create compiler invocation");
353 CI->getDiagnosticOpts().IgnoreWarnings =
true;
354 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(PI.Contents);
358 auto Bounds = ComputePreambleBounds(*
CI->getLangOpts(), *ContentsBuffer, 0);
359 auto PreambleContents = llvm::MemoryBuffer::getMemBufferCopy(
360 llvm::StringRef(PI.Contents).take_front(
Bounds.Size));
362 std::move(
CI),
nullptr, std::move(PreambleContents),
366 if (
Clang->getFrontendOpts().Inputs.empty())
367 return error(
"compiler instance had no inputs");
369 Clang->getPreprocessorOpts().SingleFileParseMode =
true;
370 Clang->getPreprocessorOpts().UsePredefines =
false;
371 PreprocessOnlyAction
Action;
373 return error(
"failed BeginSourceFile");
374 Preprocessor &PP =
Clang->getPreprocessor();
375 const auto &SM = PP.getSourceManager();
376 IncludeStructure Includes;
381 std::make_unique<DirectiveCollector>(PP, SP.TextualDirectives));
383 PP.addPPCallbacks(std::make_unique<CollectMainFileMacros>(PP, SP.Macros));
384 if (llvm::Error Err =
Action.Execute())
385 return std::move(Err);
388 llvm::append_range(SP.Lines, llvm::split(Contents,
"\n"));
392const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
393 switch (IncludeDirective) {
394 case tok::pp_include:
398 case tok::pp_include_next:
399 return "include_next";
403 llvm_unreachable(
"not an include directive");
412 WallTimer() : TotalTime(std::chrono::steady_clock::duration::zero()) {}
414 void startTimer() { StartTime = std::chrono::steady_clock::now(); }
417 TotalTime += std::chrono::steady_clock::now() - StartTime;
420 double getTime() {
return std::chrono::duration<double>(TotalTime).count(); }
423 std::chrono::steady_clock::duration TotalTime;
424 std::chrono::steady_clock::time_point StartTime;
427class WallTimerRegion {
429 WallTimerRegion(WallTimer &T) : T(T) { T.startTimer(); }
430 ~WallTimerRegion() { T.stopTimer(); }
438class TimerFile :
public llvm::vfs::File {
440 TimerFile(WallTimer &Timer, std::unique_ptr<File> InnerFile)
441 : Timer(Timer), InnerFile(std::move(InnerFile)) {}
443 llvm::ErrorOr<llvm::vfs::Status> status()
override {
444 WallTimerRegion T(Timer);
445 return InnerFile->status();
447 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
448 getBuffer(
const Twine &
Name, int64_t FileSize,
bool RequiresNullTerminator,
449 bool IsVolatile)
override {
450 WallTimerRegion T(Timer);
451 return InnerFile->getBuffer(
Name, FileSize, RequiresNullTerminator,
454 std::error_code close()
override {
455 WallTimerRegion T(Timer);
456 return InnerFile->close();
461 std::unique_ptr<llvm::vfs::File> InnerFile;
466class TimerFS :
public llvm::vfs::ProxyFileSystem {
468 TimerFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
469 : ProxyFileSystem(std::move(FS)) {}
471 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
472 openFileForRead(
const llvm::Twine &
Path)
override {
473 WallTimerRegion T(Timer);
474 auto FileOr = getUnderlyingFS().openFileForRead(
Path);
477 return std::make_unique<TimerFile>(Timer, std::move(FileOr.get()));
480 llvm::ErrorOr<llvm::vfs::Status> status(
const llvm::Twine &
Path)
override {
481 WallTimerRegion T(Timer);
482 return getUnderlyingFS().status(
Path);
485 double getTime() {
return Timer.getTime(); }
493 llvm::ArrayRef<llvm::StringRef> OldLines;
494 llvm::ArrayRef<llvm::StringRef> CurrentLines;
495 llvm::StringMap<llvm::SmallVector<int>> CurrentContentsToLine;
501 bool translateRange(Range &R) {
502 int OldStart = R.start.line;
503 int OldEnd = R.end.line;
504 assert(OldStart <= OldEnd);
506 size_t RangeLen = OldEnd - OldStart + 1;
507 auto RangeContents = OldLines.slice(OldStart).take_front(RangeLen);
509 if (RangeContents.size() < RangeLen)
512 std::optional<int> Closest;
513 for (
int AlternateLine : CurrentContentsToLine.lookup(RangeContents[0])) {
516 CurrentLines.slice(AlternateLine).take_front(RangeLen))
518 int Delta = AlternateLine - OldStart;
519 if (!Closest.has_value() || abs(Delta) < abs(*Closest))
523 if (!Closest.has_value())
525 R.start.line += *Closest;
526 R.end.line += *Closest;
532 bool translateNote(Note &N) {
533 if (!N.InsideMainFile)
535 if (translateRange(N.Range))
542 bool translateFix(Fix &F) {
544 F.Edits, [
this](TextEdit &
E) { return translateRange(E.range); });
548 DiagPatcher(llvm::ArrayRef<llvm::StringRef> OldLines,
549 llvm::ArrayRef<llvm::StringRef> CurrentLines) {
550 this->OldLines = OldLines;
551 this->CurrentLines = CurrentLines;
552 for (
int Line = 0,
E = CurrentLines.size(); Line !=
E; ++Line) {
553 llvm::StringRef Contents = CurrentLines[
Line];
554 CurrentContentsToLine[Contents].push_back(Line);
561 std::optional<Diag> translateDiag(
const Diag &D) {
564 if (
D.InsideMainFile && !translateRange(NewRange)) {
570 NewD.Range = NewRange;
573 llvm::erase_if(NewD.Notes, [
this](Note &N) { return !translateNote(N); });
574 llvm::erase_if(NewD.Fixes, [
this](Fix &F) { return !translateFix(F); });
580std::shared_ptr<const PreambleData>
587 auto ContentsBuffer =
589 auto Bounds = ComputePreambleBounds(*
CI.getLangOpts(), *ContentsBuffer, 0);
593 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
596 if (
auto Listener =
M.astListeners())
597 ASTListeners.emplace_back(std::move(Listener));
603 llvm::for_each(ASTListeners,
604 [&](
const auto &L) { L->sawDiagnostic(D,
Diag); });
606 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
607 CompilerInstance::createDiagnostics(&
CI.getDiagnosticOpts(),
608 &PreambleDiagnostics,
false);
610 PreambleDiagnostics.
setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
611 const clang::Diagnostic &
Info) {
615 return DiagnosticsEngine::Ignored;
616 switch (
Info.getID()) {
617 case diag::warn_no_newline_eof:
618 case diag::warn_cxx98_compat_no_newline_eof:
619 case diag::ext_no_newline_eof:
622 return Bounds.Size != ContentsBuffer->getBufferSize()
623 ? DiagnosticsEngine::Level::Ignored
631 assert(!
CI.getFrontendOpts().SkipFunctionBodies);
632 CI.getFrontendOpts().SkipFunctionBodies =
true;
635 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
637 CppFilePreambleCallbacks CapturedInfo(
640 [&ASTListeners](CompilerInstance &
CI) {
641 for (const auto &L : ASTListeners)
642 L->beforeExecute(CI);
645 llvm::SmallString<32> AbsFileName(
FileName);
646 VFS->makeAbsolute(AbsFileName);
647 auto StatCache = std::make_unique<PreambleFileStatusCache>(AbsFileName);
648 auto StatCacheFS = StatCache->getProducingFS(VFS);
649 llvm::IntrusiveRefCntPtr<TimerFS> TimedFS(
new TimerFS(StatCacheFS));
651 WallTimer PreambleTimer;
652 PreambleTimer.startTimer();
653 auto BuiltPreamble = PrecompiledPreamble::Build(
654 CI, ContentsBuffer.get(),
Bounds, *PreambleDiagsEngine,
655 Stats ? TimedFS : StatCacheFS, std::make_shared<PCHContainerOperations>(),
656 StoreInMemory, StringRef(), CapturedInfo);
657 PreambleTimer.stopTimer();
661 CI.getFrontendOpts().SkipFunctionBodies =
false;
663 if (Stats !=
nullptr) {
666 Stats->
SerializedSize = BuiltPreamble ? BuiltPreamble->getSize() : 0;
670 log(
"Built preamble of size {0} for file {1} version {2} in {3} seconds",
672 PreambleTimer.getTime());
673 std::vector<Diag> Diags = PreambleDiagnostics.
take();
674 auto Result = std::make_shared<PreambleData>(std::move(*BuiltPreamble));
675 Result->Version = Inputs.
Version;
677 Result->Diags = std::move(Diags);
678 Result->Includes = CapturedInfo.takeIncludes();
679 Result->Pragmas = CapturedInfo.takePragmaIncludes();
680 Result->Macros = CapturedInfo.takeMacros();
681 Result->Marks = CapturedInfo.takeMarks();
682 Result->CanonIncludes = CapturedInfo.takeCanonicalIncludes();
683 Result->StatCache = std::move(StatCache);
684 Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
688 elog(
"Could not build a preamble for file {0} version {1}: {2}",
FileName,
689 Inputs.
Version, BuiltPreamble.getError().message());
690 for (
const Diag &D : PreambleDiagnostics.
take()) {
691 if (D.Severity < DiagnosticsEngine::Error)
694 elog(
" error: {0}", D.Message);
701 const CompilerInvocation &
CI) {
702 auto ContentsBuffer =
704 auto Bounds = ComputePreambleBounds(*
CI.getLangOpts(), *ContentsBuffer, 0);
712 for (
char C :
Text) {
727static std::vector<Diag>
patchDiags(llvm::ArrayRef<Diag> BaselineDiags,
728 const ScannedPreamble &BaselineScan,
729 const ScannedPreamble &ModifiedScan) {
730 std::vector<Diag> PatchedDiags;
731 if (BaselineDiags.empty())
733 DiagPatcher Patcher(BaselineScan.Lines, ModifiedScan.Lines);
734 for (
auto &D : BaselineDiags) {
735 if (
auto NewD = Patcher.translateDiag(D))
736 PatchedDiags.emplace_back(std::move(*NewD));
743 llvm::SmallString<128> PatchName;
744 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(
FileName),
746 return PatchName.str().str();
749PreamblePatch PreamblePatch::create(llvm::StringRef
FileName,
750 const ParseInputs &Modified,
751 const PreambleData &Baseline,
752 PatchType PatchType) {
753 trace::Span Tracer(
"CreatePreamblePatch");
755 assert(llvm::sys::path::is_absolute(
FileName) &&
"relative FileName!");
765 scanPreamble(Baseline.Preamble.getContents(), Modified.CompileCommand);
767 elog(
"Failed to scan baseline of {0}: {1}",
FileName,
768 BaselineScan.takeError());
771 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand);
773 elog(
"Failed to scan modified contents of {0}: {1}",
FileName,
774 ModifiedScan.takeError());
778 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
779 bool DirectivesChanged =
780 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
786 PP.Baseline = &Baseline;
788 PP.ModifiedBounds = ModifiedScan->Bounds;
790 llvm::raw_string_ostream
Patch(PP.PatchContents);
792 Patch <<
"#line 0 \"";
801 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
804 for (
const auto &Inc : Baseline.Includes.MainFileIncludes)
805 ExistingIncludes[{Inc.Directive, Inc.Written}] = &Inc;
808 for (
const auto &Inc : BaselineScan->Includes)
809 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
811 for (
auto &Inc : ModifiedScan->Includes) {
812 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
815 if (It != ExistingIncludes.end()) {
819 auto &PatchedInc = PP.PreambleIncludes.emplace_back();
822 PatchedInc = *It->second;
823 PatchedInc.HashLine = Inc.HashLine;
824 PatchedInc.HashOffset = Inc.HashOffset;
831 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
832 Patch << llvm::formatv(
833 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
839 PP.PreambleIncludes = Baseline.Includes.MainFileIncludes;
842 if (DirectivesChanged) {
854 for (
const auto &TD : ModifiedScan->TextualDirectives) {
857 if (TD.Directive == tok::pp_define)
858 Patch <<
"#undef " << TD.MacroName <<
'\n';
859 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
860 Patch << TD.Text <<
'\n';
864 PP.PatchedDiags =
patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan);
865 PP.PatchedMarks = std::move(ModifiedScan->Marks);
866 PP.PatchedMacros = std::move(ModifiedScan->Macros);
867 dlog(
"Created preamble patch: {0}",
Patch.str());
886 if (PatchContents.empty())
888 auto &PPOpts =
CI.getPreprocessorOpts();
892 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
894 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
897 PPOpts.Includes.push_back(PatchFileName);
901 return PreambleIncludes;
907 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
908 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
914 return PatchContents.empty() ||
918 if (PatchContents.empty())
919 return Baseline->Marks;
924 if (PatchContents.empty())
925 return Baseline->Macros;
926 return PatchedMacros;
930 const SourceManager &SM) {
932 if (
auto File = SM.getFileManager().getFile(PatchFilePath))
const FunctionDecl * Decl
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.
bool preserveDiagnostics() const
Whether diagnostics generated using this patch are trustable.
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 const FileEntry * getPatchEntry(llvm::StringRef MainFilePath, const SourceManager &SM)
Returns the FileEntry for the preamble patch of MainFilePath in SM, if any.
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.
@ 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< CommentHandler > collectIWYUHeaderMaps(CanonicalIncludes *Includes)
Returns a CommentHandler that parses pragma comment on include files to determine when we should incl...
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)
std::function< void(ASTContext &, Preprocessor &, const CanonicalIncludes &)> PreambleParsedCallback
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.
bool AllowStalePreamble
Enable emitting diagnostics using stale preambles.
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.