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/Edit/EditedSource.h"
24#include "clang/Lex/Lexer.h"
25#include "clang/Lex/Token.h"
26#include "llvm/ADT/ArrayRef.h"
27#include "llvm/ADT/DenseSet.h"
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/STLFunctionalExtras.h"
30#include "llvm/ADT/ScopeExit.h"
31#include "llvm/ADT/SmallString.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/StringExtras.h"
34#include "llvm/ADT/StringRef.h"
35#include "llvm/ADT/StringSet.h"
36#include "llvm/ADT/Twine.h"
37#include "llvm/Support/ErrorHandling.h"
38#include "llvm/Support/FormatVariadic.h"
39#include "llvm/Support/Path.h"
40#include "llvm/Support/SourceMgr.h"
41#include "llvm/Support/raw_ostream.h"
55const char *getDiagnosticCode(
unsigned ID) {
57#define DIAG(ENUM, CLASS, DEFAULT_MAPPING, DESC, GROPU, SFINAE, NOWERROR, \
58 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
60 case clang::diag::ENUM: \
62#include "clang/Basic/DiagnosticASTKinds.inc"
63#include "clang/Basic/DiagnosticAnalysisKinds.inc"
64#include "clang/Basic/DiagnosticCommentKinds.inc"
65#include "clang/Basic/DiagnosticCommonKinds.inc"
66#include "clang/Basic/DiagnosticDriverKinds.inc"
67#include "clang/Basic/DiagnosticFrontendKinds.inc"
68#include "clang/Basic/DiagnosticLexKinds.inc"
69#include "clang/Basic/DiagnosticParseKinds.inc"
70#include "clang/Basic/DiagnosticRefactoringKinds.inc"
71#include "clang/Basic/DiagnosticSemaKinds.inc"
72#include "clang/Basic/DiagnosticSerializationKinds.inc"
79bool mentionsMainFile(
const Diag &D) {
85 for (
auto &N :
D.Notes) {
92bool isExcluded(
unsigned DiagID) {
94 if (DiagID == clang::diag::err_msasm_unable_to_create_target ||
95 DiagID == clang::diag::err_msasm_unsupported_arch)
102bool locationInRange(SourceLocation L, CharSourceRange R,
103 const SourceManager &M) {
104 assert(R.isCharRange());
105 if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
106 M.getFileID(R.getBegin()) != M.getFileID(L))
108 return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
113std::optional<Range> diagnosticRange(
const clang::Diagnostic &D,
114 const LangOptions &L) {
115 auto &M =
D.getSourceManager();
116 auto PatchedRange = [&M](CharSourceRange &R) {
121 auto Loc = M.getFileLoc(
D.getLocation());
122 for (
const auto &CR :
D.getRanges()) {
123 auto R = Lexer::makeFileCharRange(CR, M, L);
124 if (locationInRange(Loc, R, M))
128 for (
const auto &F :
D.getFixItHints()) {
129 auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L);
130 if (locationInRange(Loc, R, M))
136 auto [FID, Offset] = M.getDecomposedLoc(Loc);
137 if (Offset > M.getBufferData(FID).size())
141 auto R = CharSourceRange::getCharRange(Loc);
143 if (!Lexer::getRawToken(Loc, Tok, M, L,
true) && Tok.isNot(tok::comment))
144 R = CharSourceRange::getTokenRange(Tok.getLocation(), Tok.getEndLoc());
150const char *getMainFileRange(
const Diag &D,
const SourceManager &SM,
151 SourceLocation DiagLoc,
Range &R) {
153 for (
const auto &N :
D.Notes) {
154 if (N.InsideMainFile) {
156 case diag::note_template_class_instantiation_was_here:
157 case diag::note_template_class_explicit_specialization_was_here:
158 case diag::note_template_class_instantiation_here:
159 case diag::note_template_member_class_here:
160 case diag::note_template_member_function_here:
161 case diag::note_function_template_spec_here:
162 case diag::note_template_static_data_member_def_here:
163 case diag::note_template_variable_def_here:
164 case diag::note_template_enum_def_here:
165 case diag::note_template_nsdmi_here:
166 case diag::note_template_type_alias_instantiation_here:
167 case diag::note_template_exception_spec_instantiation_here:
168 case diag::note_template_requirement_instantiation_here:
169 case diag::note_evaluating_exception_spec_here:
170 case diag::note_default_arg_instantiation_here:
171 case diag::note_default_function_arg_instantiation_here:
172 case diag::note_explicit_template_arg_substitution_here:
173 case diag::note_function_template_deduction_instantiation_here:
174 case diag::note_deduced_template_arg_substitution_here:
175 case diag::note_prior_template_arg_substitution:
176 case diag::note_template_default_arg_checking:
177 case diag::note_concept_specialization_here:
178 case diag::note_nested_requirement_here:
179 case diag::note_checking_constraints_for_template_id_here:
180 case diag::note_checking_constraints_for_var_spec_id_here:
181 case diag::note_checking_constraints_for_class_spec_id_here:
182 case diag::note_checking_constraints_for_function_here:
183 case diag::note_constraint_substitution_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());
626 for (
auto &
Diag : Output)
631 std::set<std::pair<Range, std::string>> SeenDiags;
632 llvm::erase_if(Output, [&](
const Diag &D) {
633 return !SeenDiags.emplace(D.Range, D.Message).second;
635 return std::move(Output);
639 const Preprocessor *PP) {
642 OrigSrcMgr = &PP->getSourceManager();
648 LangOpts = std::nullopt;
649 OrigSrcMgr =
nullptr;
655 constexpr unsigned MaxLen = 50;
661 llvm::StringRef R = Code.split(
'\n').first;
663 R = R.take_front(MaxLen);
666 if (R.size() != Code.size())
674 const clang::Diagnostic &
Info,
676 llvm::SmallString<64> Message;
677 Info.FormatDiagnostic(Message);
679 D.Message = std::string(Message);
680 D.Severity = DiagLevel;
681 D.Category = DiagnosticIDs::getCategoryNameFromID(
682 DiagnosticIDs::getCategoryNumberForDiag(
Info.getID()))
687 const llvm::StringSet<> &Suppress,
688 const std::optional<LangOptions> &LangOpts) {
692 if (LangOpts &&
Diag.getID() == diag::pp_pragma_sysheader_in_main_file &&
693 LangOpts->IsHeaderFile)
696 if (
const char *CodePtr = getDiagnosticCode(
Diag.getID())) {
701 Diag.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
709 const clang::Diagnostic &
Info) {
714 if (OrigSrcMgr &&
Info.hasSourceManager() &&
715 OrigSrcMgr != &
Info.getSourceManager()) {
720 DiagnosticConsumer::HandleDiagnostic(DiagLevel,
Info);
721 bool OriginallyError =
722 Info.getDiags()->getDiagnosticIDs()->isDefaultMappingAsError(
725 if (!isNote(DiagLevel)) {
731 DiagLevel = DiagnosticsEngine::Ignored;
732 }
else if (Adjuster) {
734 DiagLevel = Adjuster(DiagLevel,
Info);
738 if (
Info.getLocation().isInvalid()) {
741 if (!OriginallyError) {
750 LastDiagOriginallyError = OriginallyError;
751 LastDiag->ID =
Info.getID();
753 LastDiag->InsideMainFile =
true;
755 LastDiag->Range.start =
Position{0, 0};
756 LastDiag->Range.end =
Position{0, 0};
760 if (!LangOpts || !
Info.hasSourceManager()) {
765 SourceManager &SM =
Info.getSourceManager();
767 auto FillDiagBase = [&](
DiagBase &D) {
770 SourceLocation PatchLoc =
773 if (
auto DRange = diagnosticRange(
Info, *LangOpts))
776 D.Severity = DiagnosticsEngine::Ignored;
777 auto FID = SM.getFileID(
Info.getLocation());
778 if (
const auto FE = SM.getFileEntryRefForID(FID)) {
779 D.File = FE->getName().str();
786 auto AddFix = [&](
bool SyntheticMessage) ->
bool {
787 assert(!
Info.getFixItHints().empty() &&
788 "diagnostic does not have attached fix-its");
790 if (!LastDiag->InsideMainFile)
793 auto FixIts =
Info.getFixItHints().vec();
794 for (
auto &FixIt : FixIts) {
798 if (FixIt.RemoveRange.getBegin().isMacroID() &&
799 FixIt.RemoveRange.getEnd().isMacroID() &&
800 SM.getFileID(FixIt.RemoveRange.getBegin()) ==
801 SM.getFileID(FixIt.RemoveRange.getEnd())) {
802 FixIt.RemoveRange = CharSourceRange(
803 {SM.getTopMacroCallerLoc(FixIt.RemoveRange.getBegin()),
804 SM.getTopMacroCallerLoc(FixIt.RemoveRange.getEnd())},
805 FixIt.RemoveRange.isTokenRange());
808 if (FixIt.RemoveRange.getBegin().isMacroID() ||
809 FixIt.RemoveRange.getEnd().isMacroID())
812 llvm::SmallVector<FixItHint> MergedFixIts;
813 clang::edit::mergeFixits(FixIts, SM, *LangOpts, MergedFixIts);
814 if (MergedFixIts.empty())
816 llvm::SmallVector<TextEdit> Edits;
817 Edits.reserve(MergedFixIts.size());
818 for (
const auto &FixIt : MergedFixIts) {
821 Edits.push_back(
toTextEdit(FixIt, SM, *LangOpts));
824 llvm::SmallString<64> Message;
826 if (SyntheticMessage && MergedFixIts.size() == 1) {
827 const auto &FixIt = MergedFixIts.front();
828 bool Invalid =
false;
829 llvm::StringRef Remove =
830 Lexer::getSourceText(FixIt.RemoveRange, SM, *LangOpts, &Invalid);
831 llvm::StringRef Insert = FixIt.CodeToInsert;
833 llvm::raw_svector_ostream M(Message);
834 if (!Remove.empty() && !Insert.empty()) {
840 }
else if (!Remove.empty()) {
844 }
else if (!Insert.empty()) {
850 llvm::replace(Message,
'\n',
' ');
854 Info.FormatDiagnostic(Message);
855 LastDiag->Fixes.push_back(
Fix{std::string(Message), std::move(Edits), {}});
859 if (!isNote(DiagLevel)) {
865 FillDiagBase(*LastDiag);
866 if (isExcluded(LastDiag->ID))
867 LastDiag->Severity = DiagnosticsEngine::Ignored;
869 DiagCB(
Info, *LastDiag);
871 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
874 LastDiagLoc.emplace(
Info.getLocation(),
Info.getSourceManager());
875 LastDiagOriginallyError = OriginallyError;
876 if (!
Info.getFixItHints().empty())
879 auto ExtraFixes = Fixer(LastDiag->Severity,
Info);
880 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ExtraFixes.begin(),
886 assert(
false &&
"Adding a note without main diagnostic");
893 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
898 auto ReplacementFixes = Fixer(LastDiag->Severity,
Info);
899 if (!ReplacementFixes.empty()) {
900 assert(
Info.getNumFixItHints() == 0 &&
901 "Include-fixer replaced a note with clang fix-its attached!");
902 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ReplacementFixes.begin(),
903 ReplacementFixes.end());
908 if (!
Info.getFixItHints().empty()) {
918 LastDiag->Notes.push_back(std::move(N));
923void StoreDiags::flushLastDiag() {
926 llvm::scope_exit Finish([&, NDiags(Output.size())] {
927 if (Output.size() == NDiags)
928 vlog(
"Dropped diagnostic: {0}: {1}", LastDiag->File, LastDiag->Message);
932 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
935 if (!LastDiag->InsideMainFile && LastDiagLoc && LastDiagOriginallyError) {
936 if (tryMoveToMainFile(*LastDiag, *LastDiagLoc)) {
938 if (!IncludedErrorLocations
939 .insert({LastDiag->Range.start.line,
940 LastDiag->Range.start.character})
945 if (!mentionsMainFile(*LastDiag))
947 Output.push_back(std::move(*LastDiag));
951 Code.consume_front(
"err_");
952 Code.consume_front(
"-W");
958 llvm::StringRef Name) {
973 std::tie(
Module, Check) = Name.split(
'-');
974 if (
Module.empty() || Check.empty())
976 return (
"https://clang.llvm.org/extra/clang-tidy/checks/" +
Module +
"/" +
981 if (Name ==
"unused-includes" || Name ==
"missing-includes")
982 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.