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 &)> BeforePPCallbacks,
94 std::function<
void(CompilerInstance &)> BeforeExecuteCallback)
95 : File(File), Stats(Stats),
96 ParseForwardingFunctions(ParseForwardingFunctions),
97 BeforePPCallbacks(std::move(BeforePPCallbacks)),
98 BeforeExecuteCallback(std::move(BeforeExecuteCallback)) {}
100 IncludeStructure takeIncludes() {
return std::move(Includes); }
102 MainFileMacros takeMacros() {
return std::move(Macros); }
104 std::vector<PragmaMark> takeMarks() {
return std::move(Marks); }
106 include_cleaner::PragmaIncludes takePragmaIncludes() {
107 return std::move(Pragmas);
110 std::optional<CapturedASTCtx> takeLife() {
return std::move(CapturedCtx); }
112 bool isMainFileIncludeGuarded()
const {
return IsMainFileIncludeGuarded; }
114 void AfterExecute(CompilerInstance &CI)
override {
119 if (CI.getASTReader()) {
120 CI.getASTReader()->setDeserializationListener(
nullptr);
122 CI.getASTReader()->StartTranslationUnit(
nullptr);
124 CI.getASTContext().setASTMutationListener(
nullptr);
125 CapturedCtx.emplace(CI);
127 const SourceManager &SM = CI.getSourceManager();
128 OptionalFileEntryRef MainFE = SM.getFileEntryRefForID(SM.getMainFileID());
129 IsMainFileIncludeGuarded =
130 CI.getPreprocessor().getHeaderSearchInfo().isFileMultipleIncludeGuarded(
134 const ASTContext &
AST = CI.getASTContext();
135 Stats->BuildSize =
AST.getASTAllocatedMemory();
136 Stats->BuildSize +=
AST.getSideTableAllocatedMemory();
137 Stats->BuildSize +=
AST.Idents.getAllocator().getTotalMemory();
138 Stats->BuildSize +=
AST.Selectors.getTotalMemory();
140 Stats->BuildSize +=
AST.getSourceManager().getContentCacheSize();
141 Stats->BuildSize +=
AST.getSourceManager().getDataStructureSizes();
143 AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
145 const Preprocessor &PP = CI.getPreprocessor();
146 Stats->BuildSize += PP.getTotalMemory();
147 if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
148 Stats->BuildSize += PRec->getTotalMemory();
149 Stats->BuildSize += PP.getHeaderSearchInfo().getTotalMemory();
153 void BeforeExecute(CompilerInstance &CI)
override {
154 LangOpts = &CI.getLangOpts();
155 SourceMgr = &CI.getSourceManager();
156 PP = &CI.getPreprocessor();
157 if (BeforePPCallbacks)
158 BeforePPCallbacks(CI);
159 Includes.collect(CI);
161 if (BeforeExecuteCallback)
162 BeforeExecuteCallback(CI);
165 std::unique_ptr<PPCallbacks> createPPCallbacks()
override {
166 assert(SourceMgr && LangOpts && PP &&
167 "SourceMgr, LangOpts and PP must be set at this point");
169 return std::make_unique<PPChainedCallbacks>(
170 std::make_unique<CollectMainFileMacros>(*PP, Macros),
174 bool shouldSkipFunctionBody(Decl *D)
override {
182 if (
auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D)) {
183 if (ParseForwardingFunctions) {
190 if (
const auto *II = FT->getDeclName().getAsIdentifierInfo()) {
191 if (II->isStr(
"make_unique") && FT->isInStdNamespace())
201 IncludeStructure Includes;
202 include_cleaner::PragmaIncludes Pragmas;
203 MainFileMacros Macros;
204 std::vector<PragmaMark> Marks;
205 bool IsMainFileIncludeGuarded =
false;
206 const clang::LangOptions *LangOpts =
nullptr;
207 const SourceManager *SourceMgr =
nullptr;
208 const Preprocessor *PP =
nullptr;
209 PreambleBuildStats *Stats;
210 bool ParseForwardingFunctions;
211 std::function<void(CompilerInstance &)> BeforePPCallbacks;
212 std::function<void(CompilerInstance &)> BeforeExecuteCallback;
213 std::optional<CapturedASTCtx> CapturedCtx;
218struct TextualPPDirective {
219 unsigned DirectiveLine;
223 tok::PPKeywordKind Directive = tok::PPKeywordKind::pp_not_keyword;
225 std::string MacroName;
227 bool operator==(
const TextualPPDirective &RHS)
const {
228 return std::tie(DirectiveLine, Offset, Text) ==
229 std::tie(RHS.DirectiveLine, RHS.Offset, RHS.Text);
236std::string spellDirective(llvm::StringRef Prefix,
237 CharSourceRange DirectiveRange,
238 const LangOptions &LangOpts,
const SourceManager &SM,
239 unsigned &DirectiveLine,
unsigned &Offset) {
240 std::string SpelledDirective;
241 llvm::raw_string_ostream OS(SpelledDirective);
245 DirectiveRange = SM.getExpansionRange(DirectiveRange);
246 if (DirectiveRange.isTokenRange()) {
247 DirectiveRange.setEnd(
248 Lexer::getLocForEndOfToken(DirectiveRange.getEnd(), 0, SM, LangOpts));
251 auto DecompLoc = SM.getDecomposedLoc(DirectiveRange.getBegin());
252 DirectiveLine = SM.getLineNumber(DecompLoc.first, DecompLoc.second);
253 Offset = DecompLoc.second;
254 auto TargetColumn = SM.getColumnNumber(DecompLoc.first, DecompLoc.second) - 1;
258 if (Prefix.size() <= TargetColumn) {
262 OS << std::string(TargetColumn - Prefix.size(),
' ');
268 OS <<
"\\\n" << std::string(TargetColumn,
' ');
278struct DirectiveCollector :
public PPCallbacks {
279 DirectiveCollector(
const Preprocessor &PP,
280 std::vector<TextualPPDirective> &TextualDirectives)
281 : LangOpts(PP.getLangOpts()), SM(PP.getSourceManager()),
282 TextualDirectives(TextualDirectives) {}
284 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
285 SrcMgr::CharacteristicKind FileType,
286 FileID PrevFID)
override {
287 InMainFile = SM.isWrittenInMainFile(Loc);
290 void MacroDefined(
const Token &MacroNameTok,
291 const MacroDirective *
MD)
override {
294 TextualDirectives.emplace_back();
295 TextualPPDirective &TD = TextualDirectives.back();
296 TD.Directive = tok::pp_define;
297 TD.MacroName = MacroNameTok.getIdentifierInfo()->getName().str();
299 const auto *MI =
MD->getMacroInfo();
301 spellDirective(
"#define ",
302 CharSourceRange::getTokenRange(
303 MI->getDefinitionLoc(), MI->getDefinitionEndLoc()),
304 LangOpts, SM, TD.DirectiveLine, TD.Offset);
308 bool InMainFile =
true;
309 const LangOptions &LangOpts;
310 const SourceManager &SM;
311 std::vector<TextualPPDirective> &TextualDirectives;
314struct ScannedPreamble {
315 std::vector<Inclusion> Includes;
316 std::vector<TextualPPDirective> TextualDirectives;
318 std::vector<llvm::StringRef> Lines;
319 PreambleBounds Bounds = {0,
false};
320 std::vector<PragmaMark> Marks;
321 MainFileMacros Macros;
328llvm::Expected<ScannedPreamble> scanPreamble(llvm::StringRef Contents,
329 const tooling::CompileCommand &Cmd,
330 bool SkipPreambleBuild) {
333 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl()
const override {
334 return new llvm::vfs::InMemoryFileSystem;
344 PI.CompileCommand = Cmd;
345 IgnoringDiagConsumer IgnoreDiags;
348 return error(
"failed to create compiler invocation");
349 CI->getDiagnosticOpts().IgnoreWarnings =
true;
350 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(PI.Contents);
356 auto PreambleContents = llvm::MemoryBuffer::getMemBufferCopy(
357 llvm::StringRef(PI.Contents).take_front(Bounds.Size));
359 std::move(CI),
nullptr, std::move(PreambleContents),
362 FS.view(std::nullopt), IgnoreDiags);
363 if (Clang->getFrontendOpts().Inputs.empty())
364 return error(
"compiler instance had no inputs");
366 Clang->getPreprocessorOpts().SingleFileParseMode =
true;
367 Clang->getPreprocessorOpts().UsePredefines =
false;
368 PreprocessOnlyAction Action;
369 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
370 return error(
"failed BeginSourceFile");
371 Preprocessor &PP = Clang->getPreprocessor();
372 const auto &SM = PP.getSourceManager();
378 std::make_unique<DirectiveCollector>(PP, SP.TextualDirectives));
380 PP.addPPCallbacks(std::make_unique<CollectMainFileMacros>(PP, SP.Macros));
381 if (llvm::Error Err = Action.Execute())
382 return std::move(Err);
383 Action.EndSourceFile();
384 SP.Includes = std::move(Includes.MainFileIncludes);
385 llvm::append_range(SP.Lines, llvm::split(Contents,
"\n"));
389const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) {
390 switch (IncludeDirective) {
391 case tok::pp_include:
395 case tok::pp_include_next:
396 return "include_next";
400 llvm_unreachable(
"not an include directive");
409 WallTimer() : TotalTime(std::chrono::steady_clock::duration::zero()) {}
411 void startTimer() { StartTime = std::chrono::steady_clock::now(); }
414 TotalTime += std::chrono::steady_clock::now() - StartTime;
417 double getTime() {
return std::chrono::duration<double>(TotalTime).count(); }
420 std::chrono::steady_clock::duration TotalTime;
421 std::chrono::steady_clock::time_point StartTime;
424class WallTimerRegion {
426 WallTimerRegion(WallTimer &T) : T(T) { T.startTimer(); }
427 ~WallTimerRegion() { T.stopTimer(); }
435class TimerFile :
public llvm::vfs::File {
437 TimerFile(WallTimer &Timer, std::unique_ptr<File> InnerFile)
438 : Timer(Timer), InnerFile(std::move(InnerFile)) {}
440 llvm::ErrorOr<llvm::vfs::Status> status()
override {
441 WallTimerRegion
T(Timer);
442 return InnerFile->status();
444 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
445 getBuffer(
const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator,
446 bool IsVolatile)
override {
447 WallTimerRegion
T(Timer);
448 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
451 std::error_code close()
override {
452 WallTimerRegion
T(Timer);
453 return InnerFile->close();
458 std::unique_ptr<llvm::vfs::File> InnerFile;
463class TimerFS :
public llvm::vfs::ProxyFileSystem {
465 TimerFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
466 : ProxyFileSystem(std::move(FS)) {}
468 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
469 openFileForRead(
const llvm::Twine &
Path)
override {
470 WallTimerRegion
T(Timer);
471 auto FileOr = getUnderlyingFS().openFileForRead(
Path);
474 return std::make_unique<TimerFile>(Timer, std::move(FileOr.get()));
477 llvm::ErrorOr<llvm::vfs::Status> status(
const llvm::Twine &
Path)
override {
478 WallTimerRegion
T(Timer);
479 return getUnderlyingFS().status(
Path);
482 double getTime() {
return Timer.getTime(); }
490 llvm::ArrayRef<llvm::StringRef> OldLines;
491 llvm::ArrayRef<llvm::StringRef> CurrentLines;
492 llvm::StringMap<llvm::SmallVector<int>> CurrentContentsToLine;
498 bool translateRange(Range &R) {
499 int OldStart = R.start.line;
500 int OldEnd = R.end.line;
501 assert(OldStart <= OldEnd);
503 size_t RangeLen = OldEnd - OldStart + 1;
504 auto RangeContents = OldLines.slice(OldStart).take_front(RangeLen);
506 if (RangeContents.size() < RangeLen)
509 std::optional<int> Closest;
510 for (
int AlternateLine : CurrentContentsToLine.lookup(RangeContents[0])) {
513 CurrentLines.slice(AlternateLine).take_front(RangeLen))
515 int Delta = AlternateLine - OldStart;
516 if (!Closest.has_value() || abs(Delta) < abs(*Closest))
520 if (!Closest.has_value())
522 R.start.line += *Closest;
523 R.end.line += *Closest;
529 bool translateNote(Note &N) {
530 if (!N.InsideMainFile)
532 if (translateRange(N.Range))
539 bool translateFix(
Fix &F) {
541 F.Edits, [
this](TextEdit &E) { return translateRange(E.range); });
545 DiagPatcher(llvm::ArrayRef<llvm::StringRef> OldLines,
546 llvm::ArrayRef<llvm::StringRef> CurrentLines) {
547 this->OldLines = OldLines;
548 this->CurrentLines = CurrentLines;
549 for (
int Line = 0, E = CurrentLines.size(); Line != E; ++Line) {
550 llvm::StringRef Contents = CurrentLines[Line];
551 CurrentContentsToLine[Contents].push_back(Line);
558 std::optional<Diag> translateDiag(
const Diag &D) {
559 Range NewRange =
D.Range;
561 if (
D.InsideMainFile && !translateRange(NewRange)) {
567 NewD.Range = NewRange;
570 llvm::erase_if(NewD.Notes, [
this](Note &N) { return !translateNote(N); });
571 llvm::erase_if(NewD.Fixes, [
this](
Fix &F) { return !translateFix(F); });
577std::shared_ptr<const PreambleData>
584 auto ContentsBuffer =
585 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
591 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
594 if (
auto Listener = M.astListeners())
595 ASTListeners.emplace_back(std::move(Listener));
601 for (
const auto &L : ASTListeners)
602 L->sawDiagnostic(D,
Diag);
605 for (
const auto &L : ASTListeners)
606 L->finalizeDiagnostic(
Diag);
609 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
610 CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
611 &PreambleDiagnostics,
613 PreambleDiagnostics.
setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
614 const clang::Diagnostic &
Info) {
615 switch (
Info.getID()) {
616 case diag::warn_no_newline_eof:
619 return Bounds.Size != ContentsBuffer->getBufferSize()
620 ? DiagnosticsEngine::Level::Ignored
628 assert(!CI.getFrontendOpts().SkipFunctionBodies);
629 CI.getFrontendOpts().SkipFunctionBodies =
true;
632 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
634 CppFilePreambleCallbacks CapturedInfo(
636 [&ASTListeners](CompilerInstance &CI) {
637 for (const auto &L : ASTListeners)
638 L->beforePPCallbacks(CI);
640 [&ASTListeners](CompilerInstance &CI) {
641 for (const auto &L : ASTListeners)
642 L->beforeExecute(CI);
644 llvm::SmallString<32> AbsFileName(FileName);
645 VFS->makeAbsolute(AbsFileName);
646 auto StatCache = std::make_shared<PreambleFileStatusCache>(AbsFileName);
647 auto StatCacheFS = StatCache->getProducingFS(VFS);
648 llvm::IntrusiveRefCntPtr<TimerFS> TimedFS(
new TimerFS(StatCacheFS));
650 WallTimer PreambleTimer;
651 PreambleTimer.startTimer();
652 auto BuiltPreamble = PrecompiledPreamble::Build(
653 CI, ContentsBuffer.get(), Bounds, PreambleDiagsEngine,
654 Stats ? TimedFS : StatCacheFS, std::make_shared<PCHContainerOperations>(),
655 StoreInMemory,
"", CapturedInfo);
657 PreambleTimer.stopTimer();
661 PreambleDiagsEngine->setClient(
new IgnoringDiagConsumer,
true);
664 PreambleDiagsEngine.reset();
668 CI.getFrontendOpts().SkipFunctionBodies =
false;
670 if (Stats !=
nullptr) {
673 Stats->
SerializedSize = BuiltPreamble ? BuiltPreamble->getSize() : 0;
677 log(
"Built preamble of size {0} for file {1} version {2} in {3} seconds",
678 BuiltPreamble->getSize(), FileName, Inputs.
Version,
679 PreambleTimer.getTime());
680 std::vector<Diag> Diags = PreambleDiagnostics.
take();
681 auto Result = std::make_shared<PreambleData>(std::move(*BuiltPreamble));
682 Result->Version = Inputs.
Version;
684 Result->Diags = std::move(Diags);
685 Result->Includes = CapturedInfo.takeIncludes();
686 Result->Pragmas = std::make_shared<const include_cleaner::PragmaIncludes>(
687 CapturedInfo.takePragmaIncludes());
690 WallTimer PrerequisiteModuleTimer;
691 PrerequisiteModuleTimer.startTimer();
692 Result->RequiredModules =
695 PrerequisiteModuleTimer.stopTimer();
697 log(
"Built prerequisite modules for file {0} in {1} seconds", FileName,
698 PrerequisiteModuleTimer.getTime());
701 Result->Macros = CapturedInfo.takeMacros();
702 Result->Marks = CapturedInfo.takeMarks();
703 Result->StatCache = std::move(StatCache);
704 Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
708 std::make_unique<TargetOptions>(std::move(CI.getTargetOpts()));
709 if (PreambleCallback) {
711 auto Ctx = CapturedInfo.takeLife();
714 Ctx->getFileManager().setVirtualFileSystem(
715 Result->StatCache->getConsumingFS(VFS));
718 Ctx->setStatCache(Result->StatCache);
720 PreambleCallback(std::move(*Ctx), Result->Pragmas);
725 elog(
"Could not build a preamble for file {0} version {1}: {2}", FileName,
726 Inputs.
Version, BuiltPreamble.getError().message());
727 for (
const Diag &D : PreambleDiagnostics.
take()) {
728 if (D.Severity < DiagnosticsEngine::Error)
731 elog(
" error: {0}", D.Message);
738 const CompilerInvocation &CI) {
739 auto ContentsBuffer =
740 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
749 auto RequiredModulesMatch = [&]() ->
bool {
753 llvm::StringSet<> NewNameSet;
754 NewNameSet.insert_range(NewNames);
755 return NewNameSet ==
Preamble.RequiredModules->getRequiredModuleNames();
760 Preamble.Preamble.CanReuse(CI, *ContentsBuffer, Bounds, *VFS) &&
762 Preamble.RequiredModules->canReuse(CI, VFS)) &&
763 RequiredModulesMatch();
767 for (
char C :
Text) {
782static std::vector<Diag>
patchDiags(llvm::ArrayRef<Diag> BaselineDiags,
783 const ScannedPreamble &BaselineScan,
784 const ScannedPreamble &ModifiedScan) {
785 std::vector<Diag> PatchedDiags;
786 if (BaselineDiags.empty())
788 DiagPatcher Patcher(BaselineScan.Lines, ModifiedScan.Lines);
789 for (
auto &D : BaselineDiags) {
790 if (
auto NewD = Patcher.translateDiag(D))
791 PatchedDiags.emplace_back(std::move(*NewD));
798 llvm::SmallString<128> PatchName;
799 llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName),
801 return PatchName.str().str();
804PreamblePatch PreamblePatch::create(llvm::StringRef FileName,
805 const ParseInputs &Modified,
806 const PreambleData &Baseline,
807 PatchType PatchType) {
808 trace::Span Tracer(
"CreatePreamblePatch");
810 assert(llvm::sys::path::is_absolute(FileName) &&
"relative FileName!");
820 scanPreamble(Baseline.Preamble.getContents(), Modified.CompileCommand,
821 Modified.Opts.SkipPreambleBuild);
823 elog(
"Failed to scan baseline of {0}: {1}", FileName,
824 BaselineScan.takeError());
827 auto ModifiedScan = scanPreamble(Modified.Contents, Modified.CompileCommand,
828 Modified.Opts.SkipPreambleBuild);
830 elog(
"Failed to scan modified contents of {0}: {1}", FileName,
831 ModifiedScan.takeError());
835 bool IncludesChanged = BaselineScan->Includes != ModifiedScan->Includes;
836 bool DirectivesChanged =
837 BaselineScan->TextualDirectives != ModifiedScan->TextualDirectives;
843 PP.Baseline = &Baseline;
845 PP.ModifiedBounds = ModifiedScan->Bounds;
847 llvm::raw_string_ostream Patch(PP.PatchContents);
849 Patch <<
"#line 0 \"";
858 llvm::DenseMap<std::pair<tok::PPKeywordKind, llvm::StringRef>,
861 for (
const auto &Inc : Baseline.Includes.MainFileIncludes)
862 ExistingIncludes[{Inc.Directive, Inc.Written}] = &Inc;
865 for (
const auto &Inc : BaselineScan->Includes)
866 ExistingIncludes.try_emplace({Inc.Directive, Inc.Written});
868 for (
auto &Inc : ModifiedScan->Includes) {
869 auto It = ExistingIncludes.find({Inc.Directive, Inc.Written});
872 if (It != ExistingIncludes.end()) {
876 auto &PatchedInc = PP.PreambleIncludes.emplace_back();
879 PatchedInc = *It->second;
880 PatchedInc.HashLine = Inc.HashLine;
881 PatchedInc.HashOffset = Inc.HashOffset;
888 Patch << llvm::formatv(
"#line {0}\n", LineCol.first);
889 Patch << llvm::formatv(
890 "#{0} {1}\n", spellingForIncDirective(Inc.Directive), Inc.Written);
896 PP.PreambleIncludes = Baseline.Includes.MainFileIncludes;
899 if (DirectivesChanged) {
911 for (
const auto &TD : ModifiedScan->TextualDirectives) {
914 if (TD.Directive == tok::pp_define)
915 Patch <<
"#undef " << TD.MacroName <<
'\n';
916 Patch <<
"#line " << TD.DirectiveLine <<
'\n';
917 Patch << TD.Text <<
'\n';
921 PP.PatchedDiags =
patchDiags(Baseline.Diags, *BaselineScan, *ModifiedScan);
922 PP.PatchedMarks = std::move(ModifiedScan->Marks);
923 PP.PatchedMacros = std::move(ModifiedScan->Macros);
924 dlog(
"Created preamble patch: {0}", Patch.str());
947 CI.getTargetOpts() = *Baseline->TargetOpts;
950 if (PatchContents.empty())
952 auto &PPOpts = CI.getPreprocessorOpts();
956 llvm::MemoryBuffer::getMemBufferCopy(PatchContents, PatchFileName);
958 PPOpts.addRemappedFile(PatchFileName, PatchBuffer.release());
961 PPOpts.Includes.push_back(PatchFileName);
965 return PreambleIncludes;
971 PP.PreambleIncludes =
Preamble.Includes.MainFileIncludes;
972 PP.ModifiedBounds =
Preamble.Preamble.getBounds();
978 if (PatchContents.empty())
979 return Baseline->Marks;
984 if (PatchContents.empty())
985 return Baseline->Macros;
986 return PatchedMacros;
990 const SourceManager &SM) {
992 return SM.getFileManager().getOptionalFileRef(PatchFilePath);
996 const llvm::MemoryBufferRef &Buffer,
997 bool SkipPreambleBuild) {
998 return SkipPreambleBuild ? PreambleBounds(0,
false)
999 : 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 Markdown 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 setDiagFinalizer(DiagFinalizer F)
Invokes a callback after notes and fixes have been attached.
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 when a main diagnostic is first formed, before notes and fixes are attached.
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.