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_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 llvm::StringSet<> &Suppress,
684 const std::optional<LangOptions> &LangOpts) {
688 if (LangOpts &&
Diag.getID() == diag::pp_pragma_sysheader_in_main_file &&
689 LangOpts->IsHeaderFile)
692 if (
const char *CodePtr = getDiagnosticCode(
Diag.getID())) {
697 Diag.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
705 const clang::Diagnostic &
Info) {
710 if (OrigSrcMgr &&
Info.hasSourceManager() &&
711 OrigSrcMgr != &
Info.getSourceManager()) {
716 DiagnosticConsumer::HandleDiagnostic(DiagLevel,
Info);
717 bool OriginallyError =
718 Info.getDiags()->getDiagnosticIDs()->isDefaultMappingAsError(
721 if (!isNote(DiagLevel)) {
727 DiagLevel = DiagnosticsEngine::Ignored;
728 }
else if (Adjuster) {
730 DiagLevel = Adjuster(DiagLevel,
Info);
734 if (
Info.getLocation().isInvalid()) {
737 if (!OriginallyError) {
746 LastDiagOriginallyError = OriginallyError;
747 LastDiag->ID =
Info.getID();
749 LastDiag->InsideMainFile =
true;
751 LastDiag->Range.start =
Position{0, 0};
752 LastDiag->Range.end =
Position{0, 0};
756 if (!LangOpts || !
Info.hasSourceManager()) {
761 SourceManager &SM =
Info.getSourceManager();
763 auto FillDiagBase = [&](
DiagBase &D) {
766 SourceLocation PatchLoc =
769 if (
auto DRange = diagnosticRange(
Info, *LangOpts))
772 D.Severity = DiagnosticsEngine::Ignored;
773 auto FID = SM.getFileID(
Info.getLocation());
774 if (
const auto FE = SM.getFileEntryRefForID(FID)) {
775 D.File = FE->getName().str();
782 auto AddFix = [&](
bool SyntheticMessage) ->
bool {
783 assert(!
Info.getFixItHints().empty() &&
784 "diagnostic does not have attached fix-its");
786 if (!LastDiag->InsideMainFile)
789 auto FixIts =
Info.getFixItHints().vec();
790 llvm::SmallVector<TextEdit, 1> Edits;
791 for (
auto &FixIt : FixIts) {
795 if (FixIt.RemoveRange.getBegin().isMacroID() &&
796 FixIt.RemoveRange.getEnd().isMacroID() &&
797 SM.getFileID(FixIt.RemoveRange.getBegin()) ==
798 SM.getFileID(FixIt.RemoveRange.getEnd())) {
799 FixIt.RemoveRange = CharSourceRange(
800 {SM.getTopMacroCallerLoc(FixIt.RemoveRange.getBegin()),
801 SM.getTopMacroCallerLoc(FixIt.RemoveRange.getEnd())},
802 FixIt.RemoveRange.isTokenRange());
805 if (FixIt.RemoveRange.getBegin().isMacroID() ||
806 FixIt.RemoveRange.getEnd().isMacroID())
810 Edits.push_back(
toTextEdit(FixIt, SM, *LangOpts));
813 llvm::SmallString<64> Message;
815 if (SyntheticMessage && FixIts.size() == 1) {
816 const auto &FixIt = FixIts.front();
817 bool Invalid =
false;
818 llvm::StringRef Remove =
819 Lexer::getSourceText(FixIt.RemoveRange, SM, *LangOpts, &Invalid);
820 llvm::StringRef Insert = FixIt.CodeToInsert;
822 llvm::raw_svector_ostream M(Message);
823 if (!Remove.empty() && !Insert.empty()) {
829 }
else if (!Remove.empty()) {
833 }
else if (!Insert.empty()) {
839 llvm::replace(Message,
'\n',
' ');
843 Info.FormatDiagnostic(Message);
844 LastDiag->Fixes.push_back(
Fix{std::string(Message), std::move(Edits), {}});
848 if (!isNote(DiagLevel)) {
854 FillDiagBase(*LastDiag);
855 if (isExcluded(LastDiag->ID))
856 LastDiag->Severity = DiagnosticsEngine::Ignored;
858 DiagCB(
Info, *LastDiag);
860 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
863 LastDiagLoc.emplace(
Info.getLocation(),
Info.getSourceManager());
864 LastDiagOriginallyError = OriginallyError;
865 if (!
Info.getFixItHints().empty())
868 auto ExtraFixes = Fixer(LastDiag->Severity,
Info);
869 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ExtraFixes.begin(),
875 assert(
false &&
"Adding a note without main diagnostic");
882 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
887 auto ReplacementFixes = Fixer(LastDiag->Severity,
Info);
888 if (!ReplacementFixes.empty()) {
889 assert(
Info.getNumFixItHints() == 0 &&
890 "Include-fixer replaced a note with clang fix-its attached!");
891 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ReplacementFixes.begin(),
892 ReplacementFixes.end());
897 if (!
Info.getFixItHints().empty()) {
907 LastDiag->Notes.push_back(std::move(N));
912void StoreDiags::flushLastDiag() {
915 llvm::scope_exit Finish([&, NDiags(Output.size())] {
916 if (Output.size() == NDiags)
917 vlog(
"Dropped diagnostic: {0}: {1}", LastDiag->File, LastDiag->Message);
921 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
924 if (!LastDiag->InsideMainFile && LastDiagLoc && LastDiagOriginallyError) {
925 if (tryMoveToMainFile(*LastDiag, *LastDiagLoc)) {
927 if (!IncludedErrorLocations
928 .insert({LastDiag->Range.start.line,
929 LastDiag->Range.start.character})
934 if (!mentionsMainFile(*LastDiag))
936 Output.push_back(std::move(*LastDiag));
940 Code.consume_front(
"err_");
941 Code.consume_front(
"-W");
947 llvm::StringRef Name) {
962 std::tie(
Module, Check) = Name.split(
'-');
963 if (
Module.empty() || Check.empty())
965 return (
"https://clang.llvm.org/extra/clang-tidy/checks/" +
Module +
"/" +
970 if (Name ==
"unused-includes" || Name ==
"missing-includes")
971 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.