20#include "clang-include-cleaner/Record.h"
25#include "clang/AST/DeclTemplate.h"
26#include "clang/AST/Type.h"
27#include "clang/Basic/Diagnostic.h"
28#include "clang/Basic/DiagnosticLex.h"
29#include "clang/Basic/DiagnosticOptions.h"
30#include "clang/Basic/LangOptions.h"
31#include "clang/Basic/SourceLocation.h"
32#include "clang/Basic/SourceManager.h"
33#include "clang/Basic/TargetInfo.h"
34#include "clang/Basic/TokenKinds.h"
35#include "clang/Frontend/CompilerInstance.h"
36#include "clang/Frontend/CompilerInvocation.h"
37#include "clang/Frontend/FrontendActions.h"
38#include "clang/Frontend/PrecompiledPreamble.h"
39#include "clang/Lex/HeaderSearch.h"
40#include "clang/Lex/Lexer.h"
41#include "clang/Lex/PPCallbacks.h"
42#include "clang/Lex/Preprocessor.h"
43#include "clang/Lex/PreprocessorOptions.h"
44#include "clang/Serialization/ASTReader.h"
45#include "clang/Tooling/CompilationDatabase.h"
46#include "llvm/ADT/ArrayRef.h"
47#include "llvm/ADT/DenseMap.h"
48#include "llvm/ADT/IntrusiveRefCntPtr.h"
49#include "llvm/ADT/STLExtras.h"
50#include "llvm/ADT/SmallString.h"
51#include "llvm/ADT/SmallVector.h"
52#include "llvm/ADT/StringExtras.h"
53#include "llvm/ADT/StringMap.h"
54#include "llvm/ADT/StringRef.h"
55#include "llvm/Support/Casting.h"
56#include "llvm/Support/Error.h"
57#include "llvm/Support/ErrorHandling.h"
58#include "llvm/Support/ErrorOr.h"
59#include "llvm/Support/FormatVariadic.h"
60#include "llvm/Support/MemoryBuffer.h"
61#include "llvm/Support/Path.h"
62#include "llvm/Support/VirtualFileSystem.h"
63#include "llvm/Support/raw_ostream.h"
73#include <system_error>
82bool compileCommandsAreEqual(
const tooling::CompileCommand &LHS,
83 const tooling::CompileCommand &RHS) {
85 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
86 llvm::ArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
89class CppFilePreambleCallbacks :
public PreambleCallbacks {
91 CppFilePreambleCallbacks(
92 PathRef File, PreambleBuildStats *Stats,
bool ParseForwardingFunctions,
93 std::function<
void(CompilerInstance &)> BeforeExecuteCallback)
94 : File(File), Stats(Stats),
95 ParseForwardingFunctions(ParseForwardingFunctions),
96 BeforeExecuteCallback(std::move(BeforeExecuteCallback)) {}
98 IncludeStructure takeIncludes() {
return std::move(Includes); }
100 MainFileMacros takeMacros() {
return std::move(Macros); }
102 std::vector<PragmaMark> takeMarks() {
return std::move(Marks); }
104 include_cleaner::PragmaIncludes takePragmaIncludes() {
105 return std::move(Pragmas);
108 std::optional<CapturedASTCtx> takeLife() {
return std::move(CapturedCtx); }
110 bool isMainFileIncludeGuarded()
const {
return IsMainFileIncludeGuarded; }
112 void AfterExecute(CompilerInstance &CI)
override {
117 if (CI.getASTReader()) {
118 CI.getASTReader()->setDeserializationListener(
nullptr);
120 CI.getASTReader()->StartTranslationUnit(
nullptr);
122 CI.getASTContext().setASTMutationListener(
nullptr);
123 CapturedCtx.emplace(CI);
125 const SourceManager &SM = CI.getSourceManager();
126 OptionalFileEntryRef MainFE = SM.getFileEntryRefForID(SM.getMainFileID());
127 IsMainFileIncludeGuarded =
128 CI.getPreprocessor().getHeaderSearchInfo().isFileMultipleIncludeGuarded(
132 const ASTContext &
AST = CI.getASTContext();
133 Stats->BuildSize =
AST.getASTAllocatedMemory();
134 Stats->BuildSize +=
AST.getSideTableAllocatedMemory();
135 Stats->BuildSize +=
AST.Idents.getAllocator().getTotalMemory();
136 Stats->BuildSize +=
AST.Selectors.getTotalMemory();
138 Stats->BuildSize +=
AST.getSourceManager().getContentCacheSize();
139 Stats->BuildSize +=
AST.getSourceManager().getDataStructureSizes();
141 AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
143 const Preprocessor &PP = CI.getPreprocessor();
144 Stats->BuildSize += PP.getTotalMemory();
145 if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
146 Stats->BuildSize += PRec->getTotalMemory();
147 Stats->BuildSize += PP.getHeaderSearchInfo().getTotalMemory();
151 void BeforeExecute(CompilerInstance &CI)
override {
152 LangOpts = &CI.getLangOpts();
153 SourceMgr = &CI.getSourceManager();
154 PP = &CI.getPreprocessor();
155 Includes.collect(CI);
157 if (BeforeExecuteCallback)
158 BeforeExecuteCallback(CI);
161 std::unique_ptr<PPCallbacks> createPPCallbacks()
override {
162 assert(SourceMgr && LangOpts && PP &&
163 "SourceMgr, LangOpts and PP must be set at this point");
165 return std::make_unique<PPChainedCallbacks>(
166 std::make_unique<CollectMainFileMacros>(*PP, Macros),
170 bool shouldSkipFunctionBody(Decl *D)
override {
178 if (
auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
179 if (ParseForwardingFunctions) {
186 if (
const auto *II = FT->getDeclName().getAsIdentifierInfo()) {
187 if (II->isStr(
"make_unique") && FT->isInStdNamespace())
197 IncludeStructure Includes;
198 include_cleaner::PragmaIncludes Pragmas;
199 MainFileMacros Macros;
200 std::vector<PragmaMark> Marks;
201 bool IsMainFileIncludeGuarded =
false;
202 const clang::LangOptions *LangOpts =
nullptr;
203 const SourceManager *SourceMgr =
nullptr;
204 const Preprocessor *PP =
nullptr;
205 PreambleBuildStats *Stats;
206 bool ParseForwardingFunctions;
207 std::function<void(CompilerInstance &)> BeforeExecuteCallback;
208 std::optional<CapturedASTCtx> CapturedCtx;
213struct TextualPPDirective {
214 unsigned DirectiveLine;
218 tok::PPKeywordKind Directive = tok::PPKeywordKind::pp_not_keyword;
220 std::string MacroName;
222 bool operator==(
const TextualPPDirective &RHS)
const {
223 return std::tie(DirectiveLine, Offset, Text) ==
224 std::tie(RHS.DirectiveLine, RHS.Offset, RHS.Text);
231std::string spellDirective(llvm::StringRef Prefix,
232 CharSourceRange DirectiveRange,
233 const LangOptions &LangOpts,
const SourceManager &SM,
234 unsigned &DirectiveLine,
unsigned &Offset) {
235 std::string SpelledDirective;
236 llvm::raw_string_ostream OS(SpelledDirective);
240 DirectiveRange = SM.getExpansionRange(DirectiveRange);
241 if (DirectiveRange.isTokenRange()) {
242 DirectiveRange.setEnd(
243 Lexer::getLocForEndOfToken(DirectiveRange.getEnd(), 0, SM, LangOpts));
246 auto DecompLoc = SM.getDecomposedLoc(DirectiveRange.getBegin());
247 DirectiveLine = SM.getLineNumber(DecompLoc.first, DecompLoc.second);
248 Offset = DecompLoc.second;
249 auto TargetColumn = SM.getColumnNumber(DecompLoc.first, DecompLoc.second) - 1;
253 if (Prefix.size() <= TargetColumn) {
257 OS << std::string(TargetColumn - Prefix.size(),
' ');
263 OS <<
"\\\n" << std::string(TargetColumn,
' ');
273struct DirectiveCollector :
public PPCallbacks {
274 DirectiveCollector(
const Preprocessor &PP,
275 std::vector<TextualPPDirective> &TextualDirectives)
276 : LangOpts(PP.getLangOpts()), SM(PP.getSourceManager()),
277 TextualDirectives(TextualDirectives) {}
279 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
280 SrcMgr::CharacteristicKind FileType,
281 FileID PrevFID)
override {
282 InMainFile = SM.isWrittenInMainFile(Loc);
285 void MacroDefined(
const Token &MacroNameTok,
286 const MacroDirective *MD)
override {
289 TextualDirectives.emplace_back();
290 TextualPPDirective &TD = TextualDirectives.back();
291 TD.Directive = tok::pp_define;
292 TD.MacroName = MacroNameTok.getIdentifierInfo()->getName().str();
294 const auto *MI = MD->getMacroInfo();
296 spellDirective(
"#define ",
297 CharSourceRange::getTokenRange(
298 MI->getDefinitionLoc(), MI->getDefinitionEndLoc()),
299 LangOpts, SM, TD.DirectiveLine, TD.Offset);
303 bool InMainFile =
true;
304 const LangOptions &LangOpts;
305 const SourceManager &SM;
306 std::vector<TextualPPDirective> &TextualDirectives;
309struct ScannedPreamble {
310 std::vector<Inclusion> Includes;
311 std::vector<TextualPPDirective> TextualDirectives;
313 std::vector<llvm::StringRef> Lines;
314 PreambleBounds Bounds = {0,
false};
315 std::vector<PragmaMark> Marks;
316 MainFileMacros Macros;
323llvm::Expected<ScannedPreamble>
324scanPreamble(llvm::StringRef Contents,
const tooling::CompileCommand &Cmd) {
327 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
328 return new llvm::vfs::InMemoryFileSystem;
338 PI.CompileCommand = Cmd;
339 IgnoringDiagConsumer IgnoreDiags;
342 return error(
"failed to create compiler invocation");
343 CI->getDiagnosticOpts().IgnoreWarnings =
true;
344 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(PI.Contents);
348 auto Bounds = ComputePreambleBounds(CI->getLangOpts(), *ContentsBuffer, 0);
349 auto PreambleContents = llvm::MemoryBuffer::getMemBufferCopy(
350 llvm::StringRef(PI.Contents).take_front(Bounds.Size));
352 std::move(CI),
nullptr, std::move(PreambleContents),
355 FS.view(std::nullopt), IgnoreDiags);
356 if (Clang->getFrontendOpts().Inputs.empty())
357 return error(
"compiler instance had no inputs");
359 Clang->getPreprocessorOpts().SingleFileParseMode =
true;
360 Clang->getPreprocessorOpts().UsePredefines =
false;
361 PreprocessOnlyAction Action;
362 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
363 return error(
"failed BeginSourceFile");
364 Preprocessor &PP = Clang->getPreprocessor();
365 const auto &SM = PP.getSourceManager();
371 std::make_unique<DirectiveCollector>(PP, SP.TextualDirectives));
373 PP.addPPCallbacks(std::make_unique<CollectMainFileMacros>(PP, SP.Macros));
374 if (llvm::Error Err = Action.Execute())
375 return std::move(Err);
376 Action.EndSourceFile();
377 SP.Includes = std::move(Includes.MainFileIncludes);
378 llvm::append_range(SP.Lines, llvm::split(Contents,
"\n"));
382const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
383 switch (IncludeDirective) {
384 case tok::pp_include:
388 case tok::pp_include_next:
389 return "include_next";
393 llvm_unreachable(
"not an include directive");
402 WallTimer() : TotalTime(std::chrono::steady_clock::duration::zero()) {}
404 void startTimer() { StartTime = std::chrono::steady_clock::now(); }
407 TotalTime += std::chrono::steady_clock::now() - StartTime;
410 double getTime() {
return std::chrono::duration<double>(TotalTime).count(); }
413 std::chrono::steady_clock::duration TotalTime;
414 std::chrono::steady_clock::time_point StartTime;
417class WallTimerRegion {
419 WallTimerRegion(WallTimer &T) : T(T) { T.startTimer(); }
420 ~WallTimerRegion() { T.stopTimer(); }
428class TimerFile :
public llvm::vfs::File {
430 TimerFile(WallTimer &Timer, std::unique_ptr<File> InnerFile)
431 : Timer(Timer), InnerFile(std::move(InnerFile)) {}
433 llvm::ErrorOr<llvm::vfs::Status> status()
override {
434 WallTimerRegion
T(Timer);
435 return InnerFile->status();
437 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
438 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
439 bool IsVolatile)
override {
440 WallTimerRegion
T(Timer);
441 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
444 std::error_code close()
override {
445 WallTimerRegion
T(Timer);
446 return InnerFile->close();
451 std::unique_ptr<llvm::vfs::File> InnerFile;
456class TimerFS :
public llvm::vfs::ProxyFileSystem {
458 TimerFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
459 : ProxyFileSystem(std::move(FS)) {}
461 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
462 openFileForRead(
const llvm::Twine &
Path)
override {
463 WallTimerRegion
T(Timer);
464 auto FileOr = getUnderlyingFS().openFileForRead(
Path);
467 return std::make_unique<TimerFile>(Timer, std::move(FileOr.get()));
470 llvm::ErrorOr<llvm::vfs::Status> status(
const llvm::Twine &
Path)
override {
471 WallTimerRegion
T(Timer);
472 return getUnderlyingFS().status(
Path);
475 double getTime() {
return Timer.getTime(); }
483 llvm::ArrayRef<llvm::StringRef> OldLines;
484 llvm::ArrayRef<llvm::StringRef> CurrentLines;
485 llvm::StringMap<llvm::SmallVector<int>> CurrentContentsToLine;
491 bool translateRange(Range &R) {
492 int OldStart = R.start.line;
493 int OldEnd = R.end.line;
494 assert(OldStart <= OldEnd);
496 size_t RangeLen = OldEnd - OldStart + 1;
497 auto RangeContents = OldLines.slice(OldStart).take_front(RangeLen);
499 if (RangeContents.size() < RangeLen)
502 std::optional<int> Closest;
503 for (
int AlternateLine : CurrentContentsToLine.lookup(RangeContents[0])) {
506 CurrentLines.slice(AlternateLine).take_front(RangeLen))
508 int Delta = AlternateLine - OldStart;
509 if (!Closest.has_value() || abs(Delta) < abs(*Closest))
513 if (!Closest.has_value())
515 R.start.line += *Closest;
516 R.end.line += *Closest;
522 bool translateNote(Note &N) {
523 if (!N.InsideMainFile)
525 if (translateRange(N.Range))
532 bool translateFix(
Fix &F) {
534 F.Edits, [
this](TextEdit &E) { return translateRange(E.range); });
538 DiagPatcher(llvm::ArrayRef<llvm::StringRef> OldLines,
539 llvm::ArrayRef<llvm::StringRef> CurrentLines) {
540 this->OldLines = OldLines;
541 this->CurrentLines = CurrentLines;
542 for (
int Line = 0, E = CurrentLines.size(); Line != E; ++Line) {
543 llvm::StringRef Contents = CurrentLines[Line];
544 CurrentContentsToLine[Contents].push_back(Line);
551 std::optional<Diag> translateDiag(
const Diag &D) {
552 Range NewRange =
D.Range;
554 if (
D.InsideMainFile && !translateRange(NewRange)) {
560 NewD.Range = NewRange;
563 llvm::erase_if(NewD.Notes, [
this](Note &N) { return !translateNote(N); });
564 llvm::erase_if(NewD.Fixes, [
this](
Fix &F) { return !translateFix(F); });
570std::shared_ptr<const PreambleData>
577 auto ContentsBuffer =
578 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
579 auto Bounds = ComputePreambleBounds(CI.getLangOpts(), *ContentsBuffer, 0);
583 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
586 if (
auto Listener = M.astListeners())
587 ASTListeners.emplace_back(std::move(Listener));
593 for (
const auto &L : ASTListeners)
594 L->sawDiagnostic(D,
Diag);
597 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
598 CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
599 &PreambleDiagnostics,
601 PreambleDiagnostics.
setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
602 const clang::Diagnostic &
Info) {
603 switch (
Info.getID()) {
604 case diag::warn_no_newline_eof:
607 return Bounds.Size != ContentsBuffer->getBufferSize()
608 ? DiagnosticsEngine::Level::Ignored
616 assert(!CI.getFrontendOpts().SkipFunctionBodies);
617 CI.getFrontendOpts().SkipFunctionBodies =
true;
620 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
622 CppFilePreambleCallbacks CapturedInfo(
624 [&ASTListeners](CompilerInstance &CI) {
625 for (const auto &L : ASTListeners)
626 L->beforeExecute(CI);
628 llvm::SmallString<32> AbsFileName(FileName);
629 VFS->makeAbsolute(AbsFileName);
630 auto StatCache = std::make_shared<PreambleFileStatusCache>(AbsFileName);
631 auto StatCacheFS = StatCache->getProducingFS(VFS);
632 llvm::IntrusiveRefCntPtr<TimerFS> TimedFS(
new TimerFS(StatCacheFS));
634 WallTimer PreambleTimer;
635 PreambleTimer.startTimer();
636 auto BuiltPreamble = PrecompiledPreamble::Build(
637 CI, ContentsBuffer.get(), Bounds, PreambleDiagsEngine,
638 Stats ? TimedFS : StatCacheFS, std::make_shared<PCHContainerOperations>(),
639 StoreInMemory,
"", CapturedInfo);
641 PreambleTimer.stopTimer();
645 PreambleDiagsEngine->setClient(
new IgnoringDiagConsumer,
true);
648 PreambleDiagsEngine.reset();
652 CI.getFrontendOpts().SkipFunctionBodies =
false;
654 if (Stats !=
nullptr) {
657 Stats->
SerializedSize = BuiltPreamble ? BuiltPreamble->getSize() : 0;
661 log(
"Built preamble of size {0} for file {1} version {2} in {3} seconds",
662 BuiltPreamble->getSize(), FileName, Inputs.
Version,
663 PreambleTimer.getTime());
664 std::vector<Diag> Diags = PreambleDiagnostics.
take();
665 auto Result = std::make_shared<PreambleData>(std::move(*BuiltPreamble));
666 Result->Version = Inputs.
Version;
668 Result->Diags = std::move(Diags);
669 Result->Includes = CapturedInfo.takeIncludes();
670 Result->Pragmas = std::make_shared<const include_cleaner::PragmaIncludes>(
671 CapturedInfo.takePragmaIncludes());
674 WallTimer PrerequisiteModuleTimer;
675 PrerequisiteModuleTimer.startTimer();
676 Result->RequiredModules =
679 PrerequisiteModuleTimer.stopTimer();
681 log(
"Built prerequisite modules for file {0} in {1} seconds", FileName,
682 PrerequisiteModuleTimer.getTime());
685 Result->Macros = CapturedInfo.takeMacros();
686 Result->Marks = CapturedInfo.takeMarks();
687 Result->StatCache = std::move(StatCache);
688 Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
692 std::make_unique<TargetOptions>(std::move(CI.getTargetOpts()));
693 if (PreambleCallback) {
695 auto Ctx = CapturedInfo.takeLife();
698 Ctx->getFileManager().setVirtualFileSystem(
699 Result->StatCache->getConsumingFS(VFS));
702 Ctx->setStatCache(Result->StatCache);
704 PreambleCallback(std::move(*Ctx), Result->Pragmas);
709 elog(
"Could not build a preamble for file {0} version {1}: {2}", FileName,
710 Inputs.
Version, BuiltPreamble.getError().message());
711 for (
const Diag &D : PreambleDiagnostics.
take()) {
712 if (D.Severity < DiagnosticsEngine::Error)
715 elog(
" error: {0}", D.Message);
722 const CompilerInvocation &CI) {
723 auto ContentsBuffer =
724 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
725 auto Bounds = ComputePreambleBounds(CI.getLangOpts(), *ContentsBuffer, 0);
729 Preamble.Preamble.CanReuse(CI, *ContentsBuffer, Bounds, *VFS) &&
731 Preamble.RequiredModules->canReuse(CI, VFS));
735 for (
char C :
Text) {
750static std::vector<Diag>
patchDiags(llvm::ArrayRef<Diag> BaselineDiags,
751 const ScannedPreamble &BaselineScan,
752 const ScannedPreamble &ModifiedScan) {
753 std::vector<Diag> PatchedDiags;
754 if (BaselineDiags.empty())
756 DiagPatcher Patcher(BaselineScan.Lines, ModifiedScan.Lines);
757 for (
auto &D : BaselineDiags) {
758 if (
auto NewD = Patcher.translateDiag(D))
759 PatchedDiags.emplace_back(std::move(*NewD));
766 llvm::SmallString<128> PatchName;
767 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName),
769 return PatchName.str().str();
772PreamblePatch PreamblePatch::create(llvm::StringRef FileName,
773 const ParseInputs &Modified,
774 const PreambleData &Baseline,
775 PatchType PatchType) {
776 trace::Span Tracer(
"CreatePreamblePatch");
778 assert(llvm::sys::path::is_absolute(FileName) &&
"relative FileName!");
788 scanPreamble(Baseline.Preamble.getContents(), Modified.CompileCommand);
790 elog(
"Failed to scan baseline of {0}: {1}", FileName,
791 BaselineScan.takeError());
794 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand);
796 elog(
"Failed to scan modified contents of {0}: {1}", FileName,
797 ModifiedScan.takeError());
801 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
802 bool DirectivesChanged =
803 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
809 PP.Baseline = &Baseline;
811 PP.ModifiedBounds = ModifiedScan->Bounds;
813 llvm::raw_string_ostream Patch(PP.PatchContents);
815 Patch <<
"#line 0 \"";
824 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
827 for (
const auto &Inc : Baseline.Includes.MainFileIncludes)
828 ExistingIncludes[{Inc.Directive, Inc.Written}] = &Inc;
831 for (
const auto &Inc : BaselineScan->Includes)
832 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
834 for (
auto &Inc : ModifiedScan->Includes) {
835 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
838 if (It != ExistingIncludes.end()) {
842 auto &PatchedInc = PP.PreambleIncludes.emplace_back();
845 PatchedInc = *It->second;
846 PatchedInc.HashLine = Inc.HashLine;
847 PatchedInc.HashOffset = Inc.HashOffset;
854 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
855 Patch << llvm::formatv(
856 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
862 PP.PreambleIncludes = Baseline.Includes.MainFileIncludes;
865 if (DirectivesChanged) {
877 for (
const auto &TD : ModifiedScan->TextualDirectives) {
880 if (TD.Directive == tok::pp_define)
881 Patch <<
"#undef " << TD.MacroName <<
'\n';
882 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
883 Patch << TD.Text <<
'\n';
887 PP.PatchedDiags =
patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan);
888 PP.PatchedMarks = std::move(ModifiedScan->Marks);
889 PP.PatchedMacros = std::move(ModifiedScan->Macros);
890 dlog(
"Created preamble patch: {0}", Patch.str());
913 CI.getTargetOpts() = *Baseline->TargetOpts;
916 if (PatchContents.empty())
918 auto &PPOpts = CI.getPreprocessorOpts();
922 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
924 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
927 PPOpts.Includes.push_back(PatchFileName);
931 return PreambleIncludes;
937 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
938 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
944 if (PatchContents.empty())
945 return Baseline->Marks;
950 if (PatchContents.empty())
951 return Baseline->Macros;
952 return PatchedMacros;
956 const SourceManager &SM) {
958 return SM.getFileManager().getOptionalFileRef(PatchFilePath);
static cl::opt< bool > Fix("fix", desc(R"(
Apply suggested fixes. Without -fix-errors
clang-tidy will bail out if any compilation
errors were found.
)"), cl::init(false), cl::cat(ClangTidyCategory))
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
void collect(const CompilerInstance &CI)
std::unique_ptr< PrerequisiteModules > buildPrerequisiteModulesFor(PathRef File, const ThreadsafeFS &TFS)
static OptionalFileEntryRef getPatchEntry(llvm::StringRef MainFilePath, const SourceManager &SM)
Returns the FileEntry for the preamble patch of MainFilePath in SM, if any.
const MainFileMacros & mainFileMacros() const
llvm::ArrayRef< PragmaMark > marks() const
void apply(CompilerInvocation &CI) const
Adjusts CI (which compiles the modified inputs) to be used with the baseline preamble.
static PreamblePatch unmodified(const PreambleData &Preamble)
Preamble is used verbatim.
static PreamblePatch createMacroPatch(llvm::StringRef FileName, const ParseInputs &Modified, const PreambleData &Baseline)
static PreamblePatch createFullPatch(llvm::StringRef FileName, const ParseInputs &Modified, const PreambleData &Baseline)
Builds a patch that contains new PP directives introduced to the preamble section of Modified compare...
static constexpr llvm::StringLiteral HeaderName
std::vector< Inclusion > preambleIncludes() const
Returns include directives from the Modified preamble that were resolved using the Baseline preamble.
StoreDiags collects the diagnostics that can later be reported by clangd.
void setLevelAdjuster(LevelAdjuster Adjuster)
If set, this allows the client of this class to adjust the level of diagnostics, such as promoting wa...
std::vector< Diag > take(const clang::tidy::ClangTidyContext *Tidy=nullptr)
void setDiagCallback(DiagCallback CB)
Invokes a callback every time a diagnostics is completely formed.
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
Records an event whose duration is the lifetime of the Span object.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
bool isLikelyForwardingFunction(const FunctionTemplateDecl *FT)
Heuristic that checks if FT is likely to be forwarding a parameter pack to another function (e....
@ Info
An information message.
static std::string getPatchName(llvm::StringRef FileName)
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
bool operator==(const Inclusion &LHS, const Inclusion &RHS)
std::unique_ptr< PPCallbacks > collectPragmaMarksCallback(const SourceManager &SM, std::vector< PragmaMark > &Out)
Collect all pragma marks from the main file.
bool isPreambleCompatible(const PreambleData &Preamble, const ParseInputs &Inputs, PathRef FileName, const CompilerInvocation &CI)
Returns true if Preamble is reusable for Inputs.
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation CI, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback, PreambleBuildStats *Stats)
Build a preamble for the new inputs unless an old one can be reused.
std::unique_ptr< CompilerInstance > prepareCompilerInstance(std::unique_ptr< clang::CompilerInvocation > CI, const PrecompiledPreamble *Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, DiagnosticConsumer &DiagsClient)
void log(const char *Fmt, Ts &&... Vals)
llvm::StringRef toSourceCode(const SourceManager &SM, SourceRange R)
Returns the source code covered by the source range.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
std::string Path
A typedef to represent a file path.
std::pair< size_t, size_t > offsetToClangLineColumn(llvm::StringRef Code, size_t Offset)
static std::vector< Diag > patchDiags(llvm::ArrayRef< Diag > BaselineDiags, const ScannedPreamble &BaselineScan, const ScannedPreamble &ModifiedScan)
void escapeBackslashAndQuotes(llvm::StringRef Text, llvm::raw_ostream &OS)
std::function< void(CapturedASTCtx ASTCtx, std::shared_ptr< const include_cleaner::PragmaIncludes >)> PreambleParsedCallback
void elog(const char *Fmt, Ts &&... Vals)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
A top-level diagnostic that may have Notes and Fixes.
bool PreambleParseForwardingFunctions
Timings and statistics from the premble build.
double FileSystemTime
Time spent in filesystem operations during the build, in seconds.
double TotalBuildTime
Total wall time it took to build preamble, in seconds.
size_t SerializedSize
The serialized size of the preamble.
The parsed preamble and associated data.