Index: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp =================================================================== --- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp +++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp @@ -84,6 +84,8 @@ Params.capabilities.textDocument.completion.completionItem.snippetSupport; DiagOpts.EmbedFixesInDiagnostics = Params.capabilities.textDocument.publishDiagnostics.clangdFixSupport; + DiagOpts.SendDiagnosticCategory = + Params.capabilities.textDocument.publishDiagnostics.categorySupport; if (Params.capabilities.workspace && Params.capabilities.workspace->symbol && Params.capabilities.workspace->symbol->symbolKind) { @@ -506,7 +508,7 @@ } LSPDiag["clangd_fixes"] = std::move(ClangdFixes); } - if (!Diag.category.empty()) + if (DiagOpts.SendDiagnosticCategory && !Diag.category.empty()) LSPDiag["category"] = Diag.category; DiagnosticsJSON.push_back(std::move(LSPDiag)); Index: clang-tools-extra/trunk/clangd/Diagnostics.h =================================================================== --- clang-tools-extra/trunk/clangd/Diagnostics.h +++ clang-tools-extra/trunk/clangd/Diagnostics.h @@ -27,6 +27,12 @@ /// If true, Clangd uses an LSP extension to embed the fixes with the /// diagnostics that are sent to the client. bool EmbedFixesInDiagnostics = false; + + /// If true, Clangd uses an LSP extension to send the diagnostic's + /// category to the client. The category typically describes the compilation + /// stage during which the issue was produced, e.g. "Semantic Issue" or "Parse + /// Issue". + bool SendDiagnosticCategory = false; }; /// Contains basic information about a diagnostic. Index: clang-tools-extra/trunk/clangd/Protocol.h =================================================================== --- clang-tools-extra/trunk/clangd/Protocol.h +++ clang-tools-extra/trunk/clangd/Protocol.h @@ -255,6 +255,10 @@ /// Whether the client accepts diagnostics with fixes attached using the /// "clangd_fixes" extension. bool clangdFixSupport = false; + + /// Whether the client accepts diagnostics with category attached to it + /// using the "category" extension. + bool categorySupport = false; }; bool fromJSON(const llvm::json::Value &, PublishDiagnosticsClientCapabilities &); Index: clang-tools-extra/trunk/clangd/Protocol.cpp =================================================================== --- clang-tools-extra/trunk/clangd/Protocol.cpp +++ clang-tools-extra/trunk/clangd/Protocol.cpp @@ -184,6 +184,7 @@ if (!O) return false; O.map("clangdFixSupport", R.clangdFixSupport); + O.map("categorySupport", R.categorySupport); return true; } Index: clang-tools-extra/trunk/test/clangd/compile-commands-path-in-initialize.test =================================================================== --- clang-tools-extra/trunk/test/clangd/compile-commands-path-in-initialize.test +++ clang-tools-extra/trunk/test/clangd/compile-commands-path-in-initialize.test @@ -23,7 +23,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "#pragma message Directive", # CHECK-NEXT: "message": "MACRO is one", --- {"jsonrpc":"2.0","id":0,"method":"workspace/didChangeConfiguration","params":{"settings":{"compilationDatabasePath":"INPUT_DIR/build-2"}}} @@ -31,7 +30,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "#pragma message Directive", # CHECK-NEXT: "message": "MACRO is two", --- {"jsonrpc":"2.0","id":10000,"method":"shutdown"} Index: clang-tools-extra/trunk/test/clangd/compile-commands-path.test =================================================================== --- clang-tools-extra/trunk/test/clangd/compile-commands-path.test +++ clang-tools-extra/trunk/test/clangd/compile-commands-path.test @@ -23,7 +23,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "#pragma message Directive", # CHECK-NEXT: "message": "MACRO is not defined", --- {"jsonrpc":"2.0","id":0,"method":"workspace/didChangeConfiguration","params":{"settings":{"compilationDatabasePath":"INPUT_DIR/build-1"}}} @@ -31,7 +30,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "#pragma message Directive", # CHECK-NEXT: "message": "MACRO is one", --- {"jsonrpc":"2.0","id":0,"method":"workspace/didChangeConfiguration","params":{"settings":{"compilationDatabasePath":"INPUT_DIR/build-2"}}} @@ -39,7 +37,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "#pragma message Directive", # CHECK-NEXT: "message": "MACRO is two", --- {"jsonrpc":"2.0","id":10000,"method":"shutdown"} Index: clang-tools-extra/trunk/test/clangd/diagnostic-category.test =================================================================== --- clang-tools-extra/trunk/test/clangd/diagnostic-category.test +++ clang-tools-extra/trunk/test/clangd/diagnostic-category.test @@ -0,0 +1,43 @@ +# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{"textDocument":{"publishDiagnostics":{"categorySupport":true}}},"trace":"off"}} +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.c","languageId":"c","version":1,"text":"struct Point {}; union Point p;"}}} +# CHECK: "method": "textDocument/publishDiagnostics", +# CHECK-NEXT: "params": { +# CHECK-NEXT: "diagnostics": [ +# CHECK-NEXT: { +# CHECK-NEXT: "category": "Semantic Issue", +# CHECK-NEXT: "message": "Use of 'Point' with tag type that does not match previous declaration\n\nfoo.c:1:8: note: previous use is here", +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 22, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 17, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "severity": 1 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "message": "Previous use is here\n\nfoo.c:1:18: error: use of 'Point' with tag type that does not match previous declaration", +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 12, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 7, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "severity": 3 +# CHECK-NEXT: } +# CHECK-NEXT: ], +# CHECK-NEXT: "uri": "file://{{.*}}/foo.c" +# CHECK-NEXT: } +--- +{"jsonrpc":"2.0","id":4,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} Index: clang-tools-extra/trunk/test/clangd/diagnostics.test =================================================================== --- clang-tools-extra/trunk/test/clangd/diagnostics.test +++ clang-tools-extra/trunk/test/clangd/diagnostics.test @@ -6,7 +6,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "Semantic Issue", # CHECK-NEXT: "message": "Return type of 'main' is not 'int'", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { Index: clang-tools-extra/trunk/test/clangd/did-change-configuration-params.test =================================================================== --- clang-tools-extra/trunk/test/clangd/did-change-configuration-params.test +++ clang-tools-extra/trunk/test/clangd/did-change-configuration-params.test @@ -24,7 +24,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "Semantic Issue", # CHECK-NEXT: "message": "Variable 'i' is uninitialized when used here", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { Index: clang-tools-extra/trunk/test/clangd/execute-command.test =================================================================== --- clang-tools-extra/trunk/test/clangd/execute-command.test +++ clang-tools-extra/trunk/test/clangd/execute-command.test @@ -6,7 +6,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "Semantic Issue", # CHECK-NEXT: "message": "Using the result of an assignment as a condition without parentheses", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { Index: clang-tools-extra/trunk/test/clangd/extra-flags.test =================================================================== --- clang-tools-extra/trunk/test/clangd/extra-flags.test +++ clang-tools-extra/trunk/test/clangd/extra-flags.test @@ -6,7 +6,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "Semantic Issue", # CHECK-NEXT: "message": "Variable 'i' is uninitialized when used here", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { @@ -29,7 +28,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "Semantic Issue", # CHECK-NEXT: "message": "Variable 'i' is uninitialized when used here", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { Index: clang-tools-extra/trunk/test/clangd/fixits-embed-in-diagnostic.test =================================================================== --- clang-tools-extra/trunk/test/clangd/fixits-embed-in-diagnostic.test +++ clang-tools-extra/trunk/test/clangd/fixits-embed-in-diagnostic.test @@ -6,7 +6,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "Semantic Issue", # CHECK-NEXT: "clangd_fixes": [ # CHECK-NEXT: { # CHECK-NEXT: "edit": { Index: clang-tools-extra/trunk/test/clangd/fixits.test =================================================================== --- clang-tools-extra/trunk/test/clangd/fixits.test +++ clang-tools-extra/trunk/test/clangd/fixits.test @@ -6,7 +6,6 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "category": "Semantic Issue", # CHECK-NEXT: "message": "Using the result of an assignment as a condition without parentheses", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": {