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.
This commit is contained in:
Leszek Swirski 2019-02-21 02:23:21 +01:00 committed by Fangrui Song
parent ea774dadf5
commit 0d92b72248
5 changed files with 49 additions and 20 deletions

View File

@ -108,6 +108,8 @@ struct Config {
bool linkSupport = true; bool linkSupport = true;
// TextDocumentClientCapabilities.completion.completionItem.snippetSupport // TextDocumentClientCapabilities.completion.completionItem.snippetSupport
bool snippetSupport = true; bool snippetSupport = true;
// TextDocumentClientCapabilities.publishDiagnostics.relatedInformation
bool diagnosticsRelatedInformation = true;
} client; } client;
struct CodeLens { struct CodeLens {

View File

@ -238,12 +238,18 @@ struct WorkspaceFolder {
enum class MessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 }; enum class MessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 };
REFLECT_UNDERLYING(MessageType) REFLECT_UNDERLYING(MessageType)
struct DiagnosticRelatedInformation {
Location location;
std::string message;
};
struct Diagnostic { struct Diagnostic {
lsRange range; lsRange range;
int severity = 0; int severity = 0;
int code = 0; int code = 0;
std::string source = "ccls"; std::string source = "ccls";
std::string message; std::string message;
std::vector<DiagnosticRelatedInformation> relatedInformation;
std::vector<TextEdit> fixits_; std::vector<TextEdit> fixits_;
}; };

View File

@ -195,7 +195,8 @@ REFLECT_STRUCT(TextDocumentIdentifier, uri);
REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text); REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text);
REFLECT_STRUCT(TextEdit, range, newText); REFLECT_STRUCT(TextEdit, range, newText);
REFLECT_STRUCT(VersionedTextDocumentIdentifier, uri, version); 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_STRUCT(ShowMessageParam, type, message);
REFLECT_UNDERLYING_B(LanguageId); REFLECT_UNDERLYING_B(LanguageId);

View File

@ -171,6 +171,10 @@ struct TextDocumentClientCap {
struct DocumentSymbol { struct DocumentSymbol {
bool hierarchicalDocumentSymbolSupport = false; bool hierarchicalDocumentSymbolSupport = false;
} documentSymbol; } documentSymbol;
struct PublishDiagnostics {
bool relatedInformation = false;
} publishDiagnostics;
}; };
REFLECT_STRUCT(TextDocumentClientCap::Completion::CompletionItem, REFLECT_STRUCT(TextDocumentClientCap::Completion::CompletionItem,
@ -179,7 +183,8 @@ REFLECT_STRUCT(TextDocumentClientCap::Completion, completionItem);
REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol, REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol,
hierarchicalDocumentSymbolSupport); hierarchicalDocumentSymbolSupport);
REFLECT_STRUCT(TextDocumentClientCap::LinkSupport, linkSupport); 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 { struct ClientCap {
WorkspaceClientCap workspace; WorkspaceClientCap workspace;
@ -306,6 +311,8 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
capabilities.textDocument.definition.linkSupport; capabilities.textDocument.definition.linkSupport;
g_config->client.snippetSupport &= g_config->client.snippetSupport &=
capabilities.textDocument.completion.completionItem.snippetSupport; capabilities.textDocument.completion.completionItem.snippetSupport;
g_config->client.diagnosticsRelatedInformation &=
capabilities.textDocument.publishDiagnostics.relatedInformation;
didChangeWatchedFiles = didChangeWatchedFiles =
capabilities.workspace.didChangeWatchedFiles.dynamicRegistration; capabilities.workspace.didChangeWatchedFiles.dynamicRegistration;

View File

@ -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) if (d.concerned)
OS << llvm::sys::path::filename(d.file); OS << llvm::sys::path::filename(d.file);
else else
@ -612,29 +612,42 @@ void *DiagnosticMain(void *manager_) {
for (auto &d : diags) { for (auto &d : diags) {
if (!d.concerned) if (!d.concerned)
continue; continue;
std::string buf;
llvm::raw_string_ostream OS(buf);
Diagnostic &ls_diag = ls_diags.emplace_back(); Diagnostic &ls_diag = ls_diags.emplace_back();
Fill(d, ls_diag); Fill(d, ls_diag);
ls_diag.fixits_ = d.edits; ls_diag.fixits_ = d.edits;
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; OS << d.message;
for (auto &n : d.notes) { for (const Note &n : d.notes) {
OS << "\n\n"; OS << "\n\n";
printDiag(OS, n); PrintDiag(OS, n);
} }
OS.flush(); OS.flush();
ls_diag.message = std::move(buf); ls_diag.message = std::move(buf);
for (auto &n : d.notes) { for (const Note &n : d.notes) {
if (!n.concerned) if (!n.concerned)
continue; continue;
Diagnostic &ls_diag1 = ls_diags.emplace_back(); Diagnostic &ls_diag1 = ls_diags.emplace_back();
Fill(n, ls_diag1); Fill(n, ls_diag1);
buf.clear();
OS << n.message << "\n\n"; OS << n.message << "\n\n";
printDiag(OS, d); PrintDiag(OS, d);
OS.flush(); OS.flush();
ls_diag1.message = std::move(buf); ls_diag1.message = std::move(buf);
} }
} }
}
{ {
std::lock_guard lock(manager->wfiles->mutex); std::lock_guard lock(manager->wfiles->mutex);