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> scanPreamble(llvm::StringRef Contents,
324 const tooling::CompileCommand &Cmd,
325 bool SkipPreambleBuild) {
328 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
329 return new llvm::vfs::InMemoryFileSystem;
339 PI.CompileCommand = Cmd;
340 IgnoringDiagConsumer IgnoreDiags;
343 return error(
"failed to create compiler invocation");
344 CI->getDiagnosticOpts().IgnoreWarnings =
true;
345 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(PI.Contents);
351 auto PreambleContents = llvm::MemoryBuffer::getMemBufferCopy(
352 llvm::StringRef(PI.Contents).take_front(Bounds.Size));
354 std::move(CI),
nullptr, std::move(PreambleContents),
357 FS.view(std::nullopt), IgnoreDiags);
358 if (Clang->getFrontendOpts().Inputs.empty())
359 return error(
"compiler instance had no inputs");
361 Clang->getPreprocessorOpts().SingleFileParseMode =
true;
362 Clang->getPreprocessorOpts().UsePredefines =
false;
363 PreprocessOnlyAction Action;
364 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
365 return error(
"failed BeginSourceFile");
366 Preprocessor &PP = Clang->getPreprocessor();
367 const auto &SM = PP.getSourceManager();
373 std::make_unique<DirectiveCollector>(PP, SP.TextualDirectives));
375 PP.addPPCallbacks(std::make_unique<CollectMainFileMacros>(PP, SP.Macros));
376 if (llvm::Error Err = Action.Execute())
377 return std::move(Err);
378 Action.EndSourceFile();
379 SP.Includes = std::move(Includes.MainFileIncludes);
380 llvm::append_range(SP.Lines, llvm::split(Contents,
"\n"));
384const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
385 switch (IncludeDirective) {
386 case tok::pp_include:
390 case tok::pp_include_next:
391 return "include_next";
395 llvm_unreachable(
"not an include directive");
404 WallTimer() : TotalTime(std::chrono::steady_clock::duration::zero()) {}
406 void startTimer() { StartTime = std::chrono::steady_clock::now(); }
409 TotalTime += std::chrono::steady_clock::now() - StartTime;
412 double getTime() {
return std::chrono::duration<double>(TotalTime).count(); }
415 std::chrono::steady_clock::duration TotalTime;
416 std::chrono::steady_clock::time_point StartTime;
419class WallTimerRegion {
421 WallTimerRegion(WallTimer &T) : T(T) { T.startTimer(); }
422 ~WallTimerRegion() { T.stopTimer(); }
430class TimerFile :
public llvm::vfs::File {
432 TimerFile(WallTimer &Timer, std::unique_ptr<File> InnerFile)
433 : Timer(Timer), InnerFile(std::move(InnerFile)) {}
435 llvm::ErrorOr<llvm::vfs::Status> status()
override {
436 WallTimerRegion
T(Timer);
437 return InnerFile->status();
439 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
440 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
441 bool IsVolatile)
override {
442 WallTimerRegion
T(Timer);
443 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
446 std::error_code close()
override {
447 WallTimerRegion
T(Timer);
448 return InnerFile->close();
453 std::unique_ptr<llvm::vfs::File> InnerFile;
458class TimerFS :
public llvm::vfs::ProxyFileSystem {
460 TimerFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
461 : ProxyFileSystem(std::move(FS)) {}
463 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
464 openFileForRead(
const llvm::Twine &
Path)
override {
465 WallTimerRegion
T(Timer);
466 auto FileOr = getUnderlyingFS().openFileForRead(
Path);
469 return std::make_unique<TimerFile>(Timer, std::move(FileOr.get()));
472 llvm::ErrorOr<llvm::vfs::Status> status(
const llvm::Twine &
Path)
override {
473 WallTimerRegion
T(Timer);
474 return getUnderlyingFS().status(
Path);
477 double getTime() {
return Timer.getTime(); }
485 llvm::ArrayRef<llvm::StringRef> OldLines;
486 llvm::ArrayRef<llvm::StringRef> CurrentLines;
487 llvm::StringMap<llvm::SmallVector<int>> CurrentContentsToLine;
493 bool translateRange(Range &R) {
494 int OldStart = R.start.line;
495 int OldEnd = R.end.line;
496 assert(OldStart <= OldEnd);
498 size_t RangeLen = OldEnd - OldStart + 1;
499 auto RangeContents = OldLines.slice(OldStart).take_front(RangeLen);
501 if (RangeContents.size() < RangeLen)
504 std::optional<int> Closest;
505 for (
int AlternateLine : CurrentContentsToLine.lookup(RangeContents[0])) {
508 CurrentLines.slice(AlternateLine).take_front(RangeLen))
510 int Delta = AlternateLine - OldStart;
511 if (!Closest.has_value() || abs(Delta) < abs(*Closest))
515 if (!Closest.has_value())
517 R.start.line += *Closest;
518 R.end.line += *Closest;
524 bool translateNote(Note &N) {
525 if (!N.InsideMainFile)
527 if (translateRange(N.Range))
534 bool translateFix(
Fix &F) {
536 F.Edits, [
this](TextEdit &E) { return translateRange(E.range); });
540 DiagPatcher(llvm::ArrayRef<llvm::StringRef> OldLines,
541 llvm::ArrayRef<llvm::StringRef> CurrentLines) {
542 this->OldLines = OldLines;
543 this->CurrentLines = CurrentLines;
544 for (
int Line = 0, E = CurrentLines.size(); Line != E; ++Line) {
545 llvm::StringRef Contents = CurrentLines[Line];
546 CurrentContentsToLine[Contents].push_back(Line);
553 std::optional<Diag> translateDiag(
const Diag &D) {
554 Range NewRange =
D.Range;
556 if (
D.InsideMainFile && !translateRange(NewRange)) {
562 NewD.Range = NewRange;
565 llvm::erase_if(NewD.Notes, [
this](Note &N) { return !translateNote(N); });
566 llvm::erase_if(NewD.Fixes, [
this](
Fix &F) { return !translateFix(F); });
572std::shared_ptr<const PreambleData>
579 auto ContentsBuffer =
580 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
586 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
589 if (
auto Listener = M.astListeners())
590 ASTListeners.emplace_back(std::move(Listener));
596 for (
const auto &L : ASTListeners)
597 L->sawDiagnostic(D,
Diag);
600 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
601 CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
602 &PreambleDiagnostics,
604 PreambleDiagnostics.
setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
605 const clang::Diagnostic &
Info) {
606 switch (
Info.getID()) {
607 case diag::warn_no_newline_eof:
610 return Bounds.Size != ContentsBuffer->getBufferSize()
611 ? DiagnosticsEngine::Level::Ignored
619 assert(!CI.getFrontendOpts().SkipFunctionBodies);
620 CI.getFrontendOpts().SkipFunctionBodies =
true;
623 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
625 CppFilePreambleCallbacks CapturedInfo(
627 [&ASTListeners](CompilerInstance &CI) {
628 for (const auto &L : ASTListeners)
629 L->beforeExecute(CI);
631 llvm::SmallString<32> AbsFileName(FileName);
632 VFS->makeAbsolute(AbsFileName);
633 auto StatCache = std::make_shared<PreambleFileStatusCache>(AbsFileName);
634 auto StatCacheFS = StatCache->getProducingFS(VFS);
635 llvm::IntrusiveRefCntPtr<TimerFS> TimedFS(
new TimerFS(StatCacheFS));
637 WallTimer PreambleTimer;
638 PreambleTimer.startTimer();
639 auto BuiltPreamble = PrecompiledPreamble::Build(
640 CI, ContentsBuffer.get(), Bounds, PreambleDiagsEngine,
641 Stats ? TimedFS : StatCacheFS, std::make_shared<PCHContainerOperations>(),
642 StoreInMemory,
"", CapturedInfo);
644 PreambleTimer.stopTimer();
648 PreambleDiagsEngine->setClient(
new IgnoringDiagConsumer,
true);
651 PreambleDiagsEngine.reset();
655 CI.getFrontendOpts().SkipFunctionBodies =
false;
657 if (Stats !=
nullptr) {
660 Stats->
SerializedSize = BuiltPreamble ? BuiltPreamble->getSize() : 0;
664 log(
"Built preamble of size {0} for file {1} version {2} in {3} seconds",
665 BuiltPreamble->getSize(), FileName, Inputs.
Version,
666 PreambleTimer.getTime());
667 std::vector<Diag> Diags = PreambleDiagnostics.
take();
668 auto Result = std::make_shared<PreambleData>(std::move(*BuiltPreamble));
669 Result->Version = Inputs.
Version;
671 Result->Diags = std::move(Diags);
672 Result->Includes = CapturedInfo.takeIncludes();
673 Result->Pragmas = std::make_shared<const include_cleaner::PragmaIncludes>(
674 CapturedInfo.takePragmaIncludes());
677 WallTimer PrerequisiteModuleTimer;
678 PrerequisiteModuleTimer.startTimer();
679 Result->RequiredModules =
682 PrerequisiteModuleTimer.stopTimer();
684 log(
"Built prerequisite modules for file {0} in {1} seconds", FileName,
685 PrerequisiteModuleTimer.getTime());
688 Result->Macros = CapturedInfo.takeMacros();
689 Result->Marks = CapturedInfo.takeMarks();
690 Result->StatCache = std::move(StatCache);
691 Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
695 std::make_unique<TargetOptions>(std::move(CI.getTargetOpts()));
696 if (PreambleCallback) {
698 auto Ctx = CapturedInfo.takeLife();
701 Ctx->getFileManager().setVirtualFileSystem(
702 Result->StatCache->getConsumingFS(VFS));
705 Ctx->setStatCache(Result->StatCache);
707 PreambleCallback(std::move(*Ctx), Result->Pragmas);
712 elog(
"Could not build a preamble for file {0} version {1}: {2}", FileName,
713 Inputs.
Version, BuiltPreamble.getError().message());
714 for (
const Diag &D : PreambleDiagnostics.
take()) {
715 if (D.Severity < DiagnosticsEngine::Error)
718 elog(
" error: {0}", D.Message);
725 const CompilerInvocation &CI) {
726 auto ContentsBuffer =
727 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
736 auto RequiredModulesMatch = [&]() ->
bool {
740 llvm::StringSet<> NewNameSet;
741 NewNameSet.insert_range(NewNames);
742 return NewNameSet ==
Preamble.RequiredModules->getRequiredModuleNames();
747 Preamble.Preamble.CanReuse(CI, *ContentsBuffer, Bounds, *VFS) &&
749 Preamble.RequiredModules->canReuse(CI, VFS)) &&
750 RequiredModulesMatch();
754 for (
char C :
Text) {
769static std::vector<Diag>
patchDiags(llvm::ArrayRef<Diag> BaselineDiags,
770 const ScannedPreamble &BaselineScan,
771 const ScannedPreamble &ModifiedScan) {
772 std::vector<Diag> PatchedDiags;
773 if (BaselineDiags.empty())
775 DiagPatcher Patcher(BaselineScan.Lines, ModifiedScan.Lines);
776 for (
auto &D : BaselineDiags) {
777 if (
auto NewD = Patcher.translateDiag(D))
778 PatchedDiags.emplace_back(std::move(*NewD));
785 llvm::SmallString<128> PatchName;
786 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName),
788 return PatchName.str().str();
791PreamblePatch PreamblePatch::create(llvm::StringRef FileName,
792 const ParseInputs &Modified,
793 const PreambleData &Baseline,
794 PatchType PatchType) {
795 trace::Span Tracer(
"CreatePreamblePatch");
797 assert(llvm::sys::path::is_absolute(FileName) &&
"relative FileName!");
807 scanPreamble(Baseline.Preamble.getContents(), Modified.CompileCommand,
808 Modified.Opts.SkipPreambleBuild);
810 elog(
"Failed to scan baseline of {0}: {1}", FileName,
811 BaselineScan.takeError());
814 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand,
815 Modified.Opts.SkipPreambleBuild);
817 elog(
"Failed to scan modified contents of {0}: {1}", FileName,
818 ModifiedScan.takeError());
822 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
823 bool DirectivesChanged =
824 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
830 PP.Baseline = &Baseline;
832 PP.ModifiedBounds = ModifiedScan->Bounds;
834 llvm::raw_string_ostream Patch(PP.PatchContents);
836 Patch <<
"#line 0 \"";
845 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
848 for (
const auto &Inc : Baseline.Includes.MainFileIncludes)
849 ExistingIncludes[{Inc.Directive, Inc.Written}] = &Inc;
852 for (
const auto &Inc : BaselineScan->Includes)
853 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
855 for (
auto &Inc : ModifiedScan->Includes) {
856 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
859 if (It != ExistingIncludes.end()) {
863 auto &PatchedInc = PP.PreambleIncludes.emplace_back();
866 PatchedInc = *It->second;
867 PatchedInc.HashLine = Inc.HashLine;
868 PatchedInc.HashOffset = Inc.HashOffset;
875 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
876 Patch << llvm::formatv(
877 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
883 PP.PreambleIncludes = Baseline.Includes.MainFileIncludes;
886 if (DirectivesChanged) {
898 for (
const auto &TD : ModifiedScan->TextualDirectives) {
901 if (TD.Directive == tok::pp_define)
902 Patch <<
"#undef " << TD.MacroName <<
'\n';
903 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
904 Patch << TD.Text <<
'\n';
908 PP.PatchedDiags =
patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan);
909 PP.PatchedMarks = std::move(ModifiedScan->Marks);
910 PP.PatchedMacros = std::move(ModifiedScan->Macros);
911 dlog(
"Created preamble patch: {0}", Patch.str());
934 CI.getTargetOpts() = *Baseline->TargetOpts;
937 if (PatchContents.empty())
939 auto &PPOpts = CI.getPreprocessorOpts();
943 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
945 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
948 PPOpts.Includes.push_back(PatchFileName);
952 return PreambleIncludes;
958 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
959 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
965 if (PatchContents.empty())
966 return Baseline->Marks;
971 if (PatchContents.empty())
972 return Baseline->Macros;
973 return PatchedMacros;
977 const SourceManager &SM) {
979 return SM.getFileManager().getOptionalFileRef(PatchFilePath);
983 const llvm::MemoryBufferRef &Buffer,
984 bool SkipPreambleBuild) {
985 return SkipPreambleBuild ? PreambleBounds(0,
false)
986 : ComputePreambleBounds(LangOpts, Buffer, 0);
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))
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
#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)
std::vector< std::string > getRequiredModuleNames(PathRef File)
Returns the list of directly required module names.
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)
PreambleBounds computePreambleBounds(const LangOptions &LangOpts, const llvm::MemoryBufferRef &Buffer, bool SkipPreambleBuild)
===– 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.