15#include "clang/Basic/AllDiagnostics.h"
16#include "clang/Basic/Diagnostic.h"
17#include "clang/Basic/DiagnosticIDs.h"
18#include "clang/Basic/LLVM.h"
19#include "clang/Basic/SourceLocation.h"
20#include "clang/Basic/SourceManager.h"
21#include "clang/Basic/TokenKinds.h"
22#include "clang/Lex/Lexer.h"
23#include "clang/Lex/Token.h"
24#include "llvm/ADT/ArrayRef.h"
25#include "llvm/ADT/DenseSet.h"
26#include "llvm/ADT/STLExtras.h"
27#include "llvm/ADT/STLFunctionalExtras.h"
28#include "llvm/ADT/ScopeExit.h"
29#include "llvm/ADT/SmallString.h"
30#include "llvm/ADT/SmallVector.h"
31#include "llvm/ADT/StringExtras.h"
32#include "llvm/ADT/StringRef.h"
33#include "llvm/ADT/StringSet.h"
34#include "llvm/ADT/Twine.h"
35#include "llvm/Support/ErrorHandling.h"
36#include "llvm/Support/FormatVariadic.h"
37#include "llvm/Support/Path.h"
38#include "llvm/Support/SourceMgr.h"
39#include "llvm/Support/raw_ostream.h"
53const char *getDiagnosticCode(
unsigned ID) {
55#define DIAG(ENUM, CLASS, DEFAULT_MAPPING, DESC, GROPU, SFINAE, NOWERROR, \
56 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
57 case clang::diag::ENUM: \
59#include "clang/Basic/DiagnosticASTKinds.inc"
60#include "clang/Basic/DiagnosticAnalysisKinds.inc"
61#include "clang/Basic/DiagnosticCommentKinds.inc"
62#include "clang/Basic/DiagnosticCommonKinds.inc"
63#include "clang/Basic/DiagnosticDriverKinds.inc"
64#include "clang/Basic/DiagnosticFrontendKinds.inc"
65#include "clang/Basic/DiagnosticLexKinds.inc"
66#include "clang/Basic/DiagnosticParseKinds.inc"
67#include "clang/Basic/DiagnosticRefactoringKinds.inc"
68#include "clang/Basic/DiagnosticSemaKinds.inc"
69#include "clang/Basic/DiagnosticSerializationKinds.inc"
76bool mentionsMainFile(
const Diag &D) {
82 for (
auto &N :
D.Notes) {
89bool isExcluded(
unsigned DiagID) {
91 if (DiagID == clang::diag::err_msasm_unable_to_create_target ||
92 DiagID == clang::diag::err_msasm_unsupported_arch)
99bool locationInRange(SourceLocation L, CharSourceRange R,
100 const SourceManager &M) {
101 assert(R.isCharRange());
102 if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
103 M.getFileID(R.getBegin()) != M.getFileID(L))
105 return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
110std::optional<Range> diagnosticRange(
const clang::Diagnostic &D,
111 const LangOptions &L) {
112 auto &M =
D.getSourceManager();
113 auto PatchedRange = [&M](CharSourceRange &R) {
118 auto Loc = M.getFileLoc(
D.getLocation());
119 for (
const auto &CR :
D.getRanges()) {
120 auto R = Lexer::makeFileCharRange(CR, M, L);
121 if (locationInRange(Loc, R, M))
125 for (
const auto &F :
D.getFixItHints()) {
126 auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L);
127 if (locationInRange(Loc, R, M))
133 auto [FID, Offset] = M.getDecomposedLoc(Loc);
134 if (Offset > M.getBufferData(FID).size())
138 auto R = CharSourceRange::getCharRange(Loc);
140 if (!Lexer::getRawToken(Loc, Tok, M, L,
true) && Tok.isNot(tok::comment))
141 R = CharSourceRange::getTokenRange(Tok.getLocation(), Tok.getEndLoc());
147const char *getMainFileRange(
const Diag &D,
const SourceManager &SM,
148 SourceLocation DiagLoc,
Range &R) {
150 for (
const auto &N :
D.Notes) {
151 if (N.InsideMainFile) {
153 case diag::note_template_class_instantiation_was_here:
154 case diag::note_template_class_explicit_specialization_was_here:
155 case diag::note_template_class_instantiation_here:
156 case diag::note_template_member_class_here:
157 case diag::note_template_member_function_here:
158 case diag::note_function_template_spec_here:
159 case diag::note_template_static_data_member_def_here:
160 case diag::note_template_variable_def_here:
161 case diag::note_template_enum_def_here:
162 case diag::note_template_nsdmi_here:
163 case diag::note_template_type_alias_instantiation_here:
164 case diag::note_template_exception_spec_instantiation_here:
165 case diag::note_template_requirement_instantiation_here:
166 case diag::note_evaluating_exception_spec_here:
167 case diag::note_default_arg_instantiation_here:
168 case diag::note_default_function_arg_instantiation_here:
169 case diag::note_explicit_template_arg_substitution_here:
170 case diag::note_function_template_deduction_instantiation_here:
171 case diag::note_deduced_template_arg_substitution_here:
172 case diag::note_prior_template_arg_substitution:
173 case diag::note_template_default_arg_checking:
174 case diag::note_concept_specialization_here:
175 case diag::note_nested_requirement_here:
176 case diag::note_checking_constraints_for_template_id_here:
177 case diag::note_checking_constraints_for_var_spec_id_here:
178 case diag::note_checking_constraints_for_class_spec_id_here:
179 case diag::note_checking_constraints_for_function_here:
180 case diag::note_constraint_substitution_here:
181 case diag::note_constraint_normalization_here:
182 case diag::note_parameter_mapping_substitution_here:
184 return "in template";
191 auto GetIncludeLoc = [&SM](SourceLocation SLoc) {
192 return SM.getIncludeLoc(SM.getFileID(SLoc));
194 for (
auto IncludeLocation = GetIncludeLoc(SM.getExpansionLoc(DiagLoc));
195 IncludeLocation.isValid();
196 IncludeLocation = GetIncludeLoc(IncludeLocation)) {
201 Lexer::getLocForEndOfToken(IncludeLocation, 0, SM, LangOptions()));
202 return "in included file";
212bool tryMoveToMainFile(
Diag &D, FullSourceLoc DiagLoc) {
213 const SourceManager &SM = DiagLoc.getManager();
214 DiagLoc = DiagLoc.getExpansionLoc();
216 const char *Prefix = getMainFileRange(D, SM, DiagLoc, R);
221 auto FE = *SM.getFileEntryRefForID(SM.getFileID(DiagLoc));
222 D.Notes.emplace(
D.Notes.begin());
223 Note &N =
D.Notes.front();
224 N.AbsFile = std::string(FE.getFileEntry().tryGetRealPathName());
225 N.File = std::string(FE.getName());
226 N.Message =
"error occurred here";
230 D.File = SM.getFileEntryRefForID(SM.getMainFileID())->getName().str();
231 D.Range = std::move(R);
232 D.InsideMainFile =
true;
234 D.Message = llvm::formatv(
"{0}: {1}", Prefix,
D.Message);
238bool isNote(DiagnosticsEngine::Level L) {
239 return L == DiagnosticsEngine::Note || L == DiagnosticsEngine::Remark;
242llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level Lvl) {
244 case DiagnosticsEngine::Ignored:
246 case DiagnosticsEngine::Note:
248 case DiagnosticsEngine::Remark:
250 case DiagnosticsEngine::Warning:
252 case DiagnosticsEngine::Error:
254 case DiagnosticsEngine::Fatal:
255 return "fatal error";
257 llvm_unreachable(
"unhandled DiagnosticsEngine::Level");
271void printDiag(llvm::raw_string_ostream &OS,
const DiagBase &D) {
272 if (
D.InsideMainFile) {
276 OS << llvm::sys::path::filename(
D.File) <<
":";
282 auto Pos =
D.Range.start;
283 OS << (Pos.line + 1) <<
":" << (Pos.character + 1) <<
":";
286 if (
D.InsideMainFile)
290 OS << diagLeveltoString(
D.Severity) <<
": " <<
D.Message;
294std::string capitalize(std::string Message) {
295 if (!Message.empty())
296 Message[0] = llvm::toUpper(Message[0]);
312 llvm::raw_string_ostream OS(Result);
314 if (Opts.DisplayFixesCount && !
D.Fixes.empty())
315 OS <<
" (" << (
D.Fixes.size() > 1 ?
"fixes" :
"fix") <<
" available)";
317 if (!Opts.EmitRelatedLocations)
318 for (
auto &
Note :
D.Notes) {
322 return capitalize(std::move(Result));
329 llvm::raw_string_ostream OS(Result);
333 if (!Opts.EmitRelatedLocations) {
337 return capitalize(std::move(Result));
340void setTags(clangd::Diag &D) {
341 static const auto *DeprecatedDiags =
new llvm::DenseSet<unsigned>{
342 diag::warn_access_decl_deprecated,
343 diag::warn_atl_uuid_deprecated,
344 diag::warn_deprecated,
345 diag::warn_deprecated_altivec_src_compat,
346 diag::warn_deprecated_comma_subscript,
347 diag::warn_deprecated_copy,
348 diag::warn_deprecated_copy_with_dtor,
349 diag::warn_deprecated_copy_with_user_provided_copy,
350 diag::warn_deprecated_copy_with_user_provided_dtor,
351 diag::warn_deprecated_def,
352 diag::warn_deprecated_increment_decrement_volatile,
353 diag::warn_deprecated_message,
354 diag::warn_deprecated_redundant_constexpr_static_def,
355 diag::warn_deprecated_register,
356 diag::warn_deprecated_simple_assign_volatile,
357 diag::warn_deprecated_string_literal_conversion,
358 diag::warn_deprecated_this_capture,
359 diag::warn_deprecated_volatile_param,
360 diag::warn_deprecated_volatile_return,
361 diag::warn_deprecated_volatile_structured_binding,
362 diag::warn_opencl_attr_deprecated_ignored,
363 diag::warn_property_method_deprecated,
364 diag::warn_vector_mode_deprecated,
366 static const auto *UnusedDiags =
new llvm::DenseSet<unsigned>{
367 diag::warn_opencl_attr_deprecated_ignored,
368 diag::warn_pragma_attribute_unused,
369 diag::warn_unused_but_set_parameter,
370 diag::warn_unused_but_set_variable,
371 diag::warn_unused_comparison,
372 diag::warn_unused_const_variable,
373 diag::warn_unused_exception_param,
374 diag::warn_unused_function,
375 diag::warn_unused_label,
376 diag::warn_unused_lambda_capture,
377 diag::warn_unused_local_typedef,
378 diag::warn_unused_member_function,
379 diag::warn_unused_parameter,
380 diag::warn_unused_private_field,
381 diag::warn_unused_property_backing_ivar,
382 diag::warn_unused_template,
383 diag::warn_unused_variable,
385 if (DeprecatedDiags->contains(
D.ID)) {
387 }
else if (UnusedDiags->contains(
D.ID)) {
391 if (llvm::StringRef(
D.Name).starts_with(
"misc-unused-"))
393 if (llvm::StringRef(
D.Name).starts_with(
"modernize-"))
401 if (!D.InsideMainFile)
403 OS << D.Range.start <<
"-" << D.Range.end <<
"] ";
405 return OS << D.Message;
410 const char *Sep =
"";
419 OS << static_cast<const DiagBase &>(D);
420 if (!D.Notes.empty()) {
422 const char *Sep =
"";
423 for (
auto &
Note : D.Notes) {
429 if (!D.Fixes.empty()) {
431 const char *Sep =
"";
432 for (
auto &
Fix : D.Fixes) {
443 Result.
Message = D.getMessage().str();
444 switch (D.getKind()) {
445 case llvm::SourceMgr::DK_Error:
446 Result.
Severity = DiagnosticsEngine::Error;
448 case llvm::SourceMgr::DK_Warning:
449 Result.
Severity = DiagnosticsEngine::Warning;
455 Result.
AbsFile = D.getFilename().str();
456 Result.
InsideMainFile = D.getSourceMgr()->FindBufferContainingLoc(
457 D.getLoc()) == D.getSourceMgr()->getMainFileID();
458 if (D.getRanges().empty())
459 Result.
Range = {{D.getLineNo() - 1, D.getColumnNo()},
460 {D.getLineNo() - 1, D.getColumnNo()}};
462 Result.
Range = {{D.getLineNo() - 1, (int)D.getRanges().front().first},
463 {D.getLineNo() - 1, (int)D.getRanges().front().second}};
476 if (D.Severity == DiagnosticsEngine::Warning) {
485 if (D.InsideMainFile) {
486 Main.
range = D.Range;
489 llvm::find_if(D.Notes, [](
const Note &N) { return N.InsideMainFile; });
490 assert(It != D.Notes.end() &&
491 "neither the main diagnostic nor notes are inside main file");
492 Main.
range = It->Range;
505 Main.
source =
"clang-tidy";
511 Main.
source =
"clangd-config";
519 Main.
message = mainMessage(D, Opts);
522 for (
auto &
Note : D.Notes) {
524 vlog(
"Dropping note from unknown file: {0}",
Note);
537 for (
auto &
Entry : D.OpaqueData)
539 OutFn(std::move(Main), D.Fixes);
544 for (
auto &
Note : D.Notes) {
551 OutFn(std::move(Res), llvm::ArrayRef<Fix>());
557 case DiagnosticsEngine::Remark:
559 case DiagnosticsEngine::Note:
561 case DiagnosticsEngine::Warning:
563 case DiagnosticsEngine::Fatal:
564 case DiagnosticsEngine::Error:
566 case DiagnosticsEngine::Ignored:
569 llvm_unreachable(
"Unknown diagnostic level!");
577 for (
auto &
Diag : Output) {
578 if (
const char *ClangDiag = getDiagnosticCode(
Diag.
ID)) {
582 return OrigSrcMgr->getDiagnostics()
584 ->getWarningOptionForDiag(
Diag.
ID);
586 if (!DiagnosticIDs::IsCustomDiag(
Diag.
ID))
587 return DiagnosticIDs{}.getWarningOptionForDiag(
Diag.
ID);
594 StringRef Name(ClangDiag);
597 Name.consume_front(
"err_");
601 }
else if (Tidy !=
nullptr) {
603 if (!TidyDiag.empty()) {
608 auto CleanMessage = [&](std::string &Msg) {
610 if (Rest.consume_back(
"]") && Rest.consume_back(
Diag.
Name) &&
611 Rest.consume_back(
" ["))
612 Msg.resize(Rest.size());
626 std::set<std::pair<Range, std::string>> SeenDiags;
627 llvm::erase_if(Output, [&](
const Diag &D) {
628 return !SeenDiags.emplace(D.Range, D.Message).second;
630 return std::move(Output);
634 const Preprocessor *PP) {
637 OrigSrcMgr = &PP->getSourceManager();
643 LangOpts = std::nullopt;
644 OrigSrcMgr =
nullptr;
650 constexpr unsigned MaxLen = 50;
656 llvm::StringRef R = Code.split(
'\n').first;
658 R = R.take_front(MaxLen);
661 if (R.size() != Code.size())
669 const clang::Diagnostic &
Info,
671 llvm::SmallString<64> Message;
672 Info.FormatDiagnostic(Message);
674 D.Message = std::string(Message);
675 D.Severity = DiagLevel;
676 D.Category = DiagnosticIDs::getCategoryNameFromID(
677 DiagnosticIDs::getCategoryNumberForDiag(
Info.getID()))
682 const clang::Diagnostic &
Info) {
687 if (OrigSrcMgr &&
Info.hasSourceManager() &&
688 OrigSrcMgr != &
Info.getSourceManager()) {
693 DiagnosticConsumer::HandleDiagnostic(DiagLevel,
Info);
694 bool OriginallyError =
695 Info.getDiags()->getDiagnosticIDs()->isDefaultMappingAsError(
698 if (
Info.getLocation().isInvalid()) {
701 if (!OriginallyError) {
710 LastDiagOriginallyError = OriginallyError;
711 LastDiag->ID =
Info.getID();
713 LastDiag->InsideMainFile =
true;
715 LastDiag->Range.start =
Position{0, 0};
716 LastDiag->Range.end =
Position{0, 0};
720 if (!LangOpts || !
Info.hasSourceManager()) {
725 SourceManager &SM =
Info.getSourceManager();
727 auto FillDiagBase = [&](
DiagBase &D) {
730 SourceLocation PatchLoc =
733 if (
auto DRange = diagnosticRange(
Info, *LangOpts))
736 D.Severity = DiagnosticsEngine::Ignored;
737 auto FID = SM.getFileID(
Info.getLocation());
738 if (
const auto FE = SM.getFileEntryRefForID(FID)) {
739 D.File = FE->getName().str();
746 auto AddFix = [&](
bool SyntheticMessage) ->
bool {
747 assert(!
Info.getFixItHints().empty() &&
748 "diagnostic does not have attached fix-its");
750 if (!LastDiag->InsideMainFile)
753 auto FixIts =
Info.getFixItHints().vec();
754 llvm::SmallVector<TextEdit, 1> Edits;
755 for (
auto &FixIt : FixIts) {
759 if (FixIt.RemoveRange.getBegin().isMacroID() &&
760 FixIt.RemoveRange.getEnd().isMacroID() &&
761 SM.getFileID(FixIt.RemoveRange.getBegin()) ==
762 SM.getFileID(FixIt.RemoveRange.getEnd())) {
763 FixIt.RemoveRange = CharSourceRange(
764 {SM.getTopMacroCallerLoc(FixIt.RemoveRange.getBegin()),
765 SM.getTopMacroCallerLoc(FixIt.RemoveRange.getEnd())},
766 FixIt.RemoveRange.isTokenRange());
769 if (FixIt.RemoveRange.getBegin().isMacroID() ||
770 FixIt.RemoveRange.getEnd().isMacroID())
774 Edits.push_back(
toTextEdit(FixIt, SM, *LangOpts));
777 llvm::SmallString<64> Message;
779 if (SyntheticMessage && FixIts.size() == 1) {
780 const auto &FixIt = FixIts.front();
781 bool Invalid =
false;
782 llvm::StringRef Remove =
783 Lexer::getSourceText(FixIt.RemoveRange, SM, *LangOpts, &Invalid);
784 llvm::StringRef Insert = FixIt.CodeToInsert;
786 llvm::raw_svector_ostream M(Message);
787 if (!Remove.empty() && !Insert.empty()) {
793 }
else if (!Remove.empty()) {
797 }
else if (!Insert.empty()) {
803 llvm::replace(Message,
'\n',
' ');
807 Info.FormatDiagnostic(Message);
808 LastDiag->Fixes.push_back(
809 Fix{std::string(Message), std::move(Edits), {}});
813 if (!isNote(DiagLevel)) {
820 DiagLevel = Adjuster(DiagLevel,
Info);
822 FillDiagBase(*LastDiag);
823 if (isExcluded(LastDiag->ID))
824 LastDiag->Severity = DiagnosticsEngine::Ignored;
826 DiagCB(
Info, *LastDiag);
828 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
831 LastDiagLoc.emplace(
Info.getLocation(),
Info.getSourceManager());
832 LastDiagOriginallyError = OriginallyError;
833 if (!
Info.getFixItHints().empty())
836 auto ExtraFixes = Fixer(LastDiag->Severity,
Info);
837 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ExtraFixes.begin(),
843 assert(
false &&
"Adding a note without main diagnostic");
850 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
855 auto ReplacementFixes = Fixer(LastDiag->Severity,
Info);
856 if (!ReplacementFixes.empty()) {
857 assert(
Info.getNumFixItHints() == 0 &&
858 "Include-fixer replaced a note with clang fix-its attached!");
859 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ReplacementFixes.begin(),
860 ReplacementFixes.end());
865 if (!
Info.getFixItHints().empty()) {
875 LastDiag->Notes.push_back(std::move(N));
880void StoreDiags::flushLastDiag() {
883 auto Finish = llvm::make_scope_exit([&, NDiags(Output.size())] {
884 if (Output.size() == NDiags)
885 vlog(
"Dropped diagnostic: {0}: {1}", LastDiag->File, LastDiag->Message);
889 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
892 if (!LastDiag->InsideMainFile && LastDiagLoc && LastDiagOriginallyError) {
893 if (tryMoveToMainFile(*LastDiag, *LastDiagLoc)) {
895 if (!IncludedErrorLocations
896 .insert({LastDiag->Range.start.line,
897 LastDiag->Range.start.character})
902 if (!mentionsMainFile(*LastDiag))
904 Output.push_back(std::move(*LastDiag));
908 const llvm::StringSet<> &Suppress,
909 const LangOptions &LangOpts) {
913 if (
Diag.getID() == diag::pp_pragma_sysheader_in_main_file &&
914 LangOpts.IsHeaderFile)
917 if (
const char *CodePtr = getDiagnosticCode(
Diag.getID())) {
922 Diag.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
930 Code.consume_front(
"err_");
931 Code.consume_front(
"-W");
937 llvm::StringRef Name) {
952 std::tie(
Module, Check) = Name.split(
'-');
953 if (
Module.empty() || Check.empty())
955 return (
"https://clang.llvm.org/extra/clang-tidy/checks/" +
Module +
"/" +
960 if (Name ==
"unused-includes" || Name ==
"missing-includes")
961 return {
"https://clangd.llvm.org/guides/include-cleaner"};
static void log(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info)
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override
std::vector< Diag > take(const clang::tidy::ClangTidyContext *Tidy=nullptr)
void BeginSourceFile(const LangOptions &Opts, const Preprocessor *PP) override
void EndSourceFile() override
A URI describes the location of a source file.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
std::string getCheckName(unsigned DiagnosticID) const
Returns the name of the clang-tidy check which produced this diagnostic ID.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
bool isDiagnosticSuppressed(const clang::Diagnostic &Diag, const llvm::StringSet<> &Suppress, const LangOptions &LangOpts)
Determine whether a (non-clang-tidy) diagnostic is suppressed by config.
static void writeCodeToFixMessage(llvm::raw_ostream &OS, llvm::StringRef Code)
Sanitizes a piece for presenting it in a synthesized fix message.
@ Warning
A warning message.
@ Info
An information message.
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M, const LangOptions &L)
static void fillNonLocationData(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info, clangd::DiagBase &D)
Fills D with all information, except the location-related bits.
void toLSPDiags(const Diag &D, const URIForFile &File, const ClangdDiagnosticOptions &Opts, llvm::function_ref< void(clangd::Diagnostic, llvm::ArrayRef< Fix >)> OutFn)
Conversion to LSP diagnostics.
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
void vlog(const char *Fmt, Ts &&... Vals)
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
SourceLocation translatePreamblePatchLocation(SourceLocation Loc, const SourceManager &SM)
Translates locations inside preamble patch to their main-file equivalent using presumed locations.
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
std::optional< std::string > getCanonicalPath(const FileEntryRef F, FileManager &FileMgr)
Get the canonical path of F.
llvm::StringRef normalizeSuppressedCode(llvm::StringRef Code)
Take a user-specified diagnostic code, and convert it to a normalized form stored in the config and c...
Diag toDiag(const llvm::SMDiagnostic &D, Diag::DiagSource Source)
int getSeverity(DiagnosticsEngine::Level L)
Convert from clang diagnostic level to LSP severity.
@ Deprecated
Deprecated or obsolete code.
@ Unnecessary
Unused or unnecessary code.
std::optional< std::string > getDiagnosticDocURI(Diag::DiagSource Source, unsigned ID, llvm::StringRef Name)
Returns a URI providing more information about a particular diagnostic.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
bool SendDiagnosticCategory
If true, Clangd uses an LSP extension to send the diagnostic's category to the client.
bool EmitRelatedLocations
If true, Clangd uses the relatedInformation field to include other locations (in particular attached ...
Contains basic information about a diagnostic.
DiagnosticsEngine::Level Severity
std::optional< std::string > AbsFile
A top-level diagnostic that may have Notes and Fixes.
std::vector< Fix > Fixes
Alternative fixes for this diagnostic, one should be chosen.
enum clang::clangd::Diag::DiagSource Source
std::vector< Note > Notes
Elaborate on the problem, usually pointing to a related piece of code.
std::optional< CodeDescription > codeDescription
An optional property to describe the error code.
llvm::json::Object data
A data entry field that is preserved between a textDocument/publishDiagnostics notification and textD...
std::optional< std::vector< DiagnosticRelatedInformation > > relatedInformation
An array of related diagnostic information, e.g.
std::string code
The diagnostic's code. Can be omitted.
Range range
The range at which the message applies.
std::string source
A human-readable string describing the source of this diagnostic, e.g.
std::string message
The diagnostic's message.
int severity
The diagnostic's severity.
std::optional< std::string > category
The diagnostic's category.
llvm::SmallVector< DiagnosticTag, 1 > tags
Additional metadata about the diagnostic.
A set of edits generated for a single file.
Represents a single fix-it that editor can apply to fix the error.
std::string Message
Message for the fix-it.
llvm::SmallVector< TextEdit, 1 > Edits
TextEdits from clang's fix-its. Must be non-empty.
URIForFile uri
The text document's URI.
Represents a note for the diagnostic.
A single C++ or preprocessor token.
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.