LSP: Implements find all references and semantic highlighting.

This commit is contained in:
Christian Parpart 2022-03-14 17:10:59 +01:00
parent 238ac4fd92
commit dd5d861dec
15 changed files with 904 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View 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;
}
}

View 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

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

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

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

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

View 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 }
// ]

View 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 }
// ]

View 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
// }
// ]

View 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
// }
// }
// }
// ]

View 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
// }
// }
// }
// ]