From c34b382ee5dff7b81a48c04815a65d241c857485 Mon Sep 17 00:00:00 2001 From: Leszek Swirski Date: Wed, 20 Feb 2019 17:26:42 +0100 Subject: [PATCH] Use DiagnosticRelatedInformation in clients that support it In clients that support DiagnosticRelatedInformation, display clang notes as these nested diagnostics rather than appending them to the parent diagnostic's message. Behaviour for clients that don't support related information should be unchanged. --- src/config.hh | 2 ++ src/lsp.hh | 6 +++++ src/message_handler.hh | 3 ++- src/messages/initialize.cc | 9 ++++++- src/sema_manager.cc | 49 +++++++++++++++++++++++++------------- 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/config.hh b/src/config.hh index ca914dc63..3e9aa793d 100644 --- a/src/config.hh +++ b/src/config.hh @@ -108,6 +108,8 @@ struct Config { bool linkSupport = true; // TextDocumentClientCapabilities.completion.completionItem.snippetSupport bool snippetSupport = true; + // TextDocumentClientCapabilities.publishDiagnostics.relatedInformation + bool diagnosticsRelatedInformation = true; } client; struct CodeLens { diff --git a/src/lsp.hh b/src/lsp.hh index 8f8efda96..b92578b88 100644 --- a/src/lsp.hh +++ b/src/lsp.hh @@ -238,12 +238,18 @@ struct WorkspaceFolder { enum class MessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 }; REFLECT_UNDERLYING(MessageType) +struct DiagnosticRelatedInformation { + Location location; + std::string message; +}; + struct Diagnostic { lsRange range; int severity = 0; int code = 0; std::string source = "ccls"; std::string message; + std::vector relatedInformation; std::vector fixits_; }; diff --git a/src/message_handler.hh b/src/message_handler.hh index 949fc2423..61d7e1c32 100644 --- a/src/message_handler.hh +++ b/src/message_handler.hh @@ -195,7 +195,8 @@ REFLECT_STRUCT(TextDocumentIdentifier, uri); REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text); REFLECT_STRUCT(TextEdit, range, newText); REFLECT_STRUCT(VersionedTextDocumentIdentifier, uri, version); -REFLECT_STRUCT(Diagnostic, range, severity, code, source, message); +REFLECT_STRUCT(DiagnosticRelatedInformation, location, message); +REFLECT_STRUCT(Diagnostic, range, severity, code, source, message, relatedInformation); REFLECT_STRUCT(ShowMessageParam, type, message); REFLECT_UNDERLYING_B(LanguageId); diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index 6259e8d05..707798d06 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -171,6 +171,10 @@ struct TextDocumentClientCap { struct DocumentSymbol { bool hierarchicalDocumentSymbolSupport = false; } documentSymbol; + + struct PublishDiagnostics { + bool relatedInformation = false; + } publishDiagnostics; }; REFLECT_STRUCT(TextDocumentClientCap::Completion::CompletionItem, @@ -179,7 +183,8 @@ REFLECT_STRUCT(TextDocumentClientCap::Completion, completionItem); REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol, hierarchicalDocumentSymbolSupport); REFLECT_STRUCT(TextDocumentClientCap::LinkSupport, linkSupport); -REFLECT_STRUCT(TextDocumentClientCap, completion, definition, documentSymbol); +REFLECT_STRUCT(TextDocumentClientCap::PublishDiagnostics, relatedInformation); +REFLECT_STRUCT(TextDocumentClientCap, completion, definition, documentSymbol, publishDiagnostics); struct ClientCap { WorkspaceClientCap workspace; @@ -306,6 +311,8 @@ void Initialize(MessageHandler *m, InitializeParam ¶m, ReplyOnce &reply) { capabilities.textDocument.definition.linkSupport; g_config->client.snippetSupport &= capabilities.textDocument.completion.completionItem.snippetSupport; + g_config->client.diagnosticsRelatedInformation &= + capabilities.textDocument.publishDiagnostics.relatedInformation; didChangeWatchedFiles = capabilities.workspace.didChangeWatchedFiles.dynamicRegistration; diff --git a/src/sema_manager.cc b/src/sema_manager.cc index a80bd0d7c..15c69ef23 100644 --- a/src/sema_manager.cc +++ b/src/sema_manager.cc @@ -612,27 +612,42 @@ void *DiagnosticMain(void *manager_) { for (auto &d : diags) { if (!d.concerned) continue; - std::string buf; - llvm::raw_string_ostream OS(buf); Diagnostic &ls_diag = ls_diags.emplace_back(); Fill(d, ls_diag); ls_diag.fixits_ = d.edits; - OS << d.message; - for (auto &n : d.notes) { - OS << "\n\n"; - printDiag(OS, n); - } - OS.flush(); - ls_diag.message = std::move(buf); - for (auto &n : d.notes) { - if (!n.concerned) - continue; - Diagnostic &ls_diag1 = ls_diags.emplace_back(); - Fill(n, ls_diag1); - OS << n.message << "\n\n"; - printDiag(OS, d); + if (g_config->client.diagnosticsRelatedInformation) { + ls_diag.message = d.message; + for (auto &n : d.notes) { + DiagnosticRelatedInformation &ls_diag_related = ls_diag.relatedInformation.emplace_back(); + SmallString<256> buffer(n.file); + llvm::sys::path::remove_dots(buffer, true); + ls_diag_related.location = Location { + DocumentUri::FromPath(buffer.str()), + lsRange{{n.range.start.line, n.range.start.column}, + {n.range.end.line, n.range.end.column}} + }; + ls_diag_related.message = n.message; + } + } else { + std::string buf; + llvm::raw_string_ostream OS(buf); + OS << d.message; + for (auto &n : d.notes) { + OS << "\n\n"; + printDiag(OS, n); + } OS.flush(); - ls_diag1.message = std::move(buf); + ls_diag.message = std::move(buf); + for (auto &n : d.notes) { + if (!n.concerned) + continue; + Diagnostic &ls_diag1 = ls_diags.emplace_back(); + Fill(n, ls_diag1); + OS << n.message << "\n\n"; + printDiag(OS, d); + OS.flush(); + ls_diag1.message = std::move(buf); + } } }