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/Edit/EditedSource.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)) {
396 if (!D.InsideMainFile)
398 OS << D.Range.start <<
"-" << D.Range.end <<
"] ";
400 return OS << D.Message;
405 const char *Sep =
"";
414 OS << static_cast<const DiagBase &>(D);
415 if (!D.Notes.empty()) {
417 const char *Sep =
"";
418 for (
auto &
Note : D.Notes) {
424 if (!D.Fixes.empty()) {
426 const char *Sep =
"";
427 for (
auto &
Fix : D.Fixes) {
438 Result.
Message = D.getMessage().str();
439 switch (D.getKind()) {
440 case llvm::SourceMgr::DK_Error:
441 Result.
Severity = DiagnosticsEngine::Error;
443 case llvm::SourceMgr::DK_Warning:
444 Result.
Severity = DiagnosticsEngine::Warning;
450 Result.
AbsFile = D.getFilename().str();
451 Result.
InsideMainFile = D.getSourceMgr()->FindBufferContainingLoc(
452 D.getLoc()) == D.getSourceMgr()->getMainFileID();
453 if (D.getRanges().empty())
454 Result.
Range = {{D.getLineNo() - 1, D.getColumnNo()},
455 {D.getLineNo() - 1, D.getColumnNo()}};
457 Result.
Range = {{D.getLineNo() - 1, (int)D.getRanges().front().first},
458 {D.getLineNo() - 1, (int)D.getRanges().front().second}};
471 if (D.Severity == DiagnosticsEngine::Warning) {
480 if (D.InsideMainFile) {
481 Main.
range = D.Range;
484 llvm::find_if(D.Notes, [](
const Note &N) { return N.InsideMainFile; });
485 assert(It != D.Notes.end() &&
486 "neither the main diagnostic nor notes are inside main file");
487 Main.
range = It->Range;
500 Main.
source =
"clang-tidy";
506 Main.
source =
"clangd-config";
514 Main.
message = mainMessage(D, Opts);
517 for (
auto &
Note : D.Notes) {
519 vlog(
"Dropping note from unknown file: {0}",
Note);
532 for (
auto &
Entry : D.OpaqueData)
534 OutFn(std::move(Main), D.Fixes);
539 for (
auto &
Note : D.Notes) {
546 OutFn(std::move(Res), llvm::ArrayRef<Fix>());
552 case DiagnosticsEngine::Remark:
554 case DiagnosticsEngine::Note:
556 case DiagnosticsEngine::Warning:
558 case DiagnosticsEngine::Fatal:
559 case DiagnosticsEngine::Error:
561 case DiagnosticsEngine::Ignored:
564 llvm_unreachable(
"Unknown diagnostic level!");
572 for (
auto &
Diag : Output) {
573 if (
const char *ClangDiag = getDiagnosticCode(
Diag.
ID)) {
581 return OrigSrcMgr->getDiagnostics()
583 ->getWarningOptionForDiag(
Diag.
ID);
585 if (!DiagnosticIDs::IsCustomDiag(
Diag.
ID))
586 return DiagnosticIDs{}.getWarningOptionForDiag(
Diag.
ID);
593 StringRef Name(ClangDiag);
596 Name.consume_front(
"err_");
604 for (
auto &
Diag : Output)
609 std::set<std::pair<Range, std::string>> SeenDiags;
610 llvm::erase_if(Output, [&](
const Diag &D) {
611 return !SeenDiags.emplace(D.Range, D.Message).second;
613 return std::move(Output);
617 const Preprocessor *PP) {
620 OrigSrcMgr = &PP->getSourceManager();
626 LangOpts = std::nullopt;
627 OrigSrcMgr =
nullptr;
633 constexpr unsigned MaxLen = 50;
639 llvm::StringRef R = Code.split(
'\n').first;
641 R = R.take_front(MaxLen);
644 if (R.size() != Code.size())
652 const clang::Diagnostic &
Info,
654 llvm::SmallString<64> Message;
655 Info.FormatDiagnostic(Message);
657 D.Message = std::string(Message);
658 D.Severity = DiagLevel;
659 D.Category = DiagnosticIDs::getCategoryNameFromID(
660 DiagnosticIDs::getCategoryNumberForDiag(
Info.getID()))
665 const llvm::StringSet<> &Suppress,
666 const std::optional<LangOptions> &LangOpts) {
670 if (LangOpts &&
Diag.getID() == diag::pp_pragma_sysheader_in_main_file &&
671 LangOpts->IsHeaderFile)
674 if (
const char *CodePtr = getDiagnosticCode(
Diag.getID())) {
679 Diag.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
687 const clang::Diagnostic &
Info) {
692 if (OrigSrcMgr &&
Info.hasSourceManager() &&
693 OrigSrcMgr != &
Info.getSourceManager()) {
698 DiagnosticConsumer::HandleDiagnostic(DiagLevel,
Info);
699 bool OriginallyError =
700 Info.getDiags()->getDiagnosticIDs()->isDefaultMappingAsError(
703 if (!isNote(DiagLevel)) {
709 DiagLevel = DiagnosticsEngine::Ignored;
710 }
else if (Adjuster) {
712 DiagLevel = Adjuster(DiagLevel,
Info);
716 if (
Info.getLocation().isInvalid()) {
719 if (!OriginallyError) {
728 LastDiagOriginallyError = OriginallyError;
729 LastDiag->ID =
Info.getID();
731 LastDiag->InsideMainFile =
true;
733 LastDiag->Range.start =
Position{0, 0};
734 LastDiag->Range.end =
Position{0, 0};
738 if (!LangOpts || !
Info.hasSourceManager()) {
743 SourceManager &SM =
Info.getSourceManager();
745 auto FillDiagBase = [&](
DiagBase &D) {
748 SourceLocation PatchLoc =
751 if (
auto DRange = diagnosticRange(
Info, *LangOpts))
754 D.Severity = DiagnosticsEngine::Ignored;
755 auto FID = SM.getFileID(
Info.getLocation());
756 if (
const auto FE = SM.getFileEntryRefForID(FID)) {
757 D.File = FE->getName().str();
764 auto AddFix = [&](
bool SyntheticMessage) ->
bool {
765 assert(!
Info.getFixItHints().empty() &&
766 "diagnostic does not have attached fix-its");
768 if (!LastDiag->InsideMainFile)
771 auto FixIts =
Info.getFixItHints().vec();
772 for (
auto &FixIt : FixIts) {
776 if (FixIt.RemoveRange.getBegin().isMacroID() &&
777 FixIt.RemoveRange.getEnd().isMacroID() &&
778 SM.getFileID(FixIt.RemoveRange.getBegin()) ==
779 SM.getFileID(FixIt.RemoveRange.getEnd())) {
780 FixIt.RemoveRange = CharSourceRange(
781 {SM.getTopMacroCallerLoc(FixIt.RemoveRange.getBegin()),
782 SM.getTopMacroCallerLoc(FixIt.RemoveRange.getEnd())},
783 FixIt.RemoveRange.isTokenRange());
786 if (FixIt.RemoveRange.getBegin().isMacroID() ||
787 FixIt.RemoveRange.getEnd().isMacroID())
790 llvm::SmallVector<FixItHint> MergedFixIts;
791 clang::edit::mergeFixits(FixIts, SM, *LangOpts, MergedFixIts);
792 if (MergedFixIts.empty())
794 llvm::SmallVector<TextEdit> Edits;
795 Edits.reserve(MergedFixIts.size());
796 for (
const auto &FixIt : MergedFixIts) {
799 Edits.push_back(
toTextEdit(FixIt, SM, *LangOpts));
802 llvm::SmallString<64> Message;
804 if (SyntheticMessage && MergedFixIts.size() == 1) {
805 const auto &FixIt = MergedFixIts.front();
806 bool Invalid =
false;
807 llvm::StringRef Remove =
808 Lexer::getSourceText(FixIt.RemoveRange, SM, *LangOpts, &Invalid);
809 llvm::StringRef Insert = FixIt.CodeToInsert;
811 llvm::raw_svector_ostream M(Message);
812 if (!Remove.empty() && !Insert.empty()) {
818 }
else if (!Remove.empty()) {
822 }
else if (!Insert.empty()) {
828 llvm::replace(Message,
'\n',
' ');
832 Info.FormatDiagnostic(Message);
833 LastDiag->Fixes.push_back(
Fix{std::string(Message), std::move(Edits), {}});
837 if (!isNote(DiagLevel)) {
843 FillDiagBase(*LastDiag);
844 if (isExcluded(LastDiag->ID))
845 LastDiag->Severity = DiagnosticsEngine::Ignored;
847 DiagCB(
Info, *LastDiag);
849 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
852 LastDiagLoc.emplace(
Info.getLocation(),
Info.getSourceManager());
853 LastDiagOriginallyError = OriginallyError;
854 if (!
Info.getFixItHints().empty())
857 auto ExtraFixes = Fixer(LastDiag->Severity,
Info);
858 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ExtraFixes.begin(),
864 assert(
false &&
"Adding a note without main diagnostic");
871 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
876 auto ReplacementFixes = Fixer(LastDiag->Severity,
Info);
877 if (!ReplacementFixes.empty()) {
878 assert(
Info.getNumFixItHints() == 0 &&
879 "Include-fixer replaced a note with clang fix-its attached!");
880 LastDiag->Fixes.insert(LastDiag->Fixes.end(), ReplacementFixes.begin(),
881 ReplacementFixes.end());
886 if (!
Info.getFixItHints().empty()) {
896 LastDiag->Notes.push_back(std::move(N));
901void StoreDiags::flushLastDiag() {
904 llvm::scope_exit Finish([&, NDiags(Output.size())] {
905 if (Output.size() == NDiags)
906 vlog(
"Dropped diagnostic: {0}: {1}", LastDiag->File, LastDiag->Message);
910 if (LastDiag->Severity == DiagnosticsEngine::Ignored)
913 if (!LastDiag->InsideMainFile && LastDiagLoc && LastDiagOriginallyError) {
914 if (tryMoveToMainFile(*LastDiag, *LastDiagLoc)) {
916 if (!IncludedErrorLocations
917 .insert({LastDiag->Range.start.line,
918 LastDiag->Range.start.character})
923 if (!mentionsMainFile(*LastDiag))
925 Output.push_back(std::move(*LastDiag));
929 Code.consume_front(
"err_");
930 Code.consume_front(
"-W");
936 llvm::StringRef Name) {
951 std::tie(
Module, Check) = Name.split(
'-');
952 if (
Module.empty() || Check.empty())
954 return (
"https://clang.llvm.org/extra/clang-tidy/checks/" +
Module +
"/" +
959 if (Name ==
"unused-includes" || Name ==
"missing-includes")
960 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
void BeginSourceFile(const LangOptions &Opts, const Preprocessor *PP) override
void EndSourceFile() override
std::vector< Diag > take()
A URI describes the location of a source file.
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.
enum clang::clangd::Diag::DiagSource Source
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.