10#include "../clang-tidy/ClangTidyDiagnosticConsumer.h"
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))
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) {
296 Message[0] = llvm::toUpper(Message[0]);
310std::string mainMessage(
const Diag &D,
const ClangdDiagnosticOptions &Opts) {
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) {
323 return capitalize(std::move(Result));
327std::string noteMessage(
const Diag &Main,
const DiagBase &Note,
328 const ClangdDiagnosticOptions &Opts) {
330 llvm::raw_string_ostream
OS(Result);
334 if (!Opts.EmitRelatedLocations) {
339 return capitalize(std::move(Result));
342void setTags(clangd::Diag &D) {
343 static const auto *DeprecatedDiags =
new llvm::DenseSet<unsigned>{
344 diag::warn_access_decl_deprecated,
345 diag::warn_atl_uuid_deprecated,
346 diag::warn_deprecated,
347 diag::warn_deprecated_altivec_src_compat,
348 diag::warn_deprecated_comma_subscript,
349 diag::warn_deprecated_copy,
350 diag::warn_deprecated_copy_with_dtor,
351 diag::warn_deprecated_copy_with_user_provided_copy,
352 diag::warn_deprecated_copy_with_user_provided_dtor,
353 diag::warn_deprecated_def,
354 diag::warn_deprecated_increment_decrement_volatile,
355 diag::warn_deprecated_message,
356 diag::warn_deprecated_redundant_constexpr_static_def,
357 diag::warn_deprecated_register,
358 diag::warn_deprecated_simple_assign_volatile,
359 diag::warn_deprecated_string_literal_conversion,
360 diag::warn_deprecated_this_capture,
361 diag::warn_deprecated_volatile_param,
362 diag::warn_deprecated_volatile_return,
363 diag::warn_deprecated_volatile_structured_binding,
364 diag::warn_opencl_attr_deprecated_ignored,
365 diag::warn_property_method_deprecated,
366 diag::warn_vector_mode_deprecated,
368 static const auto *UnusedDiags =
new llvm::DenseSet<unsigned>{
369 diag::warn_opencl_attr_deprecated_ignored,
370 diag::warn_pragma_attribute_unused,
371 diag::warn_unused_but_set_parameter,
372 diag::warn_unused_but_set_variable,
373 diag::warn_unused_comparison,
374 diag::warn_unused_const_variable,
375 diag::warn_unused_exception_param,
376 diag::warn_unused_function,
377 diag::warn_unused_label,
378 diag::warn_unused_lambda_capture,
379 diag::warn_unused_local_typedef,
380 diag::warn_unused_member_function,
381 diag::warn_unused_parameter,
382 diag::warn_unused_private_field,
383 diag::warn_unused_property_backing_ivar,
384 diag::warn_unused_template,
385 diag::warn_unused_variable,
387 if (DeprecatedDiags->contains(D.ID)) {
389 }
else if (UnusedDiags->contains(D.ID)) {
393 if (llvm::StringRef(D.Name).starts_with(
"misc-unused-"))
395 if (llvm::StringRef(D.Name).starts_with(
"modernize-"))
403 if (!D.InsideMainFile)
405 OS << D.Range.start <<
"-" << D.Range.end <<
"] ";
407 return OS << D.Message;
411 OS << F.Message <<
" {";
412 const char *Sep =
"";
413 for (
const auto &
Edit : F.Edits) {
421 OS << static_cast<const DiagBase &>(D);
422 if (!D.Notes.empty()) {
424 const char *Sep =
"";
425 for (
auto &
Note : D.Notes) {
431 if (!D.Fixes.empty()) {
433 const char *Sep =
"";
434 for (
auto &
Fix : D.Fixes) {
445 Result.Message = D.getMessage().str();
446 switch (D.getKind()) {
447 case llvm::SourceMgr::DK_Error:
448 Result.Severity = DiagnosticsEngine::Error;
450 case llvm::SourceMgr::DK_Warning:
451 Result.Severity = DiagnosticsEngine::Warning;
456 Result.Source = Source;
457 Result.AbsFile = D.getFilename().str();
458 Result.InsideMainFile = D.getSourceMgr()->FindBufferContainingLoc(
459 D.getLoc()) == D.getSourceMgr()->getMainFileID();
460 if (D.getRanges().empty())
461 Result.Range = {{D.getLineNo() - 1, D.getColumnNo()},
462 {D.getLineNo() - 1, D.getColumnNo()}};
464 Result.Range = {{D.getLineNo() - 1, (int)D.getRanges().front().first},
465 {D.getLineNo() - 1, (int)D.getRanges().front().second}};
478 if (D.Severity == DiagnosticsEngine::Warning) {
487 if (D.InsideMainFile) {
488 Main.
range = D.Range;
491 llvm::find_if(D.Notes, [](
const Note &N) { return N.InsideMainFile; });
492 assert(It != D.Notes.end() &&
493 "neither the main diagnostic nor notes are inside main file");
494 Main.
range = It->Range;
507 Main.
source =
"clang-tidy";
513 Main.
source =
"clangd-config";
518 if (Opts.SendDiagnosticCategory && !D.Category.empty())
521 Main.
message = mainMessage(D, Opts);
522 if (Opts.EmitRelatedLocations) {
524 for (
auto &
Note : D.Notes) {
526 vlog(
"Dropping note from unknown file: {0}",
Note);
539 for (
auto &
Entry : D.OpaqueData)
541 OutFn(std::move(Main), D.Fixes);
545 if (!Opts.EmitRelatedLocations)
546 for (
auto &
Note : D.Notes) {
553 OutFn(std::move(Res), llvm::ArrayRef<Fix>());
559 case DiagnosticsEngine::Remark:
561 case DiagnosticsEngine::Note:
563 case DiagnosticsEngine::Warning:
565 case DiagnosticsEngine::Fatal:
566 case DiagnosticsEngine::Error:
568 case DiagnosticsEngine::Ignored:
571 llvm_unreachable(
"Unknown diagnostic level!");
579 for (
auto &
Diag : Output) {
580 if (
const char *ClangDiag = getDiagnosticCode(
Diag.
ID)) {
582 StringRef
Warning = DiagnosticIDs::getWarningOptionForDiag(
Diag.
ID);
586 StringRef
Name(ClangDiag);
589 Name.consume_front(
"err_");
593 }
else if (Tidy !=
nullptr) {
595 if (!TidyDiag.empty()) {
600 auto CleanMessage = [&](std::string &Msg) {
602 if (Rest.consume_back(
"]") && Rest.consume_back(
Diag.
Name) &&
603 Rest.consume_back(
" ["))
604 Msg.resize(Rest.size());
618 std::set<std::pair<Range, std::string>> SeenDiags;
620 return !SeenDiags.emplace(D.Range, D.Message).second;
626 const Preprocessor *PP) {
629 OrigSrcMgr = &PP->getSourceManager();
635 LangOpts = std::nullopt;
636 OrigSrcMgr =
nullptr;
642 constexpr unsigned MaxLen = 50;
648 llvm::StringRef R =
Code.split(
'\n').first;
650 R = R.take_front(MaxLen);
653 if (R.size() !=
Code.size())
661 const clang::Diagnostic &
Info,
663 llvm::SmallString<64> Message;
664 Info.FormatDiagnostic(Message);
666 D.Message = std::string(Message);
667 D.Severity = DiagLevel;
668 D.Category = DiagnosticIDs::getCategoryNameFromID(
669 DiagnosticIDs::getCategoryNumberForDiag(
Info.getID()))
674 const clang::Diagnostic &
Info) {
679 if (OrigSrcMgr &&
Info.hasSourceManager() &&
680 OrigSrcMgr != &
Info.getSourceManager()) {
685 DiagnosticConsumer::HandleDiagnostic(DiagLevel,
Info);
686 bool OriginallyError =
687 Info.getDiags()->getDiagnosticIDs()->isDefaultMappingAsError(
690 if (
Info.getLocation().isInvalid()) {
693 if (!OriginallyError) {
702 LastDiagOriginallyError = OriginallyError;
703 LastDiag->ID =
Info.getID();
705 LastDiag->InsideMainFile =
true;
707 LastDiag->Range.start =
Position{0, 0};
708 LastDiag->Range.end =
Position{0, 0};
712 if (!LangOpts || !
Info.hasSourceManager()) {
717 SourceManager &SM =
Info.getSourceManager();
719 auto FillDiagBase = [&](
DiagBase &D) {
722 SourceLocation PatchLoc =
725 if (
auto DRange = diagnosticRange(
Info, *LangOpts))
728 D.Severity = DiagnosticsEngine::Ignored;
729 auto FID = SM.getFileID(
Info.getLocation());
730 if (
const auto FE = SM.getFileEntryRefForID(FID)) {
731 D.File = FE->getName().str();
738 auto AddFix = [&](
bool SyntheticMessage) ->
bool {
739 assert(!
Info.getFixItHints().empty() &&
740 "diagnostic does not have attached fix-its");
742 if (!LastDiag->InsideMainFile)
745 auto FixIts =
Info.getFixItHints().vec();
746 llvm::SmallVector<TextEdit, 1> Edits;
747 for (
auto &
FixIt : FixIts) {
751 if (
FixIt.RemoveRange.getBegin().isMacroID() &&
752 FixIt.RemoveRange.getEnd().isMacroID() &&
753 SM.getFileID(
FixIt.RemoveRange.getBegin()) ==
754 SM.getFileID(
FixIt.RemoveRange.getEnd())) {
755 FixIt.RemoveRange = CharSourceRange(
756 {SM.getTopMacroCallerLoc(
FixIt.RemoveRange.getBegin()),
757 SM.getTopMacroCallerLoc(
FixIt.RemoveRange.getEnd())},
758 FixIt.RemoveRange.isTokenRange());
761 if (
FixIt.RemoveRange.getBegin().isMacroID() ||
762 FixIt.RemoveRange.getEnd().isMacroID())
769 llvm::SmallString<64> Message;
771 if (SyntheticMessage && FixIts.size() == 1) {
772 const auto &
FixIt = FixIts.front();
773 bool Invalid =
false;
774 llvm::StringRef Remove =
775 Lexer::getSourceText(
FixIt.RemoveRange, SM, *LangOpts, &Invalid);
776 llvm::StringRef Insert =
FixIt.CodeToInsert;
778 llvm::raw_svector_ostream
M(Message);
779 if (!Remove.empty() && !Insert.empty()) {
785 }
else if (!Remove.empty()) {
789 }
else if (!Insert.empty()) {
795 std::replace(Message.begin(), Message.end(),
'\n',
' ');
799 Info.FormatDiagnostic(Message);
800 LastDiag->Fixes.push_back(
801 Fix{std::string(Message), std::move(Edits), {}});
805 if (!isNote(DiagLevel)) {
812 DiagLevel = Adjuster(DiagLevel,
Info);
814 FillDiagBase(*LastDiag);
815 if (isExcluded(LastDiag->ID))
816 LastDiag->Severity = DiagnosticsEngine::Ignored;
818 DiagCB(
Info, *LastDiag);
820 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
823 LastDiagLoc.emplace(
Info.getLocation(),
Info.getSourceManager());
824 LastDiagOriginallyError = OriginallyError;
825 if (!
Info.getFixItHints().empty())
828 auto ExtraFixes = Fixer(LastDiag->Severity,
Info);
829 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ExtraFixes.begin(),
835 assert(
false &&
"Adding a note without main diagnostic");
842 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
847 auto ReplacementFixes = Fixer(LastDiag->Severity,
Info);
848 if (!ReplacementFixes.empty()) {
849 assert(
Info.getNumFixItHints() == 0 &&
850 "Include-fixer replaced a note with clang fix-its attached!");
851 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ReplacementFixes.begin(),
852 ReplacementFixes.end());
857 if (!
Info.getFixItHints().empty()) {
867 LastDiag->Notes.push_back(std::move(N));
872void StoreDiags::flushLastDiag() {
875 auto Finish = llvm::make_scope_exit([&, NDiags(Output.size())] {
876 if (Output.size() == NDiags)
877 vlog(
"Dropped diagnostic: {0}: {1}", LastDiag->File, LastDiag->Message);
881 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
884 if (!LastDiag->InsideMainFile && LastDiagLoc && LastDiagOriginallyError) {
885 if (tryMoveToMainFile(*LastDiag, *LastDiagLoc)) {
887 if (!IncludedErrorLocations
888 .insert({LastDiag->Range.start.line,
889 LastDiag->Range.start.character})
894 if (!mentionsMainFile(*LastDiag))
896 Output.push_back(std::move(*LastDiag));
900 const llvm::StringSet<> &Suppress,
901 const LangOptions &LangOpts) {
905 if (
ID == diag::pp_pragma_sysheader_in_main_file && LangOpts.IsHeaderFile)
908 if (
const char *CodePtr = getDiagnosticCode(
ID)) {
912 StringRef
Warning = DiagnosticIDs::getWarningOptionForDiag(
ID);
919 Code.consume_front(
"err_");
920 Code.consume_front(
"-W");
926 llvm::StringRef
Name) {
942 if (
Module.empty() || Check.empty())
944 return (
"https://clang.llvm.org/extra/clang-tidy/checks/" +
Module +
"/" +
949 if (
Name ==
"unused-includes" ||
Name ==
"missing-includes")
950 return {
"https://clangd.llvm.org/guides/include-cleaner"};
llvm::SmallString< 256U > Name
CharSourceRange Range
SourceRange for the file name.
const google::protobuf::Message & M
llvm::raw_string_ostream OS
std::optional< FixItHint > FixIt
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.
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)
bool isBuiltinDiagnosticSuppressed(unsigned ID, const llvm::StringSet<> &Suppress, const LangOptions &LangOpts)
Determine whether a (non-clang-tidy) diagnostic is suppressed by config.
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.
constexpr llvm::StringLiteral Message
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
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.
URIForFile uri
The text document's URI.
Represents a note for the diagnostic.
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.