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 if (PreambleCallback) {
705 auto Ctx = CapturedInfo.takeLife();
708 Ctx->getFileManager().setVirtualFileSystem(
709 Result->StatCache->getConsumingFS(VFS));
712 Ctx->setStatCache(Result->StatCache);
714 PreambleCallback(std::move(*Ctx), Result->Pragmas);
719 elog(
"Could not build a preamble for file {0} version {1}: {2}",
FileName,
720 Inputs.
Version, BuiltPreamble.getError().message());
721 for (
const Diag &D : PreambleDiagnostics.
take()) {
722 if (D.Severity < DiagnosticsEngine::Error)
725 elog(
" error: {0}", D.Message);
732 const CompilerInvocation &
CI) {
733 auto ContentsBuffer =
735 auto Bounds = ComputePreambleBounds(
CI.getLangOpts(), *ContentsBuffer, 0);
743 for (
char C :
Text) {
758static std::vector<Diag>
patchDiags(llvm::ArrayRef<Diag> BaselineDiags,
759 const ScannedPreamble &BaselineScan,
760 const ScannedPreamble &ModifiedScan) {
761 std::vector<Diag> PatchedDiags;
762 if (BaselineDiags.empty())
764 DiagPatcher Patcher(BaselineScan.Lines, ModifiedScan.Lines);
765 for (
auto &D : BaselineDiags) {
766 if (
auto NewD = Patcher.translateDiag(D))
767 PatchedDiags.emplace_back(std::move(*NewD));
774 llvm::SmallString<128> PatchName;
775 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(
FileName),
777 return PatchName.str().str();
780PreamblePatch PreamblePatch::create(llvm::StringRef
FileName,
781 const ParseInputs &Modified,
782 const PreambleData &Baseline,
783 PatchType PatchType) {
784 trace::Span Tracer(
"CreatePreamblePatch");
786 assert(llvm::sys::path::is_absolute(
FileName) &&
"relative FileName!");
796 scanPreamble(Baseline.Preamble.getContents(), Modified.CompileCommand);
798 elog(
"Failed to scan baseline of {0}: {1}",
FileName,
799 BaselineScan.takeError());
802 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand);
804 elog(
"Failed to scan modified contents of {0}: {1}",
FileName,
805 ModifiedScan.takeError());
809 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
810 bool DirectivesChanged =
811 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
817 PP.Baseline = &Baseline;
819 PP.ModifiedBounds = ModifiedScan->Bounds;
821 llvm::raw_string_ostream
Patch(PP.PatchContents);
823 Patch <<
"#line 0 \"";
832 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
835 for (
const auto &Inc : Baseline.Includes.MainFileIncludes)
836 ExistingIncludes[{Inc.Directive, Inc.Written}] = &Inc;
839 for (
const auto &Inc : BaselineScan->Includes)
840 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
842 for (
auto &Inc : ModifiedScan->Includes) {
843 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
846 if (It != ExistingIncludes.end()) {
850 auto &PatchedInc = PP.PreambleIncludes.emplace_back();
853 PatchedInc = *It->second;
854 PatchedInc.HashLine = Inc.HashLine;
855 PatchedInc.HashOffset = Inc.HashOffset;
862 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
863 Patch << llvm::formatv(
864 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
870 PP.PreambleIncludes = Baseline.Includes.MainFileIncludes;
873 if (DirectivesChanged) {
885 for (
const auto &TD : ModifiedScan->TextualDirectives) {
888 if (TD.Directive == tok::pp_define)
889 Patch <<
"#undef " << TD.MacroName <<
'\n';
890 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
891 Patch << TD.Text <<
'\n';
895 PP.PatchedDiags =
patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan);
896 PP.PatchedMarks = std::move(ModifiedScan->Marks);
897 PP.PatchedMacros = std::move(ModifiedScan->Macros);
898 dlog(
"Created preamble patch: {0}",
Patch.str());
917 if (PatchContents.empty())
919 auto &PPOpts =
CI.getPreprocessorOpts();
923 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
925 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
928 PPOpts.Includes.push_back(PatchFileName);
932 return PreambleIncludes;
938 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
939 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
945 if (PatchContents.empty())
946 return Baseline->Marks;
951 if (PatchContents.empty())
952 return Baseline->Macros;
953 return PatchedMacros;
957 const SourceManager &SM) {
959 return SM.getFileManager().getOptionalFileRef(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.
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.