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);
617 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
618 CompilerInstance::createDiagnostics(*VFS, &
CI.getDiagnosticOpts(),
619 &PreambleDiagnostics,
622 PreambleDiagnostics.
setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
623 const clang::Diagnostic &
Info) {
627 return DiagnosticsEngine::Ignored;
628 switch (
Info.getID()) {
629 case diag::warn_no_newline_eof:
630 case diag::warn_cxx98_compat_no_newline_eof:
631 case diag::ext_no_newline_eof:
634 return Bounds.Size != ContentsBuffer->getBufferSize()
635 ? DiagnosticsEngine::Level::Ignored
643 assert(!
CI.getFrontendOpts().SkipFunctionBodies);
644 CI.getFrontendOpts().SkipFunctionBodies =
true;
647 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
649 CppFilePreambleCallbacks CapturedInfo(
651 [&ASTListeners](CompilerInstance &
CI) {
652 for (const auto &L : ASTListeners)
653 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);
668 PreambleTimer.stopTimer();
672 PreambleDiagsEngine->setClient(
new IgnoringDiagConsumer,
true);
675 PreambleDiagsEngine.reset();
676 CI.DiagnosticOpts.reset();
680 CI.getFrontendOpts().SkipFunctionBodies =
false;
682 if (Stats !=
nullptr) {
685 Stats->
SerializedSize = BuiltPreamble ? BuiltPreamble->getSize() : 0;
689 log(
"Built preamble of size {0} for file {1} version {2} in {3} seconds",
691 PreambleTimer.getTime());
692 std::vector<Diag> Diags = PreambleDiagnostics.
take();
693 auto Result = std::make_shared<PreambleData>(std::move(*BuiltPreamble));
694 Result->Version = Inputs.
Version;
696 Result->Diags = std::move(Diags);
697 Result->Includes = CapturedInfo.takeIncludes();
698 Result->Pragmas = std::make_shared<const include_cleaner::PragmaIncludes>(
699 CapturedInfo.takePragmaIncludes());
702 WallTimer PrerequisiteModuleTimer;
703 PrerequisiteModuleTimer.startTimer();
704 Result->RequiredModules =
707 PrerequisiteModuleTimer.stopTimer();
709 log(
"Built prerequisite modules for file {0} in {1} seconds",
FileName,
710 PrerequisiteModuleTimer.getTime());
713 Result->Macros = CapturedInfo.takeMacros();
714 Result->Marks = CapturedInfo.takeMarks();
715 Result->StatCache = StatCache;
716 Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
717 Result->TargetOpts =
CI.TargetOpts;
718 if (PreambleCallback) {
720 auto Ctx = CapturedInfo.takeLife();
723 Ctx->getFileManager().setVirtualFileSystem(
724 Result->StatCache->getConsumingFS(VFS));
727 Ctx->setStatCache(Result->StatCache);
729 PreambleCallback(std::move(*Ctx), Result->Pragmas);
734 elog(
"Could not build a preamble for file {0} version {1}: {2}",
FileName,
735 Inputs.
Version, BuiltPreamble.getError().message());
736 for (
const Diag &D : PreambleDiagnostics.
take()) {
737 if (D.Severity < DiagnosticsEngine::Error)
740 elog(
" error: {0}", D.Message);
747 const CompilerInvocation &
CI) {
748 auto ContentsBuffer =
750 auto Bounds = ComputePreambleBounds(
CI.getLangOpts(), *ContentsBuffer, 0);
760 for (
char C :
Text) {
775static std::vector<Diag>
patchDiags(llvm::ArrayRef<Diag> BaselineDiags,
776 const ScannedPreamble &BaselineScan,
777 const ScannedPreamble &ModifiedScan) {
778 std::vector<Diag> PatchedDiags;
779 if (BaselineDiags.empty())
781 DiagPatcher Patcher(BaselineScan.Lines, ModifiedScan.Lines);
782 for (
auto &D : BaselineDiags) {
783 if (
auto NewD = Patcher.translateDiag(D))
784 PatchedDiags.emplace_back(std::move(*NewD));
791 llvm::SmallString<128> PatchName;
792 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(
FileName),
794 return PatchName.str().str();
797PreamblePatch PreamblePatch::create(llvm::StringRef
FileName,
798 const ParseInputs &Modified,
799 const PreambleData &Baseline,
800 PatchType PatchType) {
801 trace::Span Tracer(
"CreatePreamblePatch");
803 assert(llvm::sys::path::is_absolute(
FileName) &&
"relative FileName!");
813 scanPreamble(Baseline.Preamble.getContents(), Modified.CompileCommand);
815 elog(
"Failed to scan baseline of {0}: {1}",
FileName,
816 BaselineScan.takeError());
819 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand);
821 elog(
"Failed to scan modified contents of {0}: {1}",
FileName,
822 ModifiedScan.takeError());
826 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
827 bool DirectivesChanged =
828 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
834 PP.Baseline = &Baseline;
836 PP.ModifiedBounds = ModifiedScan->Bounds;
838 llvm::raw_string_ostream
Patch(PP.PatchContents);
840 Patch <<
"#line 0 \"";
849 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
852 for (
const auto &Inc : Baseline.Includes.MainFileIncludes)
853 ExistingIncludes[{Inc.Directive, Inc.Written}] = &Inc;
856 for (
const auto &Inc : BaselineScan->Includes)
857 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
859 for (
auto &Inc : ModifiedScan->Includes) {
860 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
863 if (It != ExistingIncludes.end()) {
867 auto &PatchedInc = PP.PreambleIncludes.emplace_back();
870 PatchedInc = *It->second;
871 PatchedInc.HashLine = Inc.HashLine;
872 PatchedInc.HashOffset = Inc.HashOffset;
879 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
880 Patch << llvm::formatv(
881 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
887 PP.PreambleIncludes = Baseline.Includes.MainFileIncludes;
890 if (DirectivesChanged) {
902 for (
const auto &TD : ModifiedScan->TextualDirectives) {
905 if (TD.Directive == tok::pp_define)
906 Patch <<
"#undef " << TD.MacroName <<
'\n';
907 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
908 Patch << TD.Text <<
'\n';
912 PP.PatchedDiags =
patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan);
913 PP.PatchedMarks = std::move(ModifiedScan->Marks);
914 PP.PatchedMacros = std::move(ModifiedScan->Macros);
915 dlog(
"Created preamble patch: {0}",
Patch.str());
938 *
CI.TargetOpts = *Baseline->TargetOpts;
941 if (PatchContents.empty())
943 auto &PPOpts =
CI.getPreprocessorOpts();
947 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
949 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
952 PPOpts.Includes.push_back(PatchFileName);
956 return PreambleIncludes;
962 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
963 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
969 if (PatchContents.empty())
970 return Baseline->Marks;
975 if (PatchContents.empty())
976 return Baseline->Macros;
977 return PatchedMacros;
981 const SourceManager &SM) {
983 return SM.getFileManager().getOptionalFileRef(PatchFilePath);
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
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
std::vector< Inclusion > MainFileIncludes
void collect(const CompilerInstance &CI)
std::unique_ptr< PrerequisiteModules > buildPrerequisiteModulesFor(PathRef File, const ThreadsafeFS &TFS)
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.