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.
This commit is contained in:
Leszek Swirski 2019-02-20 17:26:42 +01:00
parent 1a8edc137b
commit c34b382ee5
5 changed files with 50 additions and 19 deletions

View File

@ -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 {

View File

@ -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<DiagnosticRelatedInformation> relatedInformation;
std::vector<TextEdit> fixits_;
};

View File

@ -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);

View File

@ -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 &param, 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;

View File

@ -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);
}
}
}