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, STABLE_ID, \
58 case clang::diag::ENUM: \
60#include "clang/Basic/DiagnosticASTKinds.inc"
61#include "clang/Basic/DiagnosticAnalysisKinds.inc"
62#include "clang/Basic/DiagnosticCommentKinds.inc"
63#include "clang/Basic/DiagnosticCommonKinds.inc"
64#include "clang/Basic/DiagnosticDriverKinds.inc"
65#include "clang/Basic/DiagnosticFrontendKinds.inc"
66#include "clang/Basic/DiagnosticLexKinds.inc"
67#include "clang/Basic/DiagnosticParseKinds.inc"
68#include "clang/Basic/DiagnosticRefactoringKinds.inc"
69#include "clang/Basic/DiagnosticSemaKinds.inc"
70#include "clang/Basic/DiagnosticSerializationKinds.inc"
77bool mentionsMainFile(
const Diag &D) {
83 for (
auto &N :
D.Notes) {
90bool isExcluded(
unsigned DiagID) {
92 if (DiagID == clang::diag::err_msasm_unable_to_create_target ||
93 DiagID == clang::diag::err_msasm_unsupported_arch)
100bool locationInRange(SourceLocation L, CharSourceRange R,
101 const SourceManager &M) {
102 assert(R.isCharRange());
103 if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
104 M.getFileID(R.getBegin()) != M.getFileID(L))
106 return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
111std::optional<Range> diagnosticRange(
const clang::Diagnostic &D,
112 const LangOptions &L) {
113 auto &M =
D.getSourceManager();
114 auto PatchedRange = [&M](CharSourceRange &R) {
119 auto Loc = M.getFileLoc(
D.getLocation());
120 for (
const auto &CR :
D.getRanges()) {
121 auto R = Lexer::makeFileCharRange(CR, M, L);
122 if (locationInRange(Loc, R, M))
126 for (
const auto &F :
D.getFixItHints()) {
127 auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L);
128 if (locationInRange(Loc, R, M))
134 auto [FID, Offset] = M.getDecomposedLoc(Loc);
135 if (Offset > M.getBufferData(FID).size())
139 auto R = CharSourceRange::getCharRange(Loc);
141 if (!Lexer::getRawToken(Loc, Tok, M, L,
true) && Tok.isNot(tok::comment))
142 R = CharSourceRange::getTokenRange(Tok.getLocation(), Tok.getEndLoc());
148const char *getMainFileRange(
const Diag &D,
const SourceManager &SM,
149 SourceLocation DiagLoc,
Range &R) {
151 for (
const auto &N :
D.Notes) {
152 if (N.InsideMainFile) {
154 case diag::note_template_class_instantiation_was_here:
155 case diag::note_template_class_explicit_specialization_was_here:
156 case diag::note_template_class_instantiation_here:
157 case diag::note_template_member_class_here:
158 case diag::note_template_member_function_here:
159 case diag::note_function_template_spec_here:
160 case diag::note_template_static_data_member_def_here:
161 case diag::note_template_variable_def_here:
162 case diag::note_template_enum_def_here:
163 case diag::note_template_nsdmi_here:
164 case diag::note_template_type_alias_instantiation_here:
165 case diag::note_template_exception_spec_instantiation_here:
166 case diag::note_template_requirement_instantiation_here:
167 case diag::note_evaluating_exception_spec_here:
168 case diag::note_default_arg_instantiation_here:
169 case diag::note_default_function_arg_instantiation_here:
170 case diag::note_explicit_template_arg_substitution_here:
171 case diag::note_function_template_deduction_instantiation_here:
172 case diag::note_deduced_template_arg_substitution_here:
173 case diag::note_prior_template_arg_substitution:
174 case diag::note_template_default_arg_checking:
175 case diag::note_concept_specialization_here:
176 case diag::note_nested_requirement_here:
177 case diag::note_checking_constraints_for_template_id_here:
178 case diag::note_checking_constraints_for_var_spec_id_here:
179 case diag::note_checking_constraints_for_class_spec_id_here:
180 case diag::note_checking_constraints_for_function_here:
181 case diag::note_constraint_substitution_here:
182 case diag::note_constraint_normalization_here:
183 case diag::note_parameter_mapping_substitution_here:
185 return "in template";
192 auto GetIncludeLoc = [&SM](SourceLocation SLoc) {
193 return SM.getIncludeLoc(SM.getFileID(SLoc));
195 for (
auto IncludeLocation = GetIncludeLoc(SM.getExpansionLoc(DiagLoc));
196 IncludeLocation.isValid();
197 IncludeLocation = GetIncludeLoc(IncludeLocation)) {
202 Lexer::getLocForEndOfToken(IncludeLocation, 0, SM, LangOptions()));
203 return "in included file";
213bool tryMoveToMainFile(
Diag &D, FullSourceLoc DiagLoc) {
214 const SourceManager &SM = DiagLoc.getManager();
215 DiagLoc = DiagLoc.getExpansionLoc();
217 const char *Prefix = getMainFileRange(D, SM, DiagLoc, R);
222 auto FE = *SM.getFileEntryRefForID(SM.getFileID(DiagLoc));
223 D.Notes.emplace(
D.Notes.begin());
224 Note &N =
D.Notes.front();
225 N.AbsFile = std::string(FE.getFileEntry().tryGetRealPathName());
226 N.File = std::string(FE.getName());
227 N.Message =
"error occurred here";
231 D.File = SM.getFileEntryRefForID(SM.getMainFileID())->getName().str();
232 D.Range = std::move(R);
233 D.InsideMainFile =
true;
235 D.Message = llvm::formatv(
"{0}: {1}", Prefix,
D.Message);
239bool isNote(DiagnosticsEngine::Level L) {
240 return L == DiagnosticsEngine::Note || L == DiagnosticsEngine::Remark;
243llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level Lvl) {
245 case DiagnosticsEngine::Ignored:
247 case DiagnosticsEngine::Note:
249 case DiagnosticsEngine::Remark:
251 case DiagnosticsEngine::Warning:
253 case DiagnosticsEngine::Error:
255 case DiagnosticsEngine::Fatal:
256 return "fatal error";
258 llvm_unreachable(
"unhandled DiagnosticsEngine::Level");
272void printDiag(llvm::raw_string_ostream &OS,
const DiagBase &D) {
273 if (
D.InsideMainFile) {
277 OS << llvm::sys::path::filename(
D.File) <<
":";
283 auto Pos =
D.Range.start;
284 OS << (Pos.line + 1) <<
":" << (Pos.character + 1) <<
":";
287 if (
D.InsideMainFile)
291 OS << diagLeveltoString(
D.Severity) <<
": " <<
D.Message;
295std::string capitalize(std::string Message) {
296 if (!Message.empty())
297 Message[0] = llvm::toUpper(Message[0]);
313 llvm::raw_string_ostream OS(Result);
315 if (Opts.DisplayFixesCount && !
D.Fixes.empty())
316 OS <<
" (" << (
D.Fixes.size() > 1 ?
"fixes" :
"fix") <<
" available)";
318 if (!Opts.EmitRelatedLocations)
319 for (
auto &
Note :
D.Notes) {
323 return capitalize(std::move(Result));
330 llvm::raw_string_ostream OS(Result);
334 if (!Opts.EmitRelatedLocations) {
338 return capitalize(std::move(Result));
341void setTags(clangd::Diag &D) {
342 static const auto *DeprecatedDiags =
new llvm::DenseSet<unsigned>{
343 diag::warn_access_decl_deprecated,
344 diag::warn_atl_uuid_deprecated,
345 diag::warn_deprecated,
346 diag::warn_deprecated_altivec_src_compat,
347 diag::warn_deprecated_comma_subscript,
348 diag::warn_deprecated_copy,
349 diag::warn_deprecated_copy_with_dtor,
350 diag::warn_deprecated_copy_with_user_provided_copy,
351 diag::warn_deprecated_copy_with_user_provided_dtor,
352 diag::warn_deprecated_def,
353 diag::warn_deprecated_increment_decrement_volatile,
354 diag::warn_deprecated_message,
355 diag::warn_deprecated_redundant_constexpr_static_def,
356 diag::warn_deprecated_register,
357 diag::warn_deprecated_simple_assign_volatile,
358 diag::warn_deprecated_string_literal_conversion,
359 diag::warn_deprecated_this_capture,
360 diag::warn_deprecated_volatile_param,
361 diag::warn_deprecated_volatile_return,
362 diag::warn_deprecated_volatile_structured_binding,
363 diag::warn_opencl_attr_deprecated_ignored,
364 diag::warn_property_method_deprecated,
365 diag::warn_vector_mode_deprecated,
367 static const auto *UnusedDiags =
new llvm::DenseSet<unsigned>{
368 diag::warn_opencl_attr_deprecated_ignored,
369 diag::warn_pragma_attribute_unused,
370 diag::warn_unused_but_set_parameter,
371 diag::warn_unused_but_set_variable,
372 diag::warn_unused_comparison,
373 diag::warn_unused_const_variable,
374 diag::warn_unused_exception_param,
375 diag::warn_unused_function,
376 diag::warn_unused_label,
377 diag::warn_unused_lambda_capture,
378 diag::warn_unused_local_typedef,
379 diag::warn_unused_member_function,
380 diag::warn_unused_parameter,
381 diag::warn_unused_private_field,
382 diag::warn_unused_property_backing_ivar,
383 diag::warn_unused_template,
384 diag::warn_unused_variable,
386 if (DeprecatedDiags->contains(
D.ID)) {
388 }
else if (UnusedDiags->contains(
D.ID)) {
392 if (llvm::StringRef(
D.Name).starts_with(
"misc-unused-"))
394 if (llvm::StringRef(
D.Name).starts_with(
"modernize-"))
402 if (!D.InsideMainFile)
404 OS << D.Range.start <<
"-" << D.Range.end <<
"] ";
406 return OS << D.Message;
411 const char *Sep =
"";
420 OS << static_cast<const DiagBase &>(D);
421 if (!D.Notes.empty()) {
423 const char *Sep =
"";
424 for (
auto &
Note : D.Notes) {
430 if (!D.Fixes.empty()) {
432 const char *Sep =
"";
433 for (
auto &
Fix : D.Fixes) {
444 Result.
Message = D.getMessage().str();
445 switch (D.getKind()) {
446 case llvm::SourceMgr::DK_Error:
447 Result.
Severity = DiagnosticsEngine::Error;
449 case llvm::SourceMgr::DK_Warning:
450 Result.
Severity = DiagnosticsEngine::Warning;
456 Result.
AbsFile = D.getFilename().str();
457 Result.
InsideMainFile = D.getSourceMgr()->FindBufferContainingLoc(
458 D.getLoc()) == D.getSourceMgr()->getMainFileID();
459 if (D.getRanges().empty())
460 Result.
Range = {{D.getLineNo() - 1, D.getColumnNo()},
461 {D.getLineNo() - 1, D.getColumnNo()}};
463 Result.
Range = {{D.getLineNo() - 1, (int)D.getRanges().front().first},
464 {D.getLineNo() - 1, (int)D.getRanges().front().second}};
477 if (D.Severity == DiagnosticsEngine::Warning) {
486 if (D.InsideMainFile) {
487 Main.
range = D.Range;
490 llvm::find_if(D.Notes, [](
const Note &N) { return N.InsideMainFile; });
491 assert(It != D.Notes.end() &&
492 "neither the main diagnostic nor notes are inside main file");
493 Main.
range = It->Range;
506 Main.
source =
"clang-tidy";
512 Main.
source =
"clangd-config";
520 Main.
message = mainMessage(D, Opts);
523 for (
auto &
Note : D.Notes) {
525 vlog(
"Dropping note from unknown file: {0}",
Note);
538 for (
auto &
Entry : D.OpaqueData)
540 OutFn(std::move(Main), D.Fixes);
545 for (
auto &
Note : D.Notes) {
552 OutFn(std::move(Res), llvm::ArrayRef<Fix>());
558 case DiagnosticsEngine::Remark:
560 case DiagnosticsEngine::Note:
562 case DiagnosticsEngine::Warning:
564 case DiagnosticsEngine::Fatal:
565 case DiagnosticsEngine::Error:
567 case DiagnosticsEngine::Ignored:
570 llvm_unreachable(
"Unknown diagnostic level!");
578 for (
auto &
Diag : Output) {
579 if (
const char *ClangDiag = getDiagnosticCode(
Diag.
ID)) {
583 return OrigSrcMgr->getDiagnostics()
585 ->getWarningOptionForDiag(
Diag.
ID);
587 if (!DiagnosticIDs::IsCustomDiag(
Diag.
ID))
588 return DiagnosticIDs{}.getWarningOptionForDiag(
Diag.
ID);
595 StringRef Name(ClangDiag);
598 Name.consume_front(
"err_");
602 }
else if (Tidy !=
nullptr) {
604 if (!TidyDiag.empty()) {
609 auto CleanMessage = [&](std::string &Msg) {
611 if (Rest.consume_back(
"]") && Rest.consume_back(
Diag.
Name) &&
612 Rest.consume_back(
" ["))
613 Msg.resize(Rest.size());
627 std::set<std::pair<Range, std::string>> SeenDiags;
628 llvm::erase_if(Output, [&](
const Diag &D) {
629 return !SeenDiags.emplace(D.Range, D.Message).second;
631 return std::move(Output);
635 const Preprocessor *PP) {
638 OrigSrcMgr = &PP->getSourceManager();
644 LangOpts = std::nullopt;
645 OrigSrcMgr =
nullptr;
651 constexpr unsigned MaxLen = 50;
657 llvm::StringRef R = Code.split(
'\n').first;
659 R = R.take_front(MaxLen);
662 if (R.size() != Code.size())
670 const clang::Diagnostic &
Info,
672 llvm::SmallString<64> Message;
673 Info.FormatDiagnostic(Message);
675 D.Message = std::string(Message);
676 D.Severity = DiagLevel;
677 D.Category = DiagnosticIDs::getCategoryNameFromID(
678 DiagnosticIDs::getCategoryNumberForDiag(
Info.getID()))
683 const clang::Diagnostic &
Info) {
688 if (OrigSrcMgr &&
Info.hasSourceManager() &&
689 OrigSrcMgr != &
Info.getSourceManager()) {
694 DiagnosticConsumer::HandleDiagnostic(DiagLevel,
Info);
695 bool OriginallyError =
696 Info.getDiags()->getDiagnosticIDs()->isDefaultMappingAsError(
699 if (
Info.getLocation().isInvalid()) {
702 if (!OriginallyError) {
711 LastDiagOriginallyError = OriginallyError;
712 LastDiag->ID =
Info.getID();
714 LastDiag->InsideMainFile =
true;
716 LastDiag->Range.start =
Position{0, 0};
717 LastDiag->Range.end =
Position{0, 0};
721 if (!LangOpts || !
Info.hasSourceManager()) {
726 SourceManager &SM =
Info.getSourceManager();
728 auto FillDiagBase = [&](
DiagBase &D) {
731 SourceLocation PatchLoc =
734 if (
auto DRange = diagnosticRange(
Info, *LangOpts))
737 D.Severity = DiagnosticsEngine::Ignored;
738 auto FID = SM.getFileID(
Info.getLocation());
739 if (
const auto FE = SM.getFileEntryRefForID(FID)) {
740 D.File = FE->getName().str();
747 auto AddFix = [&](
bool SyntheticMessage) ->
bool {
748 assert(!
Info.getFixItHints().empty() &&
749 "diagnostic does not have attached fix-its");
751 if (!LastDiag->InsideMainFile)
754 auto FixIts =
Info.getFixItHints().vec();
755 llvm::SmallVector<TextEdit, 1> Edits;
756 for (
auto &FixIt : FixIts) {
760 if (FixIt.RemoveRange.getBegin().isMacroID() &&
761 FixIt.RemoveRange.getEnd().isMacroID() &&
762 SM.getFileID(FixIt.RemoveRange.getBegin()) ==
763 SM.getFileID(FixIt.RemoveRange.getEnd())) {
764 FixIt.RemoveRange = CharSourceRange(
765 {SM.getTopMacroCallerLoc(FixIt.RemoveRange.getBegin()),
766 SM.getTopMacroCallerLoc(FixIt.RemoveRange.getEnd())},
767 FixIt.RemoveRange.isTokenRange());
770 if (FixIt.RemoveRange.getBegin().isMacroID() ||
771 FixIt.RemoveRange.getEnd().isMacroID())
775 Edits.push_back(
toTextEdit(FixIt, SM, *LangOpts));
778 llvm::SmallString<64> Message;
780 if (SyntheticMessage && FixIts.size() == 1) {
781 const auto &FixIt = FixIts.front();
782 bool Invalid =
false;
783 llvm::StringRef Remove =
784 Lexer::getSourceText(FixIt.RemoveRange, SM, *LangOpts, &Invalid);
785 llvm::StringRef Insert = FixIt.CodeToInsert;
787 llvm::raw_svector_ostream M(Message);
788 if (!Remove.empty() && !Insert.empty()) {
794 }
else if (!Remove.empty()) {
798 }
else if (!Insert.empty()) {
804 llvm::replace(Message,
'\n',
' ');
808 Info.FormatDiagnostic(Message);
809 LastDiag->Fixes.push_back(
810 Fix{std::string(Message), std::move(Edits), {}});
814 if (!isNote(DiagLevel)) {
821 DiagLevel = Adjuster(DiagLevel,
Info);
823 FillDiagBase(*LastDiag);
824 if (isExcluded(LastDiag->ID))
825 LastDiag->Severity = DiagnosticsEngine::Ignored;
827 DiagCB(
Info, *LastDiag);
829 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
832 LastDiagLoc.emplace(
Info.getLocation(),
Info.getSourceManager());
833 LastDiagOriginallyError = OriginallyError;
834 if (!
Info.getFixItHints().empty())
837 auto ExtraFixes = Fixer(LastDiag->Severity,
Info);
838 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ExtraFixes.begin(),
844 assert(
false &&
"Adding a note without main diagnostic");
851 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
856 auto ReplacementFixes = Fixer(LastDiag->Severity,
Info);
857 if (!ReplacementFixes.empty()) {
858 assert(
Info.getNumFixItHints() == 0 &&
859 "Include-fixer replaced a note with clang fix-its attached!");
860 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ReplacementFixes.begin(),
861 ReplacementFixes.end());
866 if (!
Info.getFixItHints().empty()) {
876 LastDiag->Notes.push_back(std::move(N));
881void StoreDiags::flushLastDiag() {
884 llvm::scope_exit Finish([&, NDiags(Output.size())] {
885 if (Output.size() == NDiags)
886 vlog(
"Dropped diagnostic: {0}: {1}", LastDiag->File, LastDiag->Message);
890 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
893 if (!LastDiag->InsideMainFile && LastDiagLoc && LastDiagOriginallyError) {
894 if (tryMoveToMainFile(*LastDiag, *LastDiagLoc)) {
896 if (!IncludedErrorLocations
897 .insert({LastDiag->Range.start.line,
898 LastDiag->Range.start.character})
903 if (!mentionsMainFile(*LastDiag))
905 Output.push_back(std::move(*LastDiag));
909 const llvm::StringSet<> &Suppress,
910 const LangOptions &LangOpts) {
914 if (
Diag.getID() == diag::pp_pragma_sysheader_in_main_file &&
915 LangOpts.IsHeaderFile)
918 if (
const char *CodePtr = getDiagnosticCode(
Diag.getID())) {
923 Diag.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
931 Code.consume_front(
"err_");
932 Code.consume_front(
"-W");
938 llvm::StringRef Name) {
953 std::tie(
Module, Check) = Name.split(
'-');
954 if (
Module.empty() || Check.empty())
956 return (
"https://clang.llvm.org/extra/clang-tidy/checks/" +
Module +
"/" +
961 if (Name ==
"unused-includes" || Name ==
"missing-includes")
962 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.