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 66e9cbd9a6
commit 633d8936a8
5 changed files with 51 additions and 22 deletions

View File

@ -90,6 +90,8 @@ struct Config {
} clang;
struct ClientCapability {
// TextDocumentClientCapabilities.publishDiagnostics.relatedInformation
bool diagnosticsRelatedInformation = true;
// TextDocumentClientCapabilities.documentSymbol.hierarchicalDocumentSymbolSupport
bool hierarchicalDocumentSymbolSupport = true;
// TextDocumentClientCapabilities.definition.linkSupport
@ -287,8 +289,8 @@ REFLECT_STRUCT(Config::ServerCap, documentOnTypeFormattingProvider,
foldingRangeProvider, workspace);
REFLECT_STRUCT(Config::Clang, excludeArgs, extraArgs, pathMappings,
resourceDir);
REFLECT_STRUCT(Config::ClientCapability, hierarchicalDocumentSymbolSupport,
linkSupport, snippetSupport);
REFLECT_STRUCT(Config::ClientCapability, diagnosticsRelatedInformation,
hierarchicalDocumentSymbolSupport, linkSupport, snippetSupport);
REFLECT_STRUCT(Config::CodeLens, localVariables);
REFLECT_STRUCT(Config::Completion::Include, blacklist, maxPathSize,
suffixWhitelist, whitelist);

View File

@ -226,12 +226,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

@ -183,7 +183,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

@ -160,6 +160,10 @@ struct TextDocumentClientCap {
struct DocumentSymbol {
bool hierarchicalDocumentSymbolSupport = false;
} documentSymbol;
struct PublishDiagnostics {
bool relatedInformation = false;
} publishDiagnostics;
};
REFLECT_STRUCT(TextDocumentClientCap::Completion::CompletionItem,
@ -168,7 +172,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;
@ -295,6 +300,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

@ -503,7 +503,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
@ -601,29 +601,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;
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 (auto &n : d.notes) {
for (const Note &n : d.notes) {
OS << "\n\n";
printDiag(OS, n);
PrintDiag(OS, n);
}
OS.flush();
ls_diag.message = std::move(buf);
for (auto &n : d.notes) {
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);
PrintDiag(OS, d);
OS.flush();
ls_diag1.message = std::move(buf);
}
}
}
{
std::lock_guard lock(manager->wfiles->mutex);