16#include "clang/Basic/AllDiagnostics.h"
17#include "clang/Basic/Diagnostic.h"
18#include "clang/Basic/DiagnosticIDs.h"
19#include "clang/Basic/LLVM.h"
20#include "clang/Basic/SourceLocation.h"
21#include "clang/Basic/SourceManager.h"
22#include "clang/Basic/TokenKinds.h"
23#include "clang/Lex/Lexer.h"
24#include "clang/Lex/Token.h"
25#include "llvm/ADT/ArrayRef.h"
26#include "llvm/ADT/DenseSet.h"
27#include "llvm/ADT/STLExtras.h"
28#include "llvm/ADT/STLFunctionalExtras.h"
29#include "llvm/ADT/ScopeExit.h"
30#include "llvm/ADT/SmallString.h"
31#include "llvm/ADT/SmallVector.h"
32#include "llvm/ADT/StringExtras.h"
33#include "llvm/ADT/StringRef.h"
34#include "llvm/ADT/StringSet.h"
35#include "llvm/ADT/Twine.h"
36#include "llvm/Support/ErrorHandling.h"
37#include "llvm/Support/FormatVariadic.h"
38#include "llvm/Support/Path.h"
39#include "llvm/Support/SourceMgr.h"
40#include "llvm/Support/raw_ostream.h"
54const char *getDiagnosticCode(
unsigned ID) {
56#define DIAG(ENUM, CLASS, DEFAULT_MAPPING, DESC, GROPU, SFINAE, NOWERROR, \
57 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
59 case clang::diag::ENUM: \
61#include "clang/Basic/DiagnosticASTKinds.inc"
62#include "clang/Basic/DiagnosticAnalysisKinds.inc"
63#include "clang/Basic/DiagnosticCommentKinds.inc"
64#include "clang/Basic/DiagnosticCommonKinds.inc"
65#include "clang/Basic/DiagnosticDriverKinds.inc"
66#include "clang/Basic/DiagnosticFrontendKinds.inc"
67#include "clang/Basic/DiagnosticLexKinds.inc"
68#include "clang/Basic/DiagnosticParseKinds.inc"
69#include "clang/Basic/DiagnosticRefactoringKinds.inc"
70#include "clang/Basic/DiagnosticSemaKinds.inc"
71#include "clang/Basic/DiagnosticSerializationKinds.inc"
78bool mentionsMainFile(
const Diag &D) {
84 for (
auto &N :
D.Notes) {
91bool isExcluded(
unsigned DiagID) {
93 if (DiagID == clang::diag::err_msasm_unable_to_create_target ||
94 DiagID == clang::diag::err_msasm_unsupported_arch)
101bool locationInRange(SourceLocation L, CharSourceRange R,
102 const SourceManager &M) {
103 assert(R.isCharRange());
104 if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
105 M.getFileID(R.getBegin()) != M.getFileID(L))
107 return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
112std::optional<Range> diagnosticRange(
const clang::Diagnostic &D,
113 const LangOptions &L) {
114 auto &M =
D.getSourceManager();
115 auto PatchedRange = [&M](CharSourceRange &R) {
120 auto Loc = M.getFileLoc(
D.getLocation());
121 for (
const auto &CR :
D.getRanges()) {
122 auto R = Lexer::makeFileCharRange(CR, M, L);
123 if (locationInRange(Loc, R, M))
127 for (
const auto &F :
D.getFixItHints()) {
128 auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L);
129 if (locationInRange(Loc, R, M))
135 auto [FID, Offset] = M.getDecomposedLoc(Loc);
136 if (Offset > M.getBufferData(FID).size())
140 auto R = CharSourceRange::getCharRange(Loc);
142 if (!Lexer::getRawToken(Loc, Tok, M, L,
true) && Tok.isNot(tok::comment))
143 R = CharSourceRange::getTokenRange(Tok.getLocation(), Tok.getEndLoc());
149const char *getMainFileRange(
const Diag &D,
const SourceManager &SM,
150 SourceLocation DiagLoc,
Range &R) {
152 for (
const auto &N :
D.Notes) {
153 if (N.InsideMainFile) {
155 case diag::note_template_class_instantiation_was_here:
156 case diag::note_template_class_explicit_specialization_was_here:
157 case diag::note_template_class_instantiation_here:
158 case diag::note_template_member_class_here:
159 case diag::note_template_member_function_here:
160 case diag::note_function_template_spec_here:
161 case diag::note_template_static_data_member_def_here:
162 case diag::note_template_variable_def_here:
163 case diag::note_template_enum_def_here:
164 case diag::note_template_nsdmi_here:
165 case diag::note_template_type_alias_instantiation_here:
166 case diag::note_template_exception_spec_instantiation_here:
167 case diag::note_template_requirement_instantiation_here:
168 case diag::note_evaluating_exception_spec_here:
169 case diag::note_default_arg_instantiation_here:
170 case diag::note_default_function_arg_instantiation_here:
171 case diag::note_explicit_template_arg_substitution_here:
172 case diag::note_function_template_deduction_instantiation_here:
173 case diag::note_deduced_template_arg_substitution_here:
174 case diag::note_prior_template_arg_substitution:
175 case diag::note_template_default_arg_checking:
176 case diag::note_concept_specialization_here:
177 case diag::note_nested_requirement_here:
178 case diag::note_checking_constraints_for_template_id_here:
179 case diag::note_checking_constraints_for_var_spec_id_here:
180 case diag::note_checking_constraints_for_class_spec_id_here:
181 case diag::note_checking_constraints_for_function_here:
182 case diag::note_constraint_substitution_here:
183 case diag::note_constraint_normalization_here:
184 case diag::note_parameter_mapping_substitution_here:
186 return "in template";
193 auto GetIncludeLoc = [&SM](SourceLocation SLoc) {
194 return SM.getIncludeLoc(SM.getFileID(SLoc));
196 for (
auto IncludeLocation = GetIncludeLoc(SM.getExpansionLoc(DiagLoc));
197 IncludeLocation.isValid();
198 IncludeLocation = GetIncludeLoc(IncludeLocation)) {
203 Lexer::getLocForEndOfToken(IncludeLocation, 0, SM, LangOptions()));
204 return "in included file";
214bool tryMoveToMainFile(
Diag &D, FullSourceLoc DiagLoc) {
215 const SourceManager &SM = DiagLoc.getManager();
216 DiagLoc = DiagLoc.getExpansionLoc();
218 const char *Prefix = getMainFileRange(D, SM, DiagLoc, R);
223 auto FE = *SM.getFileEntryRefForID(SM.getFileID(DiagLoc));
224 D.Notes.emplace(
D.Notes.begin());
225 Note &N =
D.Notes.front();
226 N.AbsFile = std::string(FE.getFileEntry().tryGetRealPathName());
227 N.File = std::string(FE.getName());
228 N.Message =
"error occurred here";
232 D.File = SM.getFileEntryRefForID(SM.getMainFileID())->getName().str();
233 D.Range = std::move(R);
234 D.InsideMainFile =
true;
236 D.Message = llvm::formatv(
"{0}: {1}", Prefix,
D.Message);
240bool isNote(DiagnosticsEngine::Level L) {
241 return L == DiagnosticsEngine::Note || L == DiagnosticsEngine::Remark;
244llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level Lvl) {
246 case DiagnosticsEngine::Ignored:
248 case DiagnosticsEngine::Note:
250 case DiagnosticsEngine::Remark:
252 case DiagnosticsEngine::Warning:
254 case DiagnosticsEngine::Error:
256 case DiagnosticsEngine::Fatal:
257 return "fatal error";
259 llvm_unreachable(
"unhandled DiagnosticsEngine::Level");
273void printDiag(llvm::raw_string_ostream &OS,
const DiagBase &D) {
274 if (
D.InsideMainFile) {
278 OS << llvm::sys::path::filename(
D.File) <<
":";
284 auto Pos =
D.Range.start;
285 OS << (Pos.line + 1) <<
":" << (Pos.character + 1) <<
":";
288 if (
D.InsideMainFile)
292 OS << diagLeveltoString(
D.Severity) <<
": " <<
D.Message;
296std::string capitalize(std::string Message) {
297 if (!Message.empty())
298 Message[0] = llvm::toUpper(Message[0]);
314 llvm::raw_string_ostream OS(Result);
316 if (Opts.DisplayFixesCount && !
D.Fixes.empty())
317 OS <<
" (" << (
D.Fixes.size() > 1 ?
"fixes" :
"fix") <<
" available)";
319 if (!Opts.EmitRelatedLocations)
320 for (
auto &
Note :
D.Notes) {
324 return capitalize(std::move(Result));
331 llvm::raw_string_ostream OS(Result);
335 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;
412 const char *Sep =
"";
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;
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";
521 Main.
message = mainMessage(D, Opts);
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);
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)) {
584 return OrigSrcMgr->getDiagnostics()
586 ->getWarningOptionForDiag(
Diag.
ID);
588 if (!DiagnosticIDs::IsCustomDiag(
Diag.
ID))
589 return DiagnosticIDs{}.getWarningOptionForDiag(
Diag.
ID);
596 StringRef Name(ClangDiag);
599 Name.consume_front(
"err_");
603 }
else if (Tidy !=
nullptr) {
605 if (!TidyDiag.empty()) {
610 auto CleanMessage = [&](std::string &Msg) {
612 if (Rest.consume_back(
"]") && Rest.consume_back(
Diag.
Name) &&
613 Rest.consume_back(
" ["))
614 Msg.resize(Rest.size());
628 std::set<std::pair<Range, std::string>> SeenDiags;
629 llvm::erase_if(Output, [&](
const Diag &D) {
630 return !SeenDiags.emplace(D.Range, D.Message).second;
632 return std::move(Output);
636 const Preprocessor *PP) {
639 OrigSrcMgr = &PP->getSourceManager();
645 LangOpts = std::nullopt;
646 OrigSrcMgr =
nullptr;
652 constexpr unsigned MaxLen = 50;
658 llvm::StringRef R = Code.split(
'\n').first;
660 R = R.take_front(MaxLen);
663 if (R.size() != Code.size())
671 const clang::Diagnostic &
Info,
673 llvm::SmallString<64> Message;
674 Info.FormatDiagnostic(Message);
676 D.Message = std::string(Message);
677 D.Severity = DiagLevel;
678 D.Category = DiagnosticIDs::getCategoryNameFromID(
679 DiagnosticIDs::getCategoryNumberForDiag(
Info.getID()))
684 const llvm::StringSet<> &Suppress,
685 const std::optional<LangOptions> &LangOpts) {
689 if (LangOpts &&
Diag.getID() == diag::pp_pragma_sysheader_in_main_file &&
690 LangOpts->IsHeaderFile)
693 if (
const char *CodePtr = getDiagnosticCode(
Diag.getID())) {
698 Diag.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
706 const clang::Diagnostic &
Info) {
711 if (OrigSrcMgr &&
Info.hasSourceManager() &&
712 OrigSrcMgr != &
Info.getSourceManager()) {
717 DiagnosticConsumer::HandleDiagnostic(DiagLevel,
Info);
718 bool OriginallyError =
719 Info.getDiags()->getDiagnosticIDs()->isDefaultMappingAsError(
722 if (!isNote(DiagLevel)) {
728 DiagLevel = DiagnosticsEngine::Ignored;
729 }
else if (Adjuster) {
731 DiagLevel = Adjuster(DiagLevel,
Info);
735 if (
Info.getLocation().isInvalid()) {
738 if (!OriginallyError) {
747 LastDiagOriginallyError = OriginallyError;
748 LastDiag->ID =
Info.getID();
750 LastDiag->InsideMainFile =
true;
752 LastDiag->Range.start =
Position{0, 0};
753 LastDiag->Range.end =
Position{0, 0};
757 if (!LangOpts || !
Info.hasSourceManager()) {
762 SourceManager &SM =
Info.getSourceManager();
764 auto FillDiagBase = [&](
DiagBase &D) {
767 SourceLocation PatchLoc =
770 if (
auto DRange = diagnosticRange(
Info, *LangOpts))
773 D.Severity = DiagnosticsEngine::Ignored;
774 auto FID = SM.getFileID(
Info.getLocation());
775 if (
const auto FE = SM.getFileEntryRefForID(FID)) {
776 D.File = FE->getName().str();
783 auto AddFix = [&](
bool SyntheticMessage) ->
bool {
784 assert(!
Info.getFixItHints().empty() &&
785 "diagnostic does not have attached fix-its");
787 if (!LastDiag->InsideMainFile)
790 auto FixIts =
Info.getFixItHints().vec();
791 llvm::SmallVector<TextEdit, 1> Edits;
792 for (
auto &FixIt : FixIts) {
796 if (FixIt.RemoveRange.getBegin().isMacroID() &&
797 FixIt.RemoveRange.getEnd().isMacroID() &&
798 SM.getFileID(FixIt.RemoveRange.getBegin()) ==
799 SM.getFileID(FixIt.RemoveRange.getEnd())) {
800 FixIt.RemoveRange = CharSourceRange(
801 {SM.getTopMacroCallerLoc(FixIt.RemoveRange.getBegin()),
802 SM.getTopMacroCallerLoc(FixIt.RemoveRange.getEnd())},
803 FixIt.RemoveRange.isTokenRange());
806 if (FixIt.RemoveRange.getBegin().isMacroID() ||
807 FixIt.RemoveRange.getEnd().isMacroID())
811 Edits.push_back(
toTextEdit(FixIt, SM, *LangOpts));
814 llvm::SmallString<64> Message;
816 if (SyntheticMessage && FixIts.size() == 1) {
817 const auto &FixIt = FixIts.front();
818 bool Invalid =
false;
819 llvm::StringRef Remove =
820 Lexer::getSourceText(FixIt.RemoveRange, SM, *LangOpts, &Invalid);
821 llvm::StringRef Insert = FixIt.CodeToInsert;
823 llvm::raw_svector_ostream M(Message);
824 if (!Remove.empty() && !Insert.empty()) {
830 }
else if (!Remove.empty()) {
834 }
else if (!Insert.empty()) {
840 llvm::replace(Message,
'\n',
' ');
844 Info.FormatDiagnostic(Message);
845 LastDiag->Fixes.push_back(
Fix{std::string(Message), std::move(Edits), {}});
849 if (!isNote(DiagLevel)) {
855 FillDiagBase(*LastDiag);
856 if (isExcluded(LastDiag->ID))
857 LastDiag->Severity = DiagnosticsEngine::Ignored;
859 DiagCB(
Info, *LastDiag);
861 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
864 LastDiagLoc.emplace(
Info.getLocation(),
Info.getSourceManager());
865 LastDiagOriginallyError = OriginallyError;
866 if (!
Info.getFixItHints().empty())
869 auto ExtraFixes = Fixer(LastDiag->Severity,
Info);
870 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ExtraFixes.begin(),
876 assert(
false &&
"Adding a note without main diagnostic");
883 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
888 auto ReplacementFixes = Fixer(LastDiag->Severity,
Info);
889 if (!ReplacementFixes.empty()) {
890 assert(
Info.getNumFixItHints() == 0 &&
891 "Include-fixer replaced a note with clang fix-its attached!");
892 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ReplacementFixes.begin(),
893 ReplacementFixes.end());
898 if (!
Info.getFixItHints().empty()) {
908 LastDiag->Notes.push_back(std::move(N));
913void StoreDiags::flushLastDiag() {
916 llvm::scope_exit Finish([&, NDiags(Output.size())] {
917 if (Output.size() == NDiags)
918 vlog(
"Dropped diagnostic: {0}: {1}", LastDiag->File, LastDiag->Message);
922 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
925 if (!LastDiag->InsideMainFile && LastDiagLoc && LastDiagOriginallyError) {
926 if (tryMoveToMainFile(*LastDiag, *LastDiagLoc)) {
928 if (!IncludedErrorLocations
929 .insert({LastDiag->Range.start.line,
930 LastDiag->Range.start.character})
935 if (!mentionsMainFile(*LastDiag))
937 Output.push_back(std::move(*LastDiag));
941 Code.consume_front(
"err_");
942 Code.consume_front(
"-W");
948 llvm::StringRef Name) {
963 std::tie(
Module, Check) = Name.split(
'-');
964 if (
Module.empty() || Check.empty())
966 return (
"https://clang.llvm.org/extra/clang-tidy/checks/" +
Module +
"/" +
971 if (Name ==
"unused-includes" || Name ==
"missing-includes")
972 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.
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...
static bool isDiagnosticSuppressed(const clang::Diagnostic &Diag, const llvm::StringSet<> &Suppress, const std::optional< LangOptions > &LangOpts)
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 ...
Settings that express user/project preferences and control clangd behavior.
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
struct clang::clangd::Config::@343034053122374337352226322054223376344037116252 Diagnostics
Controls warnings and errors when parsing code.
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.