Index: clangd/Diagnostics.h =================================================================== --- clangd/Diagnostics.h +++ clangd/Diagnostics.h @@ -64,6 +64,8 @@ /// A top-level diagnostic that may have Notes and Fixes. struct Diag : DiagBase { + // Diagnostic enum ID (member of clang::diag). + unsigned ID; /// Elaborate on the problem, usually pointing to a related piece of code. std::vector Notes; /// *Alternative* fixes for this diagnostic, one should be chosen. Index: clangd/Diagnostics.cpp =================================================================== --- clangd/Diagnostics.cpp +++ clangd/Diagnostics.cpp @@ -10,6 +10,8 @@ #include "Compiler.h" #include "Logger.h" #include "SourceCode.h" +#include "clang/Basic/AllDiagnostics.h" +#include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/Capacity.h" @@ -18,9 +20,31 @@ namespace clang { namespace clangd { - namespace { +const char* getDiagnosticCode(unsigned ID) { + switch (ID) { +#define DIAG(ENUM, CLASS, DEFAULT_MAPPING, DESC, GROPU, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, CATEGORY) \ + case clang::diag::ENUM: \ + return #ENUM; +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#include "clang/Basic/DiagnosticRefactoringKinds.inc" +#undef DIAG + default: + return nullptr; + } +} + bool mentionsMainFile(const Diag &D) { if (D.InsideMainFile) return true; @@ -253,6 +277,8 @@ { clangd::Diagnostic Main = FillBasicFields(D); Main.message = mainMessage(D); + if (auto* Name = getDiagnosticCode(D.ID)) + Main.code = Name; if (Opts.EmbedFixesInDiagnostics) { Main.codeActions.emplace(); for (const auto &Fix : D.Fixes) @@ -372,6 +398,7 @@ flushLastDiag(); LastDiag = Diag(); + LastDiag->ID = Info.getID(); FillDiagBase(*LastDiag); if (!Info.getFixItHints().empty()) Index: clangd/Protocol.h =================================================================== --- clangd/Protocol.h +++ clangd/Protocol.h @@ -566,8 +566,7 @@ int severity = 0; /// The diagnostic's code. Can be omitted. - /// Note: Not currently used by clangd - // std::string code; + std::string code; /// A human-readable string describing the source of this /// diagnostic, e.g. 'typescript' or 'super lint'. Index: clangd/Protocol.cpp =================================================================== --- clangd/Protocol.cpp +++ clangd/Protocol.cpp @@ -369,6 +369,8 @@ Diag["category"] = *D.category; if (D.codeActions) Diag["codeActions"] = D.codeActions; + if (!D.code.empty()) + Diag["code"] = D.code; return std::move(Diag); } @@ -378,6 +380,7 @@ return false; O.map("severity", R.severity); O.map("category", R.category); + O.map("code", R.code); return true; } Index: test/clangd/compile-commands-path-in-initialize.test =================================================================== --- test/clangd/compile-commands-path-in-initialize.test +++ test/clangd/compile-commands-path-in-initialize.test @@ -21,6 +21,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { +# CHECK-NEXT: "code": "warn_pragma_message", # CHECK-NEXT: "message": "MACRO is one", --- {"jsonrpc":"2.0","id":10000,"method":"shutdown"} Index: test/clangd/diagnostic-category.test =================================================================== --- test/clangd/diagnostic-category.test +++ test/clangd/diagnostic-category.test @@ -7,6 +7,7 @@ # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { # CHECK-NEXT: "category": "Semantic Issue", +# CHECK-NEXT: "code": "err_use_with_wrong_tag", # CHECK-NEXT: "message": "Use of 'Point' with tag type that does not match previous declaration (fix available)\n\nfoo.c:1:8: note: previous use is here", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { Index: test/clangd/diagnostics.test =================================================================== --- test/clangd/diagnostics.test +++ test/clangd/diagnostics.test @@ -6,6 +6,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { +# CHECK-NEXT: "code": "ext_main_returns_nonint", # CHECK-NEXT: "message": "Return type of 'main' is not 'int' (fix available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { Index: test/clangd/did-change-configuration-params.test =================================================================== --- test/clangd/did-change-configuration-params.test +++ test/clangd/did-change-configuration-params.test @@ -24,6 +24,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { +# CHECK-NEXT: "code": "warn_uninit_var", # CHECK-NEXT: "message": "Variable 'i' is uninitialized when used here (fix available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { Index: test/clangd/execute-command.test =================================================================== --- test/clangd/execute-command.test +++ test/clangd/execute-command.test @@ -6,6 +6,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { +# CHECK-NEXT: "code": "warn_condition_is_assignment", # CHECK-NEXT: "message": "Using the result of an assignment as a condition without parentheses (fixes available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { Index: test/clangd/fixits-codeaction.test =================================================================== --- test/clangd/fixits-codeaction.test +++ test/clangd/fixits-codeaction.test @@ -6,6 +6,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { +# CHECK-NEXT: "code": "warn_condition_is_assignment", # CHECK-NEXT: "message": "Using the result of an assignment as a condition without parentheses (fixes available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { @@ -23,13 +24,14 @@ # CHECK-NEXT: "uri": "file://{{.*}}/foo.c" # CHECK-NEXT: } --- -{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":0,"character":13},"end":{"line":0,"character":35}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 37}},"severity":2,"message":"Using the result of an assignment as a condition without parentheses (fixes available)"}]}}} +{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":0,"character":13},"end":{"line":0,"character":35}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 37}},"severity":2,"message":"Using the result of an assignment as a condition without parentheses (fixes available)", "code": "warn_condition_is_assignment"}]}}} # CHECK: "id": 2, # CHECK-NEXT: "jsonrpc": "2.0", # CHECK-NEXT: "result": [ # CHECK-NEXT: { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { +# CHECK-NEXT: "code": "warn_condition_is_assignment", # CHECK-NEXT: "message": "Using the result of an assignment as a condition without parentheses (fixes available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { @@ -82,6 +84,7 @@ # CHECK-NEXT: { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { +# CHECK-NEXT: "code": "warn_condition_is_assignment", # CHECK-NEXT: "message": "Using the result of an assignment as a condition without parentheses (fixes available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { Index: test/clangd/fixits-command.test =================================================================== --- test/clangd/fixits-command.test +++ test/clangd/fixits-command.test @@ -6,6 +6,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { +# CHECK-NEXT: "code": "warn_condition_is_assignment", # CHECK-NEXT: "message": "Using the result of an assignment as a condition without parentheses (fixes available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { Index: test/clangd/fixits-embed-in-diagnostic.test =================================================================== --- test/clangd/fixits-embed-in-diagnostic.test +++ test/clangd/fixits-embed-in-diagnostic.test @@ -6,6 +6,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { +# CHECK-NEXT: "code": "err_use_with_wrong_tag", # CHECK-NEXT: "codeActions": [ # CHECK-NEXT: { # CHECK-NEXT: "edit": {