mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
LSP: Implements find all references and semantic highlighting.
This commit is contained in:
parent
238ac4fd92
commit
dd5d861dec
@ -22,6 +22,7 @@ Compiler Features:
|
|||||||
* Code Generator: More efficient overflow checks for multiplication.
|
* Code Generator: More efficient overflow checks for multiplication.
|
||||||
* Language Server: Analyze all files in a project by default (can be customized by setting ``'file-load-strategy'`` to ``'directly-opened-and-on-import'`` in LSP settings object).
|
* Language Server: Analyze all files in a project by default (can be customized by setting ``'file-load-strategy'`` to ``'directly-opened-and-on-import'`` in LSP settings object).
|
||||||
* Yul Optimizer: Simplify the starting offset of zero-length operations to zero.
|
* Yul Optimizer: Simplify the starting offset of zero-length operations to zero.
|
||||||
|
* Language Server: Implements finding all references as well as semantic highlighting of symbols.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
@ -165,8 +165,14 @@ set(sources
|
|||||||
lsp/HandlerBase.h
|
lsp/HandlerBase.h
|
||||||
lsp/LanguageServer.cpp
|
lsp/LanguageServer.cpp
|
||||||
lsp/LanguageServer.h
|
lsp/LanguageServer.h
|
||||||
|
lsp/SemanticHighlight.cpp
|
||||||
|
lsp/SemanticHighlight.h
|
||||||
lsp/SemanticTokensBuilder.cpp
|
lsp/SemanticTokensBuilder.cpp
|
||||||
lsp/SemanticTokensBuilder.h
|
lsp/SemanticTokensBuilder.h
|
||||||
|
lsp/ReferenceCollector.cpp
|
||||||
|
lsp/ReferenceCollector.h
|
||||||
|
lsp/References.cpp
|
||||||
|
lsp/References.h
|
||||||
lsp/Transport.cpp
|
lsp/Transport.cpp
|
||||||
lsp/Transport.h
|
lsp/Transport.h
|
||||||
lsp/Utils.cpp
|
lsp/Utils.cpp
|
||||||
|
@ -26,7 +26,9 @@
|
|||||||
|
|
||||||
// LSP feature implementations
|
// LSP feature implementations
|
||||||
#include <libsolidity/lsp/GotoDefinition.h>
|
#include <libsolidity/lsp/GotoDefinition.h>
|
||||||
|
#include <libsolidity/lsp/References.h>
|
||||||
#include <libsolidity/lsp/RenameSymbol.h>
|
#include <libsolidity/lsp/RenameSymbol.h>
|
||||||
|
#include <libsolidity/lsp/SemanticHighlight.h>
|
||||||
#include <libsolidity/lsp/SemanticTokensBuilder.h>
|
#include <libsolidity/lsp/SemanticTokensBuilder.h>
|
||||||
|
|
||||||
#include <liblangutil/SourceReferenceExtractor.h>
|
#include <liblangutil/SourceReferenceExtractor.h>
|
||||||
@ -145,8 +147,10 @@ LanguageServer::LanguageServer(Transport& _transport):
|
|||||||
{"textDocument/didChange", bind(&LanguageServer::handleTextDocumentDidChange, this, _2)},
|
{"textDocument/didChange", bind(&LanguageServer::handleTextDocumentDidChange, this, _2)},
|
||||||
{"textDocument/didClose", bind(&LanguageServer::handleTextDocumentDidClose, this, _2)},
|
{"textDocument/didClose", bind(&LanguageServer::handleTextDocumentDidClose, this, _2)},
|
||||||
{"textDocument/rename", RenameSymbol(*this) },
|
{"textDocument/rename", RenameSymbol(*this) },
|
||||||
|
{"textDocument/documentHighlight", SemanticHighlight(*this) },
|
||||||
{"textDocument/implementation", GotoDefinition(*this) },
|
{"textDocument/implementation", GotoDefinition(*this) },
|
||||||
{"textDocument/semanticTokens/full", bind(&LanguageServer::semanticTokensFull, this, _1, _2)},
|
{"textDocument/semanticTokens/full", bind(&LanguageServer::semanticTokensFull, this, _1, _2)},
|
||||||
|
{"textDocument/references", References(*this) },
|
||||||
{"workspace/didChangeConfiguration", bind(&LanguageServer::handleWorkspaceDidChangeConfiguration, this, _2)},
|
{"workspace/didChangeConfiguration", bind(&LanguageServer::handleWorkspaceDidChangeConfiguration, this, _2)},
|
||||||
},
|
},
|
||||||
m_fileRepository("/" /* basePath */, {} /* no search paths */),
|
m_fileRepository("/" /* basePath */, {} /* no search paths */),
|
||||||
@ -411,6 +415,8 @@ void LanguageServer::handleInitialize(MessageID _id, Json::Value const& _args)
|
|||||||
replyArgs["serverInfo"]["version"] = string(VersionNumber);
|
replyArgs["serverInfo"]["version"] = string(VersionNumber);
|
||||||
replyArgs["capabilities"]["definitionProvider"] = true;
|
replyArgs["capabilities"]["definitionProvider"] = true;
|
||||||
replyArgs["capabilities"]["implementationProvider"] = true;
|
replyArgs["capabilities"]["implementationProvider"] = true;
|
||||||
|
replyArgs["capabilities"]["documentHighlightProvider"] = true;
|
||||||
|
replyArgs["capabilities"]["referencesProvider"] = 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"]["legend"] = semanticTokensLegend();
|
||||||
|
@ -77,6 +77,7 @@ public:
|
|||||||
|
|
||||||
FileRepository& fileRepository() noexcept { return m_fileRepository; }
|
FileRepository& fileRepository() noexcept { return m_fileRepository; }
|
||||||
Transport& client() noexcept { return m_client; }
|
Transport& client() noexcept { return m_client; }
|
||||||
|
frontend::SourceUnit const& ast(std::string const& _sourceUnitName) const { return m_compilerStack.ast(_sourceUnitName); }
|
||||||
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; }
|
||||||
|
|
||||||
|
192
libsolidity/lsp/ReferenceCollector.cpp
Normal file
192
libsolidity/lsp/ReferenceCollector.cpp
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
#include <libsolidity/lsp/ReferenceCollector.h>
|
||||||
|
#include <libsolidity/lsp/Utils.h>
|
||||||
|
|
||||||
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/lsp/LanguageServer.h>
|
||||||
|
|
||||||
|
#include <libsolutil/Common.h>
|
||||||
|
|
||||||
|
using namespace solidity::frontend;
|
||||||
|
using namespace solidity::langutil;
|
||||||
|
using namespace std::string_literals;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace solidity::lsp
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
vector<Declaration const*> allAnnotatedDeclarations(Identifier const* _identifier)
|
||||||
|
{
|
||||||
|
vector<Declaration const*> output;
|
||||||
|
output.push_back(_identifier->annotation().referencedDeclaration);
|
||||||
|
output += _identifier->annotation().candidateDeclarations;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ReferenceCollector::ReferenceCollector(
|
||||||
|
Declaration const& _declaration,
|
||||||
|
std::string const& _sourceIdentifierName
|
||||||
|
):
|
||||||
|
m_declaration{_declaration},
|
||||||
|
m_sourceIdentifierName{_sourceIdentifierName.empty() ? _declaration.name() : _sourceIdentifierName}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Reference> ReferenceCollector::collect(
|
||||||
|
Declaration const* _declaration,
|
||||||
|
ASTNode const& _ast,
|
||||||
|
std::string const& _sourceIdentifierName
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!_declaration)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
ReferenceCollector collector(*_declaration, _sourceIdentifierName);
|
||||||
|
_ast.accept(collector);
|
||||||
|
return std::move(collector.m_resultingReferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Reference> ReferenceCollector::collect(
|
||||||
|
ASTNode const* _sourceNode,
|
||||||
|
SourceUnit const& _sourceUnit
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!_sourceNode)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto output = vector<Reference>{};
|
||||||
|
|
||||||
|
if (auto const* identifier = dynamic_cast<Identifier const*>(_sourceNode))
|
||||||
|
{
|
||||||
|
for (auto const* declaration: allAnnotatedDeclarations(identifier))
|
||||||
|
output += collect(declaration, _sourceUnit, identifier->name());
|
||||||
|
}
|
||||||
|
else if (auto const* identifierPath = dynamic_cast<IdentifierPath const*>(_sourceNode))
|
||||||
|
{
|
||||||
|
solAssert(identifierPath->path().size() >= 1, "");
|
||||||
|
output += collect(identifierPath->annotation().referencedDeclaration, _sourceUnit, identifierPath->path().back());
|
||||||
|
}
|
||||||
|
else if (auto const* memberAccess = dynamic_cast<MemberAccess const*>(_sourceNode))
|
||||||
|
output += collect(memberAccess->annotation().referencedDeclaration, _sourceUnit, memberAccess->memberName());
|
||||||
|
else if (auto const* declaration = dynamic_cast<Declaration const*>(_sourceNode))
|
||||||
|
output += collect(declaration, _sourceUnit, declaration->name());
|
||||||
|
else
|
||||||
|
lspAssert(false, ErrorCode::InternalError, "Unhandled AST node "s + typeid(*_sourceNode).name());
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReferenceCollector::visit(ImportDirective const& _import)
|
||||||
|
{
|
||||||
|
if (_import.name() == m_sourceIdentifierName)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReferenceCollector::endVisit(ImportDirective const& _import)
|
||||||
|
{
|
||||||
|
for (auto const& symbolAlias: _import.symbolAliases())
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
m_sourceIdentifierName == *symbolAlias.alias &&
|
||||||
|
symbolAlias.symbol &&
|
||||||
|
symbolAlias.symbol->annotation().referencedDeclaration == &m_declaration
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_resultingReferences.emplace_back(symbolAlias.location, DocumentHighlightKind::Read);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (m_sourceIdentifierName == *symbolAlias.alias)
|
||||||
|
{
|
||||||
|
m_resultingReferences.emplace_back(symbolAlias.location, DocumentHighlightKind::Text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReferenceCollector::tryAddReference(Declaration const* _declaration, SourceLocation const& _location)
|
||||||
|
{
|
||||||
|
if (&m_declaration != _declaration)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_resultingReferences.emplace_back(_location, m_kind);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReferenceCollector::endVisit(Identifier const& _identifier)
|
||||||
|
{
|
||||||
|
if (auto const* declaration = _identifier.annotation().referencedDeclaration)
|
||||||
|
tryAddReference(declaration, _identifier.location());
|
||||||
|
|
||||||
|
for (auto const* declaration: _identifier.annotation().candidateDeclarations + _identifier.annotation().overloadedDeclarations)
|
||||||
|
tryAddReference(declaration, _identifier.location());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ReferenceCollector::endVisit(IdentifierPath const& _identifierPath)
|
||||||
|
{
|
||||||
|
tryAddReference(_identifierPath.annotation().referencedDeclaration, _identifierPath.location());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReferenceCollector::endVisit(MemberAccess const& _memberAccess)
|
||||||
|
{
|
||||||
|
if (_memberAccess.annotation().referencedDeclaration == &m_declaration)
|
||||||
|
m_resultingReferences.emplace_back(_memberAccess.location(), m_kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReferenceCollector::visit(Assignment const& _node)
|
||||||
|
{
|
||||||
|
auto const restoreKind = ScopeGuard{[this, savedKind=m_kind]() { m_kind = savedKind; }};
|
||||||
|
|
||||||
|
m_kind = DocumentHighlightKind::Write;
|
||||||
|
_node.leftHandSide().accept(*this);
|
||||||
|
|
||||||
|
m_kind = DocumentHighlightKind::Read;
|
||||||
|
_node.rightHandSide().accept(*this);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReferenceCollector::visit(VariableDeclaration const& _node)
|
||||||
|
{
|
||||||
|
if (&_node == &m_declaration)
|
||||||
|
m_resultingReferences.emplace_back(_node.nameLocation(), DocumentHighlightKind::Write);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReferenceCollector::visitNode(ASTNode const& _node)
|
||||||
|
{
|
||||||
|
if (&_node == &m_declaration)
|
||||||
|
{
|
||||||
|
if (auto const* declaration = dynamic_cast<Declaration const*>(&_node))
|
||||||
|
m_resultingReferences.emplace_back(declaration->nameLocation(), m_kind);
|
||||||
|
else
|
||||||
|
m_resultingReferences.emplace_back(_node.location(), DocumentHighlightKind::Read);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
69
libsolidity/lsp/ReferenceCollector.h
Normal file
69
libsolidity/lsp/ReferenceCollector.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libsolidity/ast/ASTForward.h>
|
||||||
|
#include <libsolidity/ast/ASTVisitor.h>
|
||||||
|
|
||||||
|
namespace solidity::lsp
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class DocumentHighlightKind
|
||||||
|
{
|
||||||
|
Unspecified = 0, //!< could be for example a highlight found in a comment
|
||||||
|
Text = 1, //!< a textual occurrence
|
||||||
|
Read = 2, //!< read access to a variable
|
||||||
|
Write = 3, //!< write access to a variable
|
||||||
|
};
|
||||||
|
|
||||||
|
// Represents a symbol / AST node that is to be highlighted, with some context associated.
|
||||||
|
using Reference = std::tuple<langutil::SourceLocation, DocumentHighlightKind>;
|
||||||
|
|
||||||
|
class ReferenceCollector: public frontend::ASTConstVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReferenceCollector(frontend::Declaration const& _declaration, std::string const& _sourceIdentifierName);
|
||||||
|
|
||||||
|
static std::vector<Reference> collect(
|
||||||
|
frontend::Declaration const* _declaration,
|
||||||
|
frontend::ASTNode const& _ast,
|
||||||
|
std::string const& _sourceIdentifierName
|
||||||
|
);
|
||||||
|
|
||||||
|
static std::vector<Reference> collect(frontend::ASTNode const* _sourceNode, frontend::SourceUnit const& _sourceUnit);
|
||||||
|
|
||||||
|
bool visit(frontend::ImportDirective const& _import) override;
|
||||||
|
void endVisit(frontend::ImportDirective const& _import) override;
|
||||||
|
void endVisit(frontend::Identifier const& _identifier) override;
|
||||||
|
void endVisit(frontend::IdentifierPath const& _identifierPath) override;
|
||||||
|
void endVisit(frontend::MemberAccess const& _memberAccess) override;
|
||||||
|
bool visit(frontend::Assignment const& _node) override;
|
||||||
|
bool visit(frontend::VariableDeclaration const& _node) override;
|
||||||
|
bool visitNode(frontend::ASTNode const& _node) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool tryAddReference(frontend::Declaration const* _declaration, solidity::langutil::SourceLocation const& _location);
|
||||||
|
|
||||||
|
private:
|
||||||
|
frontend::Declaration const& m_declaration;
|
||||||
|
std::string const& m_sourceIdentifierName;
|
||||||
|
std::vector<Reference> m_resultingReferences;
|
||||||
|
DocumentHighlightKind m_kind = DocumentHighlightKind::Read;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace
|
46
libsolidity/lsp/References.cpp
Normal file
46
libsolidity/lsp/References.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
#include <libsolidity/lsp/References.h>
|
||||||
|
#include <libsolidity/lsp/ReferenceCollector.h>
|
||||||
|
#include <libsolidity/lsp/LanguageServer.h>
|
||||||
|
#include <libsolidity/lsp/Utils.h>
|
||||||
|
|
||||||
|
#include <libsolutil/CommonData.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity::langutil;
|
||||||
|
using namespace solidity::frontend;
|
||||||
|
|
||||||
|
namespace solidity::lsp
|
||||||
|
{
|
||||||
|
|
||||||
|
void References::operator()(MessageID _id, Json::Value const& _args)
|
||||||
|
{
|
||||||
|
auto const [sourceUnitName, lineColumn] = extractSourceUnitNameAndLineColumn(_args);
|
||||||
|
|
||||||
|
ASTNode const* sourceNode = m_server.astNodeAtSourceLocation(sourceUnitName, lineColumn);
|
||||||
|
SourceUnit const& sourceUnit = m_server.ast(sourceUnitName);
|
||||||
|
|
||||||
|
Json::Value jsonReply = Json::arrayValue;
|
||||||
|
for (auto const& reference: ReferenceCollector::collect(sourceNode, sourceUnit))
|
||||||
|
jsonReply.append(toJson(get<SourceLocation>(reference)));
|
||||||
|
|
||||||
|
client().reply(_id, jsonReply);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
libsolidity/lsp/References.h
Normal file
31
libsolidity/lsp/References.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
#include <libsolidity/lsp/HandlerBase.h>
|
||||||
|
|
||||||
|
namespace solidity::lsp
|
||||||
|
{
|
||||||
|
|
||||||
|
class References: public HandlerBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit References(LanguageServer& _server): HandlerBase(_server) {}
|
||||||
|
|
||||||
|
void operator()(MessageID _id, Json::Value const& _args);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
52
libsolidity/lsp/SemanticHighlight.cpp
Normal file
52
libsolidity/lsp/SemanticHighlight.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
#include <libsolidity/lsp/SemanticHighlight.h>
|
||||||
|
#include <libsolidity/lsp/Utils.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity;
|
||||||
|
using namespace solidity::lsp;
|
||||||
|
using namespace solidity::frontend;
|
||||||
|
|
||||||
|
void SemanticHighlight::operator()(MessageID _id, Json::Value const& _args)
|
||||||
|
{
|
||||||
|
auto const [sourceUnitName, lineColumn] = extractSourceUnitNameAndLineColumn(_args);
|
||||||
|
ASTNode const* sourceNode = m_server.astNodeAtSourceLocation(sourceUnitName, lineColumn);
|
||||||
|
|
||||||
|
Json::Value jsonReply = Json::arrayValue;
|
||||||
|
for (auto const& [location, kind]: semanticHighlight(sourceNode, sourceUnitName))
|
||||||
|
{
|
||||||
|
Json::Value item = Json::objectValue;
|
||||||
|
item["range"] = toRange(location);
|
||||||
|
if (kind != DocumentHighlightKind::Unspecified)
|
||||||
|
item["kind"] = static_cast<int>(kind);
|
||||||
|
jsonReply.append(item);
|
||||||
|
}
|
||||||
|
client().reply(_id, jsonReply);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<Reference> SemanticHighlight::semanticHighlight(ASTNode const* _sourceNode, string const& _sourceUnitName)
|
||||||
|
{
|
||||||
|
if (!_sourceNode)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
SourceUnit const& sourceUnit = m_server.ast(_sourceUnitName);
|
||||||
|
|
||||||
|
return ReferenceCollector::collect(_sourceNode, sourceUnit);
|
||||||
|
}
|
||||||
|
|
37
libsolidity/lsp/SemanticHighlight.h
Normal file
37
libsolidity/lsp/SemanticHighlight.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
#include <libsolidity/lsp/HandlerBase.h>
|
||||||
|
#include <libsolidity/lsp/ReferenceCollector.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace solidity::lsp
|
||||||
|
{
|
||||||
|
|
||||||
|
class SemanticHighlight: public HandlerBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SemanticHighlight(LanguageServer& _server): HandlerBase(_server) {}
|
||||||
|
|
||||||
|
void operator()(MessageID _id, Json::Value const& _args);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Reference> semanticHighlight(frontend::ASTNode const* _sourceNode, std::string const& _sourceUnitName);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
70
test/libsolidity/lsp/references/enum.sol
Normal file
70
test/libsolidity/lsp/references/enum.sol
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity >=0.8.0;
|
||||||
|
|
||||||
|
enum Color {
|
||||||
|
// ^ @EnumDef
|
||||||
|
// ^^^^^ @ColorType0
|
||||||
|
Red,
|
||||||
|
// ^ @RedDef
|
||||||
|
// ^^^ @Red1
|
||||||
|
Green
|
||||||
|
}
|
||||||
|
|
||||||
|
contract MyContract
|
||||||
|
{
|
||||||
|
Color lastColor = Color.Red;
|
||||||
|
// ^ @lastCursorDef
|
||||||
|
// ^^^^^^^^^ @lastCursor1
|
||||||
|
// ^^^^^^^^^ @Red2
|
||||||
|
// ^^^^^ @ColorType1
|
||||||
|
// ^^^^^ @ColorType2
|
||||||
|
|
||||||
|
function sum(Color a) public view returns (Color)
|
||||||
|
// ^^^^^ @ColorType3
|
||||||
|
// ^^^^^ @ColorType4
|
||||||
|
{
|
||||||
|
Color result = Color(a);
|
||||||
|
// ^^^^^ @ColorType5
|
||||||
|
// ^^^^^ @ColorType6
|
||||||
|
if (a != lastColor)
|
||||||
|
// ^^^^^^^^^ @lastCursor2
|
||||||
|
result = Color.Green;
|
||||||
|
// ^^^^^ @ColorType7
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() public pure returns (uint)
|
||||||
|
{
|
||||||
|
uint result = 42;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @EnumDef
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// { "kind": 2, "range": @ColorType0 },
|
||||||
|
// { "kind": 2, "range": @ColorType1 },
|
||||||
|
// { "kind": 2, "range": @ColorType2 },
|
||||||
|
// { "kind": 2, "range": @ColorType3 },
|
||||||
|
// { "kind": 2, "range": @ColorType4 },
|
||||||
|
// { "kind": 2, "range": @ColorType5 },
|
||||||
|
// { "kind": 2, "range": @ColorType6 },
|
||||||
|
// { "kind": 2, "range": @ColorType7 }
|
||||||
|
// ]
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @RedDef
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// { "kind": 2, "range": @Red1 },
|
||||||
|
// { "kind": 2, "range": @Red2 }
|
||||||
|
// ]
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @lastCursorDef
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// { "kind": 3, "range": @lastCursor1 },
|
||||||
|
// { "kind": 2, "range": @lastCursor2 }
|
||||||
|
// ]
|
46
test/libsolidity/lsp/references/import_aliases.sol
Normal file
46
test/libsolidity/lsp/references/import_aliases.sol
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity >=0.8.0;
|
||||||
|
|
||||||
|
import "../goto/lib.sol" as Imported;
|
||||||
|
// ^ @ImportedDef
|
||||||
|
|
||||||
|
contract C
|
||||||
|
{
|
||||||
|
function one(uint lhs, uint rhs) public pure returns (uint result)
|
||||||
|
{
|
||||||
|
result = Imported.Lib.add(lhs, rhs + 123);
|
||||||
|
// ^ @ImportedUse
|
||||||
|
// ^^^^^^^^ @Imported1
|
||||||
|
// ^^^^^^^^^^^^ @ImportedLib1
|
||||||
|
}
|
||||||
|
function two(uint lhs, uint rhs) public pure returns (uint result)
|
||||||
|
{
|
||||||
|
result = one(Imported.Lib.add(lhs, rhs), rhs);
|
||||||
|
// ^ @LibRef
|
||||||
|
// ^^^^^^^^ @Imported2
|
||||||
|
// ^^^^^^^^^^^^ @ImportedLib2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// lib: @diagnostics 2072
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @ImportedDef
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// { "kind": 2, "range": @Imported1 },
|
||||||
|
// { "kind": 2, "range": @Imported2 }
|
||||||
|
// ]
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @ImportedUse
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// { "kind": 2, "range": @Imported1 },
|
||||||
|
// { "kind": 2, "range": @Imported2 }
|
||||||
|
// ]
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @LibRef
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// { "kind": 2, "range": @ImportedLib1 },
|
||||||
|
// { "kind": 2, "range": @ImportedLib2 }
|
||||||
|
// ]
|
83
test/libsolidity/lsp/references/read_write_access_kinds.sol
Normal file
83
test/libsolidity/lsp/references/read_write_access_kinds.sol
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity >=0.8.0;
|
||||||
|
|
||||||
|
import {RGBColor as ThatColor} from "../goto/lib.sol";
|
||||||
|
|
||||||
|
contract C
|
||||||
|
{
|
||||||
|
function other() public pure returns (ThatColor memory output)
|
||||||
|
// ^^^^^^ @OutputDef
|
||||||
|
{
|
||||||
|
output.red = 50;
|
||||||
|
// ^^^^^^ @OutputWrite1
|
||||||
|
// ^ @OutputWrite
|
||||||
|
output.green = output.red;
|
||||||
|
// ^^^^^^^^^^^^ @OutputGreenWrite1
|
||||||
|
// ^^^^^^ @OutputWrite2
|
||||||
|
// ^^^^^^ @OutputRead1
|
||||||
|
// ^ @GreenWrite
|
||||||
|
output.blue = output.green;
|
||||||
|
// ^^^^^^^^^^^^ @OutputGreenRead1
|
||||||
|
// ^^^^^^ @OutputWrite3
|
||||||
|
// ^^^^^^ @OutputRead2
|
||||||
|
// ^ @GreenUse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// lib: @diagnostics 2072
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @OutputWrite
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// {
|
||||||
|
// "kind": 3,
|
||||||
|
// "range": @OutputDef
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 3,
|
||||||
|
// "range": @OutputWrite1
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 3,
|
||||||
|
// "range": @OutputWrite2
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": @OutputRead1
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 3,
|
||||||
|
// "range": @OutputWrite3
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": @OutputRead2
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @GreenWrite
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// {
|
||||||
|
// "kind": 3,
|
||||||
|
// "range": @OutputGreenWrite1
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": @OutputGreenRead1
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @GreenUse
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// {
|
||||||
|
// "kind": 3,
|
||||||
|
// "range": @OutputGreenWrite1
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": @OutputGreenRead1
|
||||||
|
// }
|
||||||
|
// ]
|
176
test/libsolidity/lsp/references/struct.sol
Normal file
176
test/libsolidity/lsp/references/struct.sol
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity >=0.8.0;
|
||||||
|
|
||||||
|
struct MyStruct
|
||||||
|
// ^ @MyStructDef
|
||||||
|
{
|
||||||
|
uint value;
|
||||||
|
}
|
||||||
|
|
||||||
|
contract MyContract
|
||||||
|
{
|
||||||
|
MyStruct thatStruct;
|
||||||
|
// ^ @thatStructDef
|
||||||
|
|
||||||
|
function f(MyStruct memory _someStruct) public view returns (uint result)
|
||||||
|
{
|
||||||
|
MyStruct memory local = _someStruct;
|
||||||
|
local.value = local.value + thatStruct.value;
|
||||||
|
// ^ @thatStructUse (TODO)
|
||||||
|
result = local.value;
|
||||||
|
// ^ @localUse
|
||||||
|
}
|
||||||
|
|
||||||
|
function g(uint lhs, uint rhs) public pure returns (uint result)
|
||||||
|
{
|
||||||
|
uint output = lhs + rhs;
|
||||||
|
result = output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @MyStructDef
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 15,
|
||||||
|
// "line": 3
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 7,
|
||||||
|
// "line": 3
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 12,
|
||||||
|
// "line": 11
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 4,
|
||||||
|
// "line": 11
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 23,
|
||||||
|
// "line": 14
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 15,
|
||||||
|
// "line": 14
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 16,
|
||||||
|
// "line": 16
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 8,
|
||||||
|
// "line": 16
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @thatStructDef
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// {
|
||||||
|
// "kind": 3,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 23,
|
||||||
|
// "line": 11
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 13,
|
||||||
|
// "line": 11
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 46,
|
||||||
|
// "line": 17
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 36,
|
||||||
|
// "line": 17
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @localUse
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// {
|
||||||
|
// "kind": 3,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 29,
|
||||||
|
// "line": 16
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 24,
|
||||||
|
// "line": 16
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 3,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 13,
|
||||||
|
// "line": 17
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 8,
|
||||||
|
// "line": 17
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 27,
|
||||||
|
// "line": 17
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 22,
|
||||||
|
// "line": 17
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 22,
|
||||||
|
// "line": 19
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 17,
|
||||||
|
// "line": 19
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
88
test/libsolidity/lsp/references/symbol_aliases.sol
Normal file
88
test/libsolidity/lsp/references/symbol_aliases.sol
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
|
pragma solidity >=0.8.0;
|
||||||
|
|
||||||
|
import {
|
||||||
|
Lib as TheLib,
|
||||||
|
RGBColor as ThatColor
|
||||||
|
} from "../goto/lib.sol";
|
||||||
|
|
||||||
|
contract C
|
||||||
|
{
|
||||||
|
function one(uint lhs, uint rhs) public pure returns (uint result)
|
||||||
|
{
|
||||||
|
result = TheLib.add(lhs, rhs + 123);
|
||||||
|
// ^ @TheLibUse
|
||||||
|
}
|
||||||
|
|
||||||
|
function other() public pure returns (ThatColor memory output)
|
||||||
|
// ^ @ThatColorRet
|
||||||
|
{
|
||||||
|
output.red = 50;
|
||||||
|
output.green = output.red;
|
||||||
|
output.blue = output.green;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// lib: @diagnostics 2072
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @TheLibUse
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 17,
|
||||||
|
// "line": 4
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 11,
|
||||||
|
// "line": 4
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 23,
|
||||||
|
// "line": 12
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 17,
|
||||||
|
// "line": 12
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// -> textDocument/documentHighlight {
|
||||||
|
// "position": @ThatColorRet
|
||||||
|
// }
|
||||||
|
// <- [
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 25,
|
||||||
|
// "line": 5
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 16,
|
||||||
|
// "line": 5
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "kind": 2,
|
||||||
|
// "range": {
|
||||||
|
// "end": {
|
||||||
|
// "character": 51,
|
||||||
|
// "line": 16
|
||||||
|
// },
|
||||||
|
// "start": {
|
||||||
|
// "character": 42,
|
||||||
|
// "line": 16
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
Loading…
Reference in New Issue
Block a user