From 53a18f8a1e5c1f5108d47973269af9ea47b4cc67 Mon Sep 17 00:00:00 2001 From: Leszek Swirski Date: Thu, 21 Feb 2019 02:23:21 +0100 Subject: [PATCH] Use DiagnosticRelatedInformation if client supports publishDiagnostics.relatedInformation (#276) 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, 49 insertions(+), 20 deletions(-) diff --git a/src/config.hh b/src/config.hh index ca914dc6..3e9aa793 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 8f8efda9..b92578b8 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 949fc242..61d7e1c3 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 6259e8d0..707798d0 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 a80bd0d7..d78b5e06 100644 --- a/src/sema_manager.cc +++ b/src/sema_manager.cc @@ -514,7 +514,7 @@ llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level Lvl) { } } -void printDiag(llvm::raw_string_ostream &OS, const DiagBase &d) { +void PrintDiag(llvm::raw_string_ostream &OS, const DiagBase &d) { if (d.concerned) OS << llvm::sys::path::filename(d.file); else @@ -612,27 +612,40 @@ 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 (const Note &n : d.notes) { + SmallString<256> Str(n.file); + llvm::sys::path::remove_dots(Str, true); + Location loc{DocumentUri::FromPath(Str.str()), + lsRange{{n.range.start.line, n.range.start.column}, + {n.range.end.line, n.range.end.column}}}; + ls_diag.relatedInformation.push_back({loc, n.message}); + } + } else { + std::string buf; + llvm::raw_string_ostream OS(buf); + OS << d.message; + for (const Note &n : d.notes) { + OS << "\n\n"; + PrintDiag(OS, n); + } OS.flush(); - ls_diag1.message = std::move(buf); + ls_diag.message = std::move(buf); + for (const Note &n : d.notes) { + if (!n.concerned) + continue; + Diagnostic &ls_diag1 = ls_diags.emplace_back(); + Fill(n, ls_diag1); + buf.clear(); + OS << n.message << "\n\n"; + PrintDiag(OS, d); + OS.flush(); + ls_diag1.message = std::move(buf); + } } }