mirror of
https://github.com/MaskRay/ccls.git
synced 2025-01-19 03:55:49 +00:00
Revamp codeLens & codeAction
b.ref: references of bases d.ref: references of derived when b.ref > 0, don't display 0 ref or x bases
This commit is contained in:
parent
153e5c0dcc
commit
8d61b1aadb
39
src/lsp.h
39
src/lsp.h
@ -79,6 +79,8 @@ struct lsResponseError {
|
|||||||
void Write(Writer &visitor);
|
void Write(Writer &visitor);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr std::string_view ccls_xref("ccls.xref");
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
@ -193,43 +195,6 @@ struct lsLocationEx : lsLocation {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName, parentKind, role);
|
MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName, parentKind, role);
|
||||||
|
|
||||||
template <typename T> struct lsCommand {
|
|
||||||
// Title of the command (ie, 'save')
|
|
||||||
std::string title;
|
|
||||||
// Actual command identifier.
|
|
||||||
std::string command;
|
|
||||||
// Arguments to run the command with.
|
|
||||||
// **NOTE** This must be serialized as an array. Use
|
|
||||||
// MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY.
|
|
||||||
T arguments;
|
|
||||||
};
|
|
||||||
template <typename TVisitor, typename T>
|
|
||||||
void Reflect(TVisitor &visitor, lsCommand<T> &value) {
|
|
||||||
REFLECT_MEMBER_START();
|
|
||||||
REFLECT_MEMBER(title);
|
|
||||||
REFLECT_MEMBER(command);
|
|
||||||
REFLECT_MEMBER(arguments);
|
|
||||||
REFLECT_MEMBER_END();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TData, typename TCommandArguments> struct lsCodeLens {
|
|
||||||
// The range in which this code lens is valid. Should only span a single line.
|
|
||||||
lsRange range;
|
|
||||||
// The command this code lens represents.
|
|
||||||
std::optional<lsCommand<TCommandArguments>> command;
|
|
||||||
// A data entry field that is preserved on a code lens item between
|
|
||||||
// a code lens and a code lens resolve request.
|
|
||||||
TData data;
|
|
||||||
};
|
|
||||||
template <typename TVisitor, typename TData, typename TCommandArguments>
|
|
||||||
void Reflect(TVisitor &visitor, lsCodeLens<TData, TCommandArguments> &value) {
|
|
||||||
REFLECT_MEMBER_START();
|
|
||||||
REFLECT_MEMBER(range);
|
|
||||||
REFLECT_MEMBER(command);
|
|
||||||
REFLECT_MEMBER(data);
|
|
||||||
REFLECT_MEMBER_END();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct lsTextDocumentIdentifier {
|
struct lsTextDocumentIdentifier {
|
||||||
lsDocumentUri uri;
|
lsDocumentUri uri;
|
||||||
};
|
};
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
// Copyright 2017-2018 ccls Authors
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "lsp.h"
|
|
||||||
|
|
||||||
// codeAction
|
|
||||||
struct CommandArgs {
|
|
||||||
lsDocumentUri textDocumentUri;
|
|
||||||
std::vector<lsTextEdit> edits;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(CommandArgs, textDocumentUri, edits);
|
|
||||||
|
|
||||||
// codeLens
|
|
||||||
struct lsCodeLensUserData {};
|
|
||||||
MAKE_REFLECT_EMPTY_STRUCT(lsCodeLensUserData);
|
|
||||||
|
|
||||||
struct lsCodeLensCommandArguments {
|
|
||||||
lsDocumentUri uri;
|
|
||||||
lsPosition position;
|
|
||||||
std::vector<lsLocation> locations;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT(lsCodeLensCommandArguments, uri, position, locations)
|
|
@ -69,13 +69,6 @@ struct lsDocumentLinkOptions {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsDocumentLinkOptions, resolveProvider);
|
MAKE_REFLECT_STRUCT(lsDocumentLinkOptions, resolveProvider);
|
||||||
|
|
||||||
// Execute command options.
|
|
||||||
struct lsExecuteCommandOptions {
|
|
||||||
// The commands to be executed on the server
|
|
||||||
std::vector<std::string> commands;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT(lsExecuteCommandOptions, commands);
|
|
||||||
|
|
||||||
// Save options.
|
// Save options.
|
||||||
struct lsSaveOptions {
|
struct lsSaveOptions {
|
||||||
// The client is supposed to include the content on save.
|
// The client is supposed to include the content on save.
|
||||||
@ -168,8 +161,11 @@ struct lsServerCapabilities {
|
|||||||
// The server provides document link support.
|
// The server provides document link support.
|
||||||
lsDocumentLinkOptions documentLinkProvider;
|
lsDocumentLinkOptions documentLinkProvider;
|
||||||
// The server provides execute command support.
|
// The server provides execute command support.
|
||||||
lsExecuteCommandOptions executeCommandProvider;
|
struct ExecuteCommandOptions {
|
||||||
|
std::vector<std::string> commands{std::string(ccls_xref)};
|
||||||
|
} executeCommandProvider;
|
||||||
};
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(lsServerCapabilities::ExecuteCommandOptions, commands);
|
||||||
MAKE_REFLECT_STRUCT(lsServerCapabilities, textDocumentSync, hoverProvider,
|
MAKE_REFLECT_STRUCT(lsServerCapabilities, textDocumentSync, hoverProvider,
|
||||||
completionProvider, signatureHelpProvider,
|
completionProvider, signatureHelpProvider,
|
||||||
definitionProvider, implementationProvider,
|
definitionProvider, implementationProvider,
|
||||||
|
@ -6,12 +6,6 @@
|
|||||||
#include "working_files.h"
|
#include "working_files.h"
|
||||||
using namespace ccls;
|
using namespace ccls;
|
||||||
|
|
||||||
struct CommandArgs {
|
|
||||||
lsDocumentUri textDocumentUri;
|
|
||||||
std::vector<lsTextEdit> edits;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(CommandArgs, textDocumentUri, edits);
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
MethodType kMethodType = "textDocument/codeAction";
|
MethodType kMethodType = "textDocument/codeAction";
|
||||||
|
|
||||||
@ -41,10 +35,17 @@ MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionParams, textDocument,
|
|||||||
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction, id, params);
|
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction, id, params);
|
||||||
REGISTER_IN_MESSAGE(In_TextDocumentCodeAction);
|
REGISTER_IN_MESSAGE(In_TextDocumentCodeAction);
|
||||||
|
|
||||||
|
struct lsCodeAction {
|
||||||
|
std::string title;
|
||||||
|
const char *kind = "quickfix";
|
||||||
|
lsWorkspaceEdit edit;
|
||||||
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(lsCodeAction, title, kind, edit);
|
||||||
|
|
||||||
struct Out_TextDocumentCodeAction
|
struct Out_TextDocumentCodeAction
|
||||||
: public lsOutMessage<Out_TextDocumentCodeAction> {
|
: public lsOutMessage<Out_TextDocumentCodeAction> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
std::vector<lsCommand<CommandArgs>> result;
|
std::vector<lsCodeAction> result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeAction, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeAction, jsonrpc, id, result);
|
||||||
|
|
||||||
@ -64,12 +65,12 @@ struct Handler_TextDocumentCodeAction
|
|||||||
working_files->DoAction([&]() { diagnostics = wfile->diagnostics_; });
|
working_files->DoAction([&]() { diagnostics = wfile->diagnostics_; });
|
||||||
for (lsDiagnostic &diag : diagnostics)
|
for (lsDiagnostic &diag : diagnostics)
|
||||||
if (diag.fixits_.size()) {
|
if (diag.fixits_.size()) {
|
||||||
lsCommand<CommandArgs> command;
|
lsCodeAction &cmd = out.result.emplace_back();
|
||||||
command.title = "FixIt: " + diag.message;
|
cmd.title = "FixIt: " + diag.message;
|
||||||
command.command = "ccls._applyFixIt";
|
auto &edit = cmd.edit.documentChanges.emplace_back();
|
||||||
command.arguments.textDocumentUri = params.textDocument.uri;
|
edit.textDocument.uri = params.textDocument.uri;
|
||||||
command.arguments.edits = diag.fixits_;
|
edit.textDocument.version = wfile->version;
|
||||||
out.result.push_back(command);
|
edit.edits = diag.fixits_;
|
||||||
}
|
}
|
||||||
pipeline::WriteStdout(kMethodType, out);
|
pipeline::WriteStdout(kMethodType, out);
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,64 @@
|
|||||||
// Copyright 2017-2018 ccls Authors
|
// Copyright 2017-2018 ccls Authors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
#include "clang_complete.hh"
|
|
||||||
#include "lsp_code_action.h"
|
|
||||||
#include "message_handler.h"
|
#include "message_handler.h"
|
||||||
#include "pipeline.hh"
|
#include "pipeline.hh"
|
||||||
#include "query_utils.h"
|
#include "query_utils.h"
|
||||||
using namespace ccls;
|
#include "serializers/json.h"
|
||||||
|
|
||||||
|
#include <llvm/Support/FormatVariadic.h>
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace {
|
using namespace ccls;
|
||||||
MethodType kMethodType = "textDocument/codeLens";
|
|
||||||
|
namespace {
|
||||||
|
const MethodType codeLens = "textDocument/codeLens",
|
||||||
|
executeCommand = "workspace/executeCommand";
|
||||||
|
|
||||||
|
struct lsCommand {
|
||||||
|
std::string title;
|
||||||
|
std::string command;
|
||||||
|
std::vector<std::string> arguments;
|
||||||
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(lsCommand, title, command, arguments);
|
||||||
|
|
||||||
|
struct lsCodeLens {
|
||||||
|
lsRange range;
|
||||||
|
std::optional<lsCommand> command;
|
||||||
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(lsCodeLens, range, command);
|
||||||
|
|
||||||
|
struct Cmd_xref {
|
||||||
|
Usr usr;
|
||||||
|
SymbolKind kind;
|
||||||
|
std::string field;
|
||||||
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(Cmd_xref, usr, kind, field);
|
||||||
|
|
||||||
|
struct Out_xref : public lsOutMessage<Out_xref> {
|
||||||
|
lsRequestId id;
|
||||||
|
std::vector<lsLocation> result;
|
||||||
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(Out_xref, jsonrpc, id, result);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string ToString(T &v) {
|
||||||
|
rapidjson::StringBuffer output;
|
||||||
|
rapidjson::Writer<rapidjson::StringBuffer> writer(output);
|
||||||
|
JsonWriter json_writer(&writer);
|
||||||
|
Reflect(json_writer, v);
|
||||||
|
return output.GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CommonCodeLensParams {
|
||||||
|
std::vector<lsCodeLens> *result;
|
||||||
|
DB *db;
|
||||||
|
WorkingFile *wfile;
|
||||||
|
};
|
||||||
|
|
||||||
using TCodeLens = lsCodeLens<lsCodeLensUserData, lsCodeLensCommandArguments>;
|
|
||||||
struct In_TextDocumentCodeLens : public RequestInMessage {
|
struct In_TextDocumentCodeLens : public RequestInMessage {
|
||||||
MethodType GetMethodType() const override { return kMethodType; }
|
MethodType GetMethodType() const override { return codeLens; }
|
||||||
struct Params {
|
struct Params {
|
||||||
lsTextDocumentIdentifier textDocument;
|
lsTextDocumentIdentifier textDocument;
|
||||||
} params;
|
} params;
|
||||||
@ -27,179 +70,85 @@ REGISTER_IN_MESSAGE(In_TextDocumentCodeLens);
|
|||||||
struct Out_TextDocumentCodeLens
|
struct Out_TextDocumentCodeLens
|
||||||
: public lsOutMessage<Out_TextDocumentCodeLens> {
|
: public lsOutMessage<Out_TextDocumentCodeLens> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
std::vector<lsCodeLens<lsCodeLensUserData, lsCodeLensCommandArguments>>
|
std::vector<lsCodeLens> result;
|
||||||
result;
|
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result);
|
||||||
|
|
||||||
struct CommonCodeLensParams {
|
|
||||||
std::vector<TCodeLens> *result;
|
|
||||||
DB *db;
|
|
||||||
WorkingFiles *working_files;
|
|
||||||
WorkingFile *working_file;
|
|
||||||
};
|
|
||||||
|
|
||||||
Use OffsetStartColumn(Use use, int16_t offset) {
|
|
||||||
use.range.start.column += offset;
|
|
||||||
return use;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddCodeLens(const char *singular, const char *plural,
|
|
||||||
CommonCodeLensParams *common, Use use,
|
|
||||||
const std::vector<Use> &uses, bool force_display) {
|
|
||||||
TCodeLens code_lens;
|
|
||||||
std::optional<lsRange> range = GetLsRange(common->working_file, use.range);
|
|
||||||
if (!range)
|
|
||||||
return;
|
|
||||||
if (use.file_id < 0)
|
|
||||||
return;
|
|
||||||
code_lens.range = *range;
|
|
||||||
code_lens.command = lsCommand<lsCodeLensCommandArguments>();
|
|
||||||
code_lens.command->command = "ccls.showReferences";
|
|
||||||
code_lens.command->arguments.uri = GetLsDocumentUri(common->db, use.file_id);
|
|
||||||
code_lens.command->arguments.position = code_lens.range.start;
|
|
||||||
|
|
||||||
// Add unique uses.
|
|
||||||
std::vector<lsLocation> unique_uses;
|
|
||||||
for (Use use1 : uses) {
|
|
||||||
if (auto ls_loc = GetLsLocation(common->db, common->working_files, use1))
|
|
||||||
unique_uses.push_back(*ls_loc);
|
|
||||||
}
|
|
||||||
code_lens.command->arguments.locations.assign(unique_uses.begin(),
|
|
||||||
unique_uses.end());
|
|
||||||
|
|
||||||
// User visible label
|
|
||||||
size_t num_usages = unique_uses.size();
|
|
||||||
code_lens.command->title = std::to_string(num_usages) + " ";
|
|
||||||
if (num_usages == 1)
|
|
||||||
code_lens.command->title += singular;
|
|
||||||
else
|
|
||||||
code_lens.command->title += plural;
|
|
||||||
|
|
||||||
if (force_display || unique_uses.size() > 0)
|
|
||||||
common->result->push_back(code_lens);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Handler_TextDocumentCodeLens
|
struct Handler_TextDocumentCodeLens
|
||||||
: BaseMessageHandler<In_TextDocumentCodeLens> {
|
: BaseMessageHandler<In_TextDocumentCodeLens> {
|
||||||
MethodType GetMethodType() const override { return kMethodType; }
|
MethodType GetMethodType() const override { return codeLens; }
|
||||||
void Run(In_TextDocumentCodeLens *request) override {
|
void Run(In_TextDocumentCodeLens *request) override {
|
||||||
auto ¶ms = request->params;
|
auto ¶ms = request->params;
|
||||||
Out_TextDocumentCodeLens out;
|
Out_TextDocumentCodeLens out;
|
||||||
out.id = request->id;
|
out.id = request->id;
|
||||||
|
|
||||||
std::string path = params.textDocument.uri.GetPath();
|
std::string path = params.textDocument.uri.GetPath();
|
||||||
clang_complete->NotifyView(path);
|
|
||||||
|
|
||||||
QueryFile *file;
|
QueryFile *file;
|
||||||
if (!FindFileOrFail(db, project, request->id,
|
if (!FindFileOrFail(db, project, request->id, path, &file))
|
||||||
params.textDocument.uri.GetPath(), &file))
|
|
||||||
return;
|
return;
|
||||||
|
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
|
||||||
|
|
||||||
CommonCodeLensParams common;
|
auto Add = [&](const char *singular, Cmd_xref show, Use use, int num,
|
||||||
common.result = &out.result;
|
bool force_display = false) {
|
||||||
common.db = db;
|
if (!num && !force_display)
|
||||||
common.working_files = working_files;
|
return;
|
||||||
common.working_file = working_files->GetFileByFilename(file->def->path);
|
std::optional<lsRange> range = GetLsRange(wfile, use.range);
|
||||||
|
if (!range)
|
||||||
|
return;
|
||||||
|
lsCodeLens &code_lens = out.result.emplace_back();
|
||||||
|
code_lens.range = *range;
|
||||||
|
code_lens.command = lsCommand();
|
||||||
|
code_lens.command->command = std::string(ccls_xref);
|
||||||
|
bool plural = num > 1 && singular[strlen(singular) - 1] != 'd';
|
||||||
|
code_lens.command->title =
|
||||||
|
llvm::formatv("{0} {1}{2}", num, singular, plural ? "s" : "").str();
|
||||||
|
code_lens.command->arguments.push_back(ToString(show));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto ToSpell = [&](Use use) {
|
||||||
|
Maybe<Use> def = GetDefinitionSpell(db, use);
|
||||||
|
if (def && def->file_id == use.file_id &&
|
||||||
|
def->range.start.line == use.range.start.line)
|
||||||
|
return *def;
|
||||||
|
return use;
|
||||||
|
};
|
||||||
|
|
||||||
std::unordered_set<Range> seen;
|
std::unordered_set<Range> seen;
|
||||||
for (auto [sym, refcnt] : file->outline2refcnt) {
|
for (auto [sym, refcnt] : file->outline2refcnt) {
|
||||||
if (refcnt <= 0 || !seen.insert(sym.range).second)
|
if (refcnt <= 0 || !seen.insert(sym.range).second)
|
||||||
continue;
|
continue;
|
||||||
// NOTE: We OffsetColumn so that the code lens always show up in a
|
Use use = ToSpell({{sym.range, sym.usr, sym.kind, sym.role}, file->id});
|
||||||
// predictable order. Otherwise, the client may randomize it.
|
|
||||||
Use use{{sym.range, sym.usr, sym.kind, sym.role}, file->id};
|
|
||||||
|
|
||||||
switch (sym.kind) {
|
switch (sym.kind) {
|
||||||
case SymbolKind::Type: {
|
|
||||||
QueryType &type = db->GetType(sym);
|
|
||||||
const QueryType::Def *def = type.AnyDef();
|
|
||||||
if (!def || def->kind == lsSymbolKind::Namespace)
|
|
||||||
continue;
|
|
||||||
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0),
|
|
||||||
type.uses, true /*force_display*/);
|
|
||||||
AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, 1),
|
|
||||||
GetTypeDeclarations(db, type.derived),
|
|
||||||
false /*force_display*/);
|
|
||||||
AddCodeLens("var", "vars", &common, OffsetStartColumn(use, 2),
|
|
||||||
GetVarDeclarations(db, type.instances, true),
|
|
||||||
false /*force_display*/);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SymbolKind::Func: {
|
case SymbolKind::Func: {
|
||||||
QueryFunc &func = db->GetFunc(sym);
|
QueryFunc &func = db->GetFunc(sym);
|
||||||
const QueryFunc::Def *def = func.AnyDef();
|
const QueryFunc::Def *def = func.AnyDef();
|
||||||
if (!def)
|
if (!def)
|
||||||
continue;
|
continue;
|
||||||
|
std::vector<Use> base_uses = GetUsesForAllBases(db, func);
|
||||||
int16_t offset = 0;
|
std::vector<Use> derived_uses = GetUsesForAllDerived(db, func);
|
||||||
|
Add("ref", {sym.usr, SymbolKind::Func, "uses"}, use, func.uses.size(),
|
||||||
// For functions, the outline will report a location that is using the
|
base_uses.empty());
|
||||||
// extent since that is better for outline. This tries to convert the
|
if (base_uses.size())
|
||||||
// extent location to the spelling location.
|
Add("b.ref", {sym.usr, SymbolKind::Func, "bases uses"}, use,
|
||||||
auto try_ensure_spelling = [&](Use use) {
|
base_uses.size());
|
||||||
Maybe<Use> def = GetDefinitionSpell(db, use);
|
if (derived_uses.size())
|
||||||
if (!def || def->range.start.line != use.range.start.line) {
|
Add("d.ref", {sym.usr, SymbolKind::Func, "derived uses"}, use,
|
||||||
return use;
|
derived_uses.size());
|
||||||
|
if (base_uses.empty())
|
||||||
|
Add("base", {sym.usr, SymbolKind::Func, "bases"}, use,
|
||||||
|
def->bases.size());
|
||||||
|
Add("derived", {sym.usr, SymbolKind::Func, "derived"}, use,
|
||||||
|
func.derived.size());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return *def;
|
case SymbolKind::Type: {
|
||||||
};
|
QueryType &type = db->GetType(sym);
|
||||||
|
Add("ref", {sym.usr, SymbolKind::Type, "uses"}, use, type.uses.size(),
|
||||||
std::vector<Use> base_callers = GetUsesForAllBases(db, func);
|
true);
|
||||||
std::vector<Use> derived_callers = GetUsesForAllDerived(db, func);
|
Add("derived", {sym.usr, SymbolKind::Type, "derived"}, use,
|
||||||
if (base_callers.empty() && derived_callers.empty()) {
|
type.derived.size());
|
||||||
Use loc = try_ensure_spelling(use);
|
Add("var", {sym.usr, SymbolKind::Type, "instances"}, use,
|
||||||
AddCodeLens("call", "calls", &common,
|
type.instances.size());
|
||||||
OffsetStartColumn(loc, offset++), func.uses,
|
|
||||||
true /*force_display*/);
|
|
||||||
} else {
|
|
||||||
Use loc = try_ensure_spelling(use);
|
|
||||||
AddCodeLens("direct call", "direct calls", &common,
|
|
||||||
OffsetStartColumn(loc, offset++), func.uses,
|
|
||||||
false /*force_display*/);
|
|
||||||
if (!base_callers.empty())
|
|
||||||
AddCodeLens("base call", "base calls", &common,
|
|
||||||
OffsetStartColumn(loc, offset++), base_callers,
|
|
||||||
false /*force_display*/);
|
|
||||||
if (!derived_callers.empty())
|
|
||||||
AddCodeLens("derived call", "derived calls", &common,
|
|
||||||
OffsetStartColumn(loc, offset++), derived_callers,
|
|
||||||
false /*force_display*/);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddCodeLens(
|
|
||||||
"derived", "derived", &common, OffsetStartColumn(use, offset++),
|
|
||||||
GetFuncDeclarations(db, func.derived), false /*force_display*/);
|
|
||||||
|
|
||||||
// "Base"
|
|
||||||
if (def->bases.size() == 1) {
|
|
||||||
Maybe<Use> base_loc = GetDefinitionSpell(
|
|
||||||
db, SymbolIdx{def->bases[0], SymbolKind::Func});
|
|
||||||
if (base_loc) {
|
|
||||||
std::optional<lsLocation> ls_base =
|
|
||||||
GetLsLocation(db, working_files, *base_loc);
|
|
||||||
if (ls_base) {
|
|
||||||
std::optional<lsRange> range =
|
|
||||||
GetLsRange(common.working_file, sym.range);
|
|
||||||
if (range) {
|
|
||||||
TCodeLens code_lens;
|
|
||||||
code_lens.range = *range;
|
|
||||||
code_lens.range.start.character += offset++;
|
|
||||||
code_lens.command = lsCommand<lsCodeLensCommandArguments>();
|
|
||||||
code_lens.command->title = "Base";
|
|
||||||
code_lens.command->command = "ccls.goto";
|
|
||||||
code_lens.command->arguments.uri = ls_base->uri;
|
|
||||||
code_lens.command->arguments.position = ls_base->range.start;
|
|
||||||
out.result.push_back(code_lens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
AddCodeLens("base", "base", &common, OffsetStartColumn(use, 1),
|
|
||||||
GetTypeDeclarations(db, def->bases),
|
|
||||||
false /*force_display*/);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Var: {
|
case SymbolKind::Var: {
|
||||||
@ -207,27 +156,88 @@ struct Handler_TextDocumentCodeLens
|
|||||||
const QueryVar::Def *def = var.AnyDef();
|
const QueryVar::Def *def = var.AnyDef();
|
||||||
if (!def || (def->is_local() && !g_config->codeLens.localVariables))
|
if (!def || (def->is_local() && !g_config->codeLens.localVariables))
|
||||||
continue;
|
continue;
|
||||||
|
Add("ref", {sym.usr, SymbolKind::Var, "uses"}, use, var.uses.size(),
|
||||||
bool force_display = true;
|
def->kind != lsSymbolKind::Macro);
|
||||||
// Do not show 0 refs on macro with no uses, as it is most likely
|
|
||||||
// a header guard.
|
|
||||||
if (def->kind == lsSymbolKind::Macro)
|
|
||||||
force_display = false;
|
|
||||||
|
|
||||||
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0), var.uses,
|
|
||||||
force_display);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::File:
|
case SymbolKind::File:
|
||||||
case SymbolKind::Invalid: {
|
case SymbolKind::Invalid:
|
||||||
assert(false && "unexpected");
|
llvm_unreachable("");
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline::WriteStdout(kMethodType, out);
|
pipeline::WriteStdout(codeLens, out);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens);
|
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens);
|
||||||
|
|
||||||
|
struct In_WorkspaceExecuteCommand : public RequestInMessage {
|
||||||
|
MethodType GetMethodType() const override { return executeCommand; }
|
||||||
|
lsCommand params;
|
||||||
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(In_WorkspaceExecuteCommand, id, params);
|
||||||
|
REGISTER_IN_MESSAGE(In_WorkspaceExecuteCommand);
|
||||||
|
|
||||||
|
struct Handler_WorkspaceExecuteCommand
|
||||||
|
: BaseMessageHandler<In_WorkspaceExecuteCommand> {
|
||||||
|
MethodType GetMethodType() const override { return executeCommand; }
|
||||||
|
void Run(In_WorkspaceExecuteCommand *request) override {
|
||||||
|
const auto ¶ms = request->params;
|
||||||
|
if (params.arguments.empty())
|
||||||
|
return;
|
||||||
|
rapidjson::Document reader;
|
||||||
|
reader.Parse(params.arguments[0].c_str());
|
||||||
|
JsonReader json_reader{&reader};
|
||||||
|
if (params.command == ccls_xref) {
|
||||||
|
Cmd_xref cmd;
|
||||||
|
Reflect(json_reader, cmd);
|
||||||
|
Out_xref out;
|
||||||
|
out.id = request->id;
|
||||||
|
auto Map = [&](auto &&uses) {
|
||||||
|
for (auto &use : uses)
|
||||||
|
if (auto loc = GetLsLocation(db, working_files, use))
|
||||||
|
out.result.push_back(std::move(*loc));
|
||||||
|
};
|
||||||
|
switch (cmd.kind) {
|
||||||
|
case SymbolKind::Func: {
|
||||||
|
QueryFunc &func = db->Func(cmd.usr);
|
||||||
|
if (cmd.field == "bases") {
|
||||||
|
if (auto *def = func.AnyDef())
|
||||||
|
Map(GetFuncDeclarations(db, def->bases));
|
||||||
|
} else if (cmd.field == "bases uses") {
|
||||||
|
Map(GetUsesForAllBases(db, func));
|
||||||
|
} else if (cmd.field == "derived") {
|
||||||
|
Map(GetFuncDeclarations(db, func.derived));
|
||||||
|
} else if (cmd.field == "derived uses") {
|
||||||
|
Map(GetUsesForAllDerived(db, func));
|
||||||
|
} else if (cmd.field == "uses") {
|
||||||
|
Map(func.uses);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SymbolKind::Type: {
|
||||||
|
QueryType &type = db->Type(cmd.usr);
|
||||||
|
if (cmd.field == "derived") {
|
||||||
|
Map(GetTypeDeclarations(db, type.derived));
|
||||||
|
} else if (cmd.field == "instances") {
|
||||||
|
Map(GetVarDeclarations(db, type.instances, 7));
|
||||||
|
} else if (cmd.field == "uses") {
|
||||||
|
Map(type.uses);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SymbolKind::Var: {
|
||||||
|
QueryVar &var = db->Var(cmd.usr);
|
||||||
|
if (cmd.field == "uses")
|
||||||
|
Map(var.uses);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pipeline::WriteStdout(executeCommand, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand);
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
// Copyright 2017-2018 ccls Authors
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
#include "lsp_code_action.h"
|
|
||||||
#include "message_handler.h"
|
|
||||||
#include "pipeline.hh"
|
|
||||||
#include "query_utils.h"
|
|
||||||
using namespace ccls;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
MethodType kMethodType = "workspace/executeCommand";
|
|
||||||
|
|
||||||
struct In_WorkspaceExecuteCommand : public RequestInMessage {
|
|
||||||
MethodType GetMethodType() const override { return kMethodType; }
|
|
||||||
lsCommand<lsCodeLensCommandArguments> params;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT(In_WorkspaceExecuteCommand, id, params);
|
|
||||||
REGISTER_IN_MESSAGE(In_WorkspaceExecuteCommand);
|
|
||||||
|
|
||||||
struct Out_WorkspaceExecuteCommand
|
|
||||||
: public lsOutMessage<Out_WorkspaceExecuteCommand> {
|
|
||||||
lsRequestId id;
|
|
||||||
std::variant<std::vector<lsLocation>, CommandArgs> result;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT(Out_WorkspaceExecuteCommand, jsonrpc, id, result);
|
|
||||||
|
|
||||||
struct Handler_WorkspaceExecuteCommand
|
|
||||||
: BaseMessageHandler<In_WorkspaceExecuteCommand> {
|
|
||||||
MethodType GetMethodType() const override { return kMethodType; }
|
|
||||||
void Run(In_WorkspaceExecuteCommand *request) override {
|
|
||||||
const auto ¶ms = request->params;
|
|
||||||
Out_WorkspaceExecuteCommand out;
|
|
||||||
out.id = request->id;
|
|
||||||
if (params.command == "ccls._applyFixIt") {
|
|
||||||
} else if (params.command == "ccls._autoImplement") {
|
|
||||||
} else if (params.command == "ccls._insertInclude") {
|
|
||||||
} else if (params.command == "ccls.showReferences") {
|
|
||||||
out.result = params.arguments.locations;
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline::WriteStdout(kMethodType, out);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand);
|
|
||||||
|
|
||||||
} // namespace
|
|
Loading…
Reference in New Issue
Block a user