mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Language Server: Constrain server feature set based on advertised client capabilities.
This commit is contained in:
parent
2cb618a5c3
commit
5432c5cdb0
@ -7,6 +7,7 @@ Compiler Features:
|
|||||||
* Commandline Interface: Add `--no-cbor-metadata` that skips CBOR metadata from getting appended at the end of the bytecode.
|
* Commandline Interface: Add `--no-cbor-metadata` that skips CBOR metadata from getting appended at the end of the bytecode.
|
||||||
* Standard JSON: Add a boolean field `settings.metadata.appendCBOR` that skips CBOR metadata from getting appended at the end of the bytecode.
|
* Standard JSON: Add a boolean field `settings.metadata.appendCBOR` that skips CBOR metadata from getting appended at the end of the bytecode.
|
||||||
* Yul Optimizer: Allow replacing the previously hard-coded cleanup sequence by specifying custom steps after a colon delimiter (``:``) in the sequence string.
|
* Yul Optimizer: Allow replacing the previously hard-coded cleanup sequence by specifying custom steps after a colon delimiter (``:``) in the sequence string.
|
||||||
|
* Language Server: Constrain server feature set based on advertised client capabilities.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
#include <libsolidity/lsp/GotoDefinition.h>
|
#include <libsolidity/lsp/GotoDefinition.h>
|
||||||
|
#include <libsolidity/lsp/LanguageServer.h>
|
||||||
#include <libsolidity/lsp/Transport.h> // for RequestError
|
#include <libsolidity/lsp/Transport.h> // for RequestError
|
||||||
#include <libsolidity/lsp/Utils.h>
|
#include <libsolidity/lsp/Utils.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
@ -32,6 +33,23 @@ using namespace solidity::langutil;
|
|||||||
using namespace solidity::lsp;
|
using namespace solidity::lsp;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
Json::Value GotoDefinition::onReportCapabilities(Json::Value const& _clientCapabilities)
|
||||||
|
{
|
||||||
|
Json::Value replyCapabilities = Json::objectValue;
|
||||||
|
if (_clientCapabilities["textDocument"]["definition"])
|
||||||
|
{
|
||||||
|
replyCapabilities["definitionProvider"] = true;
|
||||||
|
m_server.registerHandler("textDocument/definition", *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_clientCapabilities["textDocument"]["implementation"])
|
||||||
|
{
|
||||||
|
replyCapabilities["implementationProvider"] = true;
|
||||||
|
m_server.registerHandler("textDocument/implementation", *this);
|
||||||
|
}
|
||||||
|
return replyCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
void GotoDefinition::operator()(MessageID _id, Json::Value const& _args)
|
void GotoDefinition::operator()(MessageID _id, Json::Value const& _args)
|
||||||
{
|
{
|
||||||
auto const [sourceUnitName, lineColumn] = extractSourceUnitNameAndLineColumn(_args);
|
auto const [sourceUnitName, lineColumn] = extractSourceUnitNameAndLineColumn(_args);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
#include <libsolidity/lsp/HandlerBase.h>
|
#include <libsolidity/lsp/HandlerBase.h>
|
||||||
|
#include <libsolidity/lsp/Transport.h>
|
||||||
|
|
||||||
namespace solidity::lsp
|
namespace solidity::lsp
|
||||||
{
|
{
|
||||||
@ -25,6 +26,8 @@ class GotoDefinition: public HandlerBase
|
|||||||
public:
|
public:
|
||||||
explicit GotoDefinition(LanguageServer& _server): HandlerBase(_server) {}
|
explicit GotoDefinition(LanguageServer& _server): HandlerBase(_server) {}
|
||||||
|
|
||||||
|
Json::Value onReportCapabilities(Json::Value const& _clientCapabilities) override;
|
||||||
|
|
||||||
void operator()(MessageID, Json::Value const&);
|
void operator()(MessageID, Json::Value const&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,6 +31,21 @@ using namespace solidity::lsp;
|
|||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
CharStreamProvider const& HandlerBase::charStreamProvider() const noexcept
|
||||||
|
{
|
||||||
|
return m_server.compilerStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileRepository& HandlerBase::fileRepository() const noexcept
|
||||||
|
{
|
||||||
|
return m_server.fileRepository();
|
||||||
|
}
|
||||||
|
|
||||||
|
Transport& HandlerBase::client() const noexcept
|
||||||
|
{
|
||||||
|
return m_server.client();
|
||||||
|
}
|
||||||
|
|
||||||
Json::Value HandlerBase::toRange(SourceLocation const& _location) const
|
Json::Value HandlerBase::toRange(SourceLocation const& _location) const
|
||||||
{
|
{
|
||||||
if (!_location.hasText())
|
if (!_location.hasText())
|
||||||
|
@ -18,17 +18,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libsolidity/lsp/FileRepository.h>
|
#include <libsolidity/lsp/FileRepository.h>
|
||||||
#include <libsolidity/lsp/LanguageServer.h>
|
|
||||||
|
|
||||||
#include <liblangutil/SourceLocation.h>
|
#include <liblangutil/SourceLocation.h>
|
||||||
#include <liblangutil/CharStreamProvider.h>
|
#include <liblangutil/CharStreamProvider.h>
|
||||||
|
|
||||||
|
#include <libsolutil/JSON.h>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace solidity::lsp
|
namespace solidity::lsp
|
||||||
{
|
{
|
||||||
|
|
||||||
class Transport;
|
class Transport;
|
||||||
|
class LanguageServer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper base class for implementing handlers.
|
* Helper base class for implementing handlers.
|
||||||
@ -37,6 +39,16 @@ class HandlerBase
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit HandlerBase(LanguageServer& _server): m_server{_server} {}
|
explicit HandlerBase(LanguageServer& _server): m_server{_server} {}
|
||||||
|
virtual ~HandlerBase() = default;
|
||||||
|
|
||||||
|
/// Callback to be invoked on every custom handler that can be used to decide whether to enable
|
||||||
|
/// or disable this feature on the server side.
|
||||||
|
///
|
||||||
|
/// @param _clientCapabilities JSON node to the root of the client advertised capabilities to be used
|
||||||
|
/// to decide if the implemented feature should be enabled or not.
|
||||||
|
/// @returns JSON object, with mapping to the capabilities to reply back with.
|
||||||
|
/// Use this to write the capabilities-reply with respect the implementation.
|
||||||
|
virtual Json::Value onReportCapabilities(Json::Value const& /*_clientCapabilities*/) { return Json::objectValue; }
|
||||||
|
|
||||||
Json::Value toRange(langutil::SourceLocation const& _location) const;
|
Json::Value toRange(langutil::SourceLocation const& _location) const;
|
||||||
Json::Value toJson(langutil::SourceLocation const& _location) const;
|
Json::Value toJson(langutil::SourceLocation const& _location) const;
|
||||||
@ -45,9 +57,9 @@ public:
|
|||||||
/// from the JSON-RPC parameters.
|
/// from the JSON-RPC parameters.
|
||||||
std::pair<std::string, langutil::LineColumn> extractSourceUnitNameAndLineColumn(Json::Value const& _params) const;
|
std::pair<std::string, langutil::LineColumn> extractSourceUnitNameAndLineColumn(Json::Value const& _params) const;
|
||||||
|
|
||||||
langutil::CharStreamProvider const& charStreamProvider() const noexcept { return m_server.compilerStack(); }
|
langutil::CharStreamProvider const& charStreamProvider() const noexcept;
|
||||||
FileRepository& fileRepository() const noexcept { return m_server.fileRepository(); }
|
FileRepository& fileRepository() const noexcept;
|
||||||
Transport& client() const noexcept { return m_server.client(); }
|
Transport& client() const noexcept;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LanguageServer& m_server;
|
LanguageServer& m_server;
|
||||||
|
@ -128,11 +128,57 @@ Json::Value semanticTokensLegend()
|
|||||||
return legend;
|
return legend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SemanticTokensHandler: public HandlerBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using HandlerBase::HandlerBase;
|
||||||
|
Json::Value onReportCapabilities(Json::Value const& _clientCapabilities) override;
|
||||||
|
void operator()(MessageID _id, Json::Value const& _args);
|
||||||
|
};
|
||||||
|
|
||||||
|
Json::Value SemanticTokensHandler::onReportCapabilities(Json::Value const& _clientCapabilities)
|
||||||
|
{
|
||||||
|
Json::Value replyCapabilities = Json::objectValue;
|
||||||
|
|
||||||
|
if (_clientCapabilities["textDocument"]["semanticTokens"])
|
||||||
|
{
|
||||||
|
replyCapabilities["semanticTokensProvider"]["legend"] = semanticTokensLegend();
|
||||||
|
replyCapabilities["semanticTokensProvider"]["range"] = false;
|
||||||
|
replyCapabilities["semanticTokensProvider"]["full"] = true; // XOR requests.full.delta = true
|
||||||
|
|
||||||
|
m_server.registerHandler("textDocument/semanticTokens/full", *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return replyCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SemanticTokensHandler::operator()(MessageID _id, Json::Value const& _args)
|
||||||
|
{
|
||||||
|
auto const uri = _args["textDocument"]["uri"];
|
||||||
|
|
||||||
|
m_server.compile();
|
||||||
|
|
||||||
|
auto const sourceName = fileRepository().uriToSourceUnitName(uri.as<string>());
|
||||||
|
SourceUnit const& ast = m_server.compilerStack().ast(sourceName);
|
||||||
|
charStreamProvider().charStream(sourceName);
|
||||||
|
|
||||||
|
Json::Value data = SemanticTokensBuilder().build(ast, charStreamProvider().charStream(sourceName));
|
||||||
|
|
||||||
|
Json::Value reply = Json::objectValue;
|
||||||
|
reply["data"] = data;
|
||||||
|
|
||||||
|
client().reply(_id, std::move(reply));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LanguageServer::LanguageServer(Transport& _transport):
|
LanguageServer::LanguageServer(Transport& _transport):
|
||||||
m_client{_transport},
|
m_onDemandHandlers{
|
||||||
m_handlers{
|
make_unique<GotoDefinition>(*this),
|
||||||
|
make_unique<RenameSymbol>(*this),
|
||||||
|
make_unique<SemanticTokensHandler>(*this),
|
||||||
|
},
|
||||||
|
m_coreHandlers{
|
||||||
{"$/cancelRequest", [](auto, auto) {/*nothing for now as we are synchronous */}},
|
{"$/cancelRequest", [](auto, auto) {/*nothing for now as we are synchronous */}},
|
||||||
{"cancelRequest", [](auto, auto) {/*nothing for now as we are synchronous */}},
|
{"cancelRequest", [](auto, auto) {/*nothing for now as we are synchronous */}},
|
||||||
{"exit", [this](auto, auto) { m_state = (m_state == State::ShutdownRequested ? State::ExitRequested : State::ExitWithoutShutdown); }},
|
{"exit", [this](auto, auto) { m_state = (m_state == State::ShutdownRequested ? State::ExitRequested : State::ExitWithoutShutdown); }},
|
||||||
@ -146,14 +192,20 @@ LanguageServer::LanguageServer(Transport& _transport):
|
|||||||
{"textDocument/didClose", bind(&LanguageServer::handleTextDocumentDidClose, this, _2)},
|
{"textDocument/didClose", bind(&LanguageServer::handleTextDocumentDidClose, this, _2)},
|
||||||
{"textDocument/rename", RenameSymbol(*this) },
|
{"textDocument/rename", RenameSymbol(*this) },
|
||||||
{"textDocument/implementation", GotoDefinition(*this) },
|
{"textDocument/implementation", GotoDefinition(*this) },
|
||||||
{"textDocument/semanticTokens/full", bind(&LanguageServer::semanticTokensFull, this, _1, _2)},
|
|
||||||
{"workspace/didChangeConfiguration", bind(&LanguageServer::handleWorkspaceDidChangeConfiguration, this, _2)},
|
{"workspace/didChangeConfiguration", bind(&LanguageServer::handleWorkspaceDidChangeConfiguration, this, _2)},
|
||||||
},
|
},
|
||||||
|
m_client{_transport},
|
||||||
|
m_handlers{m_coreHandlers},
|
||||||
m_fileRepository("/" /* basePath */, {} /* no search paths */),
|
m_fileRepository("/" /* basePath */, {} /* no search paths */),
|
||||||
m_compilerStack{m_fileRepository.reader()}
|
m_compilerStack{m_fileRepository.reader()}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LanguageServer::registerHandler(std::string _name, MessageHandler _handler)
|
||||||
|
{
|
||||||
|
m_handlers[std::move(_name)] = std::move(_handler);
|
||||||
|
}
|
||||||
|
|
||||||
Json::Value LanguageServer::toRange(SourceLocation const& _location)
|
Json::Value LanguageServer::toRange(SourceLocation const& _location)
|
||||||
{
|
{
|
||||||
return HandlerBase(*this).toRange(_location);
|
return HandlerBase(*this).toRange(_location);
|
||||||
@ -409,14 +461,23 @@ void LanguageServer::handleInitialize(MessageID _id, Json::Value const& _args)
|
|||||||
Json::Value replyArgs;
|
Json::Value replyArgs;
|
||||||
replyArgs["serverInfo"]["name"] = "solc";
|
replyArgs["serverInfo"]["name"] = "solc";
|
||||||
replyArgs["serverInfo"]["version"] = string(VersionNumber);
|
replyArgs["serverInfo"]["version"] = string(VersionNumber);
|
||||||
replyArgs["capabilities"]["definitionProvider"] = true;
|
|
||||||
replyArgs["capabilities"]["implementationProvider"] = true;
|
|
||||||
replyArgs["capabilities"]["textDocumentSync"]["change"] = 2; // 0=none, 1=full, 2=incremental
|
replyArgs["capabilities"]["textDocumentSync"]["change"] = 2; // 0=none, 1=full, 2=incremental
|
||||||
replyArgs["capabilities"]["textDocumentSync"]["openClose"] = true;
|
replyArgs["capabilities"]["textDocumentSync"]["openClose"] = true;
|
||||||
replyArgs["capabilities"]["semanticTokensProvider"]["legend"] = semanticTokensLegend();
|
|
||||||
replyArgs["capabilities"]["semanticTokensProvider"]["range"] = false;
|
m_handlers = m_coreHandlers;
|
||||||
replyArgs["capabilities"]["semanticTokensProvider"]["full"] = true; // XOR requests.full.delta = true
|
m_handlers["textDocument/didOpen"] = bind(&LanguageServer::handleTextDocumentDidOpen, this, _2);
|
||||||
replyArgs["capabilities"]["renameProvider"] = true;
|
m_handlers["textDocument/didChange"] = bind(&LanguageServer::handleTextDocumentDidChange, this, _2);
|
||||||
|
m_handlers["textDocument/didClose"] = bind(&LanguageServer::handleTextDocumentDidClose, this, _2);
|
||||||
|
m_handlers["workspace/didChangeConfiguration"] = bind(&LanguageServer::handleWorkspaceDidChangeConfiguration, this, _2);
|
||||||
|
|
||||||
|
for (unique_ptr<HandlerBase>& handler: m_onDemandHandlers)
|
||||||
|
{
|
||||||
|
Json::Value replyCapabilities = handler->onReportCapabilities(_args["capabilities"]);
|
||||||
|
if (!replyCapabilities.isObject())
|
||||||
|
continue;
|
||||||
|
for (Json::String const& memberName: replyCapabilities.getMemberNames())
|
||||||
|
replyArgs["capabilities"][memberName] = replyCapabilities[memberName];
|
||||||
|
}
|
||||||
|
|
||||||
m_client.reply(_id, std::move(replyArgs));
|
m_client.reply(_id, std::move(replyArgs));
|
||||||
}
|
}
|
||||||
@ -427,23 +488,6 @@ void LanguageServer::handleInitialized(MessageID, Json::Value const&)
|
|||||||
compileAndUpdateDiagnostics();
|
compileAndUpdateDiagnostics();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageServer::semanticTokensFull(MessageID _id, Json::Value const& _args)
|
|
||||||
{
|
|
||||||
auto uri = _args["textDocument"]["uri"];
|
|
||||||
|
|
||||||
compile();
|
|
||||||
|
|
||||||
auto const sourceName = m_fileRepository.uriToSourceUnitName(uri.as<string>());
|
|
||||||
SourceUnit const& ast = m_compilerStack.ast(sourceName);
|
|
||||||
m_compilerStack.charStream(sourceName);
|
|
||||||
Json::Value data = SemanticTokensBuilder().build(ast, m_compilerStack.charStream(sourceName));
|
|
||||||
|
|
||||||
Json::Value reply = Json::objectValue;
|
|
||||||
reply["data"] = data;
|
|
||||||
|
|
||||||
m_client.reply(_id, std::move(reply));
|
|
||||||
}
|
|
||||||
|
|
||||||
void LanguageServer::handleWorkspaceDidChangeConfiguration(Json::Value const& _args)
|
void LanguageServer::handleWorkspaceDidChangeConfiguration(Json::Value const& _args)
|
||||||
{
|
{
|
||||||
requireServerInitialized();
|
requireServerInitialized();
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libsolidity/lsp/Transport.h>
|
#include <libsolidity/lsp/Transport.h>
|
||||||
|
#include <libsolidity/lsp/HandlerBase.h>
|
||||||
#include <libsolidity/lsp/FileRepository.h>
|
#include <libsolidity/lsp/FileRepository.h>
|
||||||
#include <libsolidity/interface/CompilerStack.h>
|
#include <libsolidity/interface/CompilerStack.h>
|
||||||
#include <libsolidity/interface/FileReader.h>
|
#include <libsolidity/interface/FileReader.h>
|
||||||
@ -26,6 +27,7 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -80,6 +82,13 @@ public:
|
|||||||
frontend::ASTNode const* astNodeAtSourceLocation(std::string const& _sourceUnitName, langutil::LineColumn const& _filePos);
|
frontend::ASTNode const* astNodeAtSourceLocation(std::string const& _sourceUnitName, langutil::LineColumn const& _filePos);
|
||||||
frontend::CompilerStack const& compilerStack() const noexcept { return m_compilerStack; }
|
frontend::CompilerStack const& compilerStack() const noexcept { return m_compilerStack; }
|
||||||
|
|
||||||
|
using MessageHandler = std::function<void(MessageID, Json::Value const&)>;
|
||||||
|
|
||||||
|
void registerHandler(std::string name, MessageHandler handler);
|
||||||
|
|
||||||
|
/// Compile everything until after analysis phase.
|
||||||
|
void compile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Checks if the server is initialized (to be used by messages that need it to be initialized).
|
/// Checks if the server is initialized (to be used by messages that need it to be initialized).
|
||||||
/// Reports an error and returns false if not.
|
/// Reports an error and returns false if not.
|
||||||
@ -93,18 +102,12 @@ private:
|
|||||||
void handleTextDocumentDidClose(Json::Value const& _args);
|
void handleTextDocumentDidClose(Json::Value const& _args);
|
||||||
void handleRename(Json::Value const& _args);
|
void handleRename(Json::Value const& _args);
|
||||||
void handleGotoDefinition(MessageID _id, Json::Value const& _args);
|
void handleGotoDefinition(MessageID _id, Json::Value const& _args);
|
||||||
void semanticTokensFull(MessageID _id, Json::Value const& _args);
|
|
||||||
|
|
||||||
/// Invoked when the server user-supplied configuration changes (initiated by the client).
|
/// Invoked when the server user-supplied configuration changes (initiated by the client).
|
||||||
void changeConfiguration(Json::Value const&);
|
void changeConfiguration(Json::Value const&);
|
||||||
|
|
||||||
/// Compile everything until after analysis phase.
|
|
||||||
void compile();
|
|
||||||
|
|
||||||
std::vector<boost::filesystem::path> allSolidityFilesFromProject() const;
|
std::vector<boost::filesystem::path> allSolidityFilesFromProject() const;
|
||||||
|
|
||||||
using MessageHandler = std::function<void(MessageID, Json::Value const&)>;
|
|
||||||
|
|
||||||
Json::Value toRange(langutil::SourceLocation const& _location);
|
Json::Value toRange(langutil::SourceLocation const& _location);
|
||||||
Json::Value toJson(langutil::SourceLocation const& _location);
|
Json::Value toJson(langutil::SourceLocation const& _location);
|
||||||
|
|
||||||
@ -113,6 +116,11 @@ private:
|
|||||||
enum class State { Started, Initialized, ShutdownRequested, ExitRequested, ExitWithoutShutdown };
|
enum class State { Started, Initialized, ShutdownRequested, ExitRequested, ExitWithoutShutdown };
|
||||||
State m_state = State::Started;
|
State m_state = State::Started;
|
||||||
|
|
||||||
|
// Contains the list of features that are only advertised if advertised by the client
|
||||||
|
// during initialization stage.
|
||||||
|
std::array<std::unique_ptr<HandlerBase>, 3> m_onDemandHandlers;
|
||||||
|
std::map<std::string, MessageHandler> m_coreHandlers;
|
||||||
|
|
||||||
Transport& m_client;
|
Transport& m_client;
|
||||||
std::map<std::string, MessageHandler> m_handlers;
|
std::map<std::string, MessageHandler> m_handlers;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
#include <libsolidity/lsp/RenameSymbol.h>
|
#include <libsolidity/lsp/RenameSymbol.h>
|
||||||
|
#include <libsolidity/lsp/LanguageServer.h>
|
||||||
#include <libsolidity/lsp/Utils.h>
|
#include <libsolidity/lsp/Utils.h>
|
||||||
|
|
||||||
#include <libyul/AST.h>
|
#include <libyul/AST.h>
|
||||||
@ -48,6 +49,19 @@ CallableDeclaration const* extractCallableDeclaration(FunctionCall const& _funct
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Json::Value RenameSymbol::onReportCapabilities(Json::Value const& _clientCapabilities)
|
||||||
|
{
|
||||||
|
Json::Value replyCapabilities = Json::objectValue;
|
||||||
|
|
||||||
|
if (_clientCapabilities["textDocument"]["rename"])
|
||||||
|
{
|
||||||
|
replyCapabilities["renameProvider"] = true;
|
||||||
|
m_server.registerHandler("textDocument/rename", *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return replyCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
void RenameSymbol::operator()(MessageID _id, Json::Value const& _args)
|
void RenameSymbol::operator()(MessageID _id, Json::Value const& _args)
|
||||||
{
|
{
|
||||||
auto const&& [sourceUnitName, lineColumn] = extractSourceUnitNameAndLineColumn(_args);
|
auto const&& [sourceUnitName, lineColumn] = extractSourceUnitNameAndLineColumn(_args);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
#include <libsolidity/lsp/HandlerBase.h>
|
#include <libsolidity/lsp/HandlerBase.h>
|
||||||
|
#include <libsolidity/lsp/Transport.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libsolidity/ast/ASTVisitor.h>
|
#include <libsolidity/ast/ASTVisitor.h>
|
||||||
|
|
||||||
@ -27,6 +28,8 @@ class RenameSymbol: public HandlerBase
|
|||||||
public:
|
public:
|
||||||
explicit RenameSymbol(LanguageServer& _server): HandlerBase(_server) {}
|
explicit RenameSymbol(LanguageServer& _server): HandlerBase(_server) {}
|
||||||
|
|
||||||
|
Json::Value onReportCapabilities(Json::Value const& _clientCapabilities) override;
|
||||||
|
|
||||||
void operator()(MessageID, Json::Value const&);
|
void operator()(MessageID, Json::Value const&);
|
||||||
protected:
|
protected:
|
||||||
// Nested class because otherwise `RenameSymbol` couldn't be easily used
|
// Nested class because otherwise `RenameSymbol` couldn't be easily used
|
||||||
|
@ -927,7 +927,13 @@ class SolidityLSPTestSuite: # {{{
|
|||||||
'trace': 'messages',
|
'trace': 'messages',
|
||||||
'capabilities': {
|
'capabilities': {
|
||||||
'textDocument': {
|
'textDocument': {
|
||||||
'publishDiagnostics': {'relatedInformation': True}
|
'definition': {'dynamicRegistration': True},
|
||||||
|
'documentHighlight': {'dynamicRegistration': True},
|
||||||
|
'implementation': {'dynamicRegistration': True},
|
||||||
|
'publishDiagnostics': {'relatedInformation': True},
|
||||||
|
'references': {'dynamicRegistration': True},
|
||||||
|
'rename': {'dynamicRegistration': True},
|
||||||
|
'semanticTokens': {'dynamicRegistration': True}
|
||||||
},
|
},
|
||||||
'workspace': {
|
'workspace': {
|
||||||
'applyEdit': True,
|
'applyEdit': True,
|
||||||
|
Loading…
Reference in New Issue
Block a user