Index: clangd/Diagnostics.cpp =================================================================== --- clangd/Diagnostics.cpp +++ clangd/Diagnostics.cpp @@ -145,6 +145,13 @@ OS << diagLeveltoString(D.Severity) << ": " << D.Message; } +/// Capitalizes the first word in the diagnostic's message. +std::string capitalizeDiagnosticText(std::string Message) { + if (!Message.empty()) + Message[0] = llvm::toUpper(Message[0]); + return Message; +} + /// Returns a message sent to LSP for the main diagnostic in \p D. /// The message includes all the notes with their corresponding locations. /// However, notes with fix-its are excluded as those usually only contain a @@ -166,7 +173,7 @@ printDiag(OS, Note); } OS.flush(); - return Result; + return capitalizeDiagnosticText(std::move(Result)); } /// Returns a message sent to LSP for the note of the main diagnostic. @@ -179,7 +186,7 @@ OS << "\n\n"; printDiag(OS, Main); OS.flush(); - return Result; + return capitalizeDiagnosticText(std::move(Result)); } } // namespace Index: test/clangd/capitalize-diagnostics.test =================================================================== --- /dev/null +++ test/clangd/capitalize-diagnostics.test @@ -0,0 +1,42 @@ +# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.c","languageId":"c","version":1,"text":"void foo() { }\nvoid foo() { }"}}} +# CHECK: "method": "textDocument/publishDiagnostics", +# CHECK-NEXT: "params": { +# CHECK-NEXT: "diagnostics": [ +# CHECK-NEXT: { +# CHECK-NEXT: "message": "Redefinition of 'foo'\n\nfoo.c:1:6: note: previous definition is here", +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 8, +# CHECK-NEXT: "line": 1 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 5, +# CHECK-NEXT: "line": 1 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "severity": 1 +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "message": "Previous definition is here\n\nfoo.c:2:6: error: redefinition of 'foo'", +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 8, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 5, +# 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":5,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} Index: test/clangd/diagnostics.test =================================================================== --- test/clangd/diagnostics.test +++ test/clangd/diagnostics.test @@ -6,7 +6,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "message": "return type of 'main' is not 'int'", +# CHECK-NEXT: "message": "Return type of 'main' is not 'int'", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 4, Index: test/clangd/did-change-configuration-params.test =================================================================== --- test/clangd/did-change-configuration-params.test +++ test/clangd/did-change-configuration-params.test @@ -24,7 +24,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "message": "variable 'i' is uninitialized when used here", +# CHECK-NEXT: "message": "Variable 'i' is uninitialized when used here", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 28, Index: test/clangd/execute-command.test =================================================================== --- test/clangd/execute-command.test +++ test/clangd/execute-command.test @@ -6,7 +6,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "message": "using the result of an assignment as a condition without parentheses", +# CHECK-NEXT: "message": "Using the result of an assignment as a condition without parentheses", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 37, Index: test/clangd/extra-flags.test =================================================================== --- test/clangd/extra-flags.test +++ test/clangd/extra-flags.test @@ -6,7 +6,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "message": "variable 'i' is uninitialized when used here", +# CHECK-NEXT: "message": "Variable 'i' is uninitialized when used here", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 28, @@ -28,7 +28,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "message": "variable 'i' is uninitialized when used here", +# CHECK-NEXT: "message": "Variable 'i' is uninitialized when used here", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 28, Index: test/clangd/fixits.test =================================================================== --- test/clangd/fixits.test +++ test/clangd/fixits.test @@ -6,7 +6,7 @@ # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { -# CHECK-NEXT: "message": "using the result of an assignment as a condition without parentheses", +# CHECK-NEXT: "message": "Using the result of an assignment as a condition without parentheses", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 37, @@ -23,7 +23,7 @@ # 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":104,"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"}]}}} +{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":104,"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"}]}}} # CHECK: "id": 2, # CHECK-NEXT: "jsonrpc": "2.0", # CHECK-NEXT: "result": [ @@ -92,7 +92,7 @@ # CHECK-NEXT: } # CHECK-NEXT: ] --- -{"jsonrpc":"2.0","id":3,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":104,"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"}]}}} +{"jsonrpc":"2.0","id":3,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":104,"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"}]}}} # Make sure unused "code" and "source" fields ignored gracefully # CHECK: "id": 3, # CHECK-NEXT: "jsonrpc": "2.0",