Skip to content

Commit

Permalink
Collect tokens for ContractCaller and abi casts (FuelLabs#4083)
Browse files Browse the repository at this point in the history
## Description

Add go to definition support for the ABI argument to the
`ContractCaller`
special type and ABI argument to `abi` casts.

Simplified LSP parsed token creation for type arguments using the
previously introduced call path tree.

Fix FuelLabs#4063
Fix FuelLabs#4064


## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
  • Loading branch information
IGI-111 authored Feb 15, 2023
1 parent f7cbf83 commit 74bf48c
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 64 deletions.
38 changes: 16 additions & 22 deletions sway-lsp/src/traverse/parsed_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use sway_core::{
StructExpression, StructScrutineeField, SubfieldExpression, TraitFn, TreeType,
TupleIndexExpression, UseStatement, WhileLoopExpression,
},
Literal,
CallPathTree, Literal,
},
transform::{AttributeKind, AttributesMap},
type_system::{TypeArgument, TypeParameter},
Expand Down Expand Up @@ -823,35 +823,29 @@ impl<'a> ParsedTree<'a> {
self.collect_type_arg(type_arg, &token);
}
}
TypeInfo::Custom {
call_path,
type_arguments,
} => {
if let Some(type_args) = type_arguments {
for type_arg in type_args {
self.collect_type_arg(type_arg, &token);
}
}

_ => {
let symbol_kind = type_info_to_symbol_kind(self.type_engine, &type_info);
token.kind = symbol_kind;
token.type_def = Some(TypeDefinition::TypeId(type_argument.type_id));

for ident in &call_path.prefixes {
self.tokens.insert(to_ident_key(ident), token.clone());
if let Some(tree) = &type_argument.call_path_tree {
self.collect_call_path_tree(tree, &token);
}
self.tokens.insert(to_ident_key(&call_path.suffix), token);
}
_ => {
let symbol_kind = type_info_to_symbol_kind(self.type_engine, &type_info);
token.kind = symbol_kind;
token.type_def = Some(TypeDefinition::TypeId(type_argument.type_id));
self.tokens
.insert(to_ident_key(&Ident::new(type_argument.span.clone())), token);
}
}
}

fn collect_call_path_tree(&self, tree: &CallPathTree, token: &Token) {
for ident in &tree.call_path.prefixes {
self.tokens.insert(to_ident_key(ident), token.clone());
}
self.tokens
.insert(to_ident_key(&tree.call_path.suffix), token.clone());

for child in &tree.children {
self.collect_call_path_tree(child, token);
}
}

fn collect_scrutinee(&self, scrutinee: &Scrutinee) {
match scrutinee {
Scrutinee::CatchAll { .. } => (),
Expand Down
66 changes: 45 additions & 21 deletions sway-lsp/src/traverse/typed_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -710,20 +710,25 @@ impl<'a> TypedTree<'a> {
ty::TyExpressionVariant::AbiCast {
abi_name, address, ..
} => {
for ident in &abi_name.prefixes {
if let Some(mut token) =
self.tokens.try_get_mut(&to_ident_key(ident)).try_unwrap()
{
token.typed = Some(TypedAstToken::TypedExpression(expression.clone()));
}
}
self.collect_call_path_prefixes(
&abi_name.prefixes,
TypedAstToken::TypedExpression(expression.clone()),
namespace,
);

if let Some(mut token) = self
.tokens
.try_get_mut(&to_ident_key(&abi_name.suffix))
.try_unwrap()
{
token.typed = Some(TypedAstToken::TypedExpression(expression.clone()));
if let Some(abi_def_ident) = namespace
.submodule(&abi_name.prefixes)
.and_then(|module| module.symbols().get(&abi_name.suffix))
.and_then(|decl| decl.get_decl_ident())
{
token.type_def = Some(TypeDefinition::Ident(abi_def_ident));
}
}

self.handle_expression(address, namespace);
Expand Down Expand Up @@ -1063,23 +1068,42 @@ impl<'a> TypedTree<'a> {
self.collect_call_path_tree(child_tree, &type_arg, namespace);
}
}
TypeInfo::Custom { type_arguments, .. } => {
if let Some(type_args) = type_arguments {
for (child_tree, type_arg) in tree.children.iter().zip(type_args.iter()) {
self.collect_call_path_tree(child_tree, type_arg, namespace);
}
TypeInfo::Custom {
type_arguments: Some(type_args),
..
} => {
for (child_tree, type_arg) in tree.children.iter().zip(type_args.iter()) {
self.collect_call_path_tree(child_tree, type_arg, namespace);
}
}
_ => {
self.collect_type_id(
type_arg.type_id,
&TypedAstToken::TypedArgument(type_arg.clone()),
// use the whole span instead of just the name if we don't know
// how to walk it
type_arg.span(),
namespace,
);
TypeInfo::ContractCaller { .. } => {
// single generic argument to ContractCaller<_> has to be a single ABI
// definition call path which we can collect without recursion
if let Some(child_tree) = tree.children.first() {
let abi_call_path = &child_tree.call_path;

self.collect_call_path_prefixes(
&abi_call_path.prefixes,
TypedAstToken::TypedArgument(type_arg.clone()),
namespace,
);
if let Some(mut token) = self
.tokens
.try_get_mut(&to_ident_key(&abi_call_path.suffix))
.try_unwrap()
{
token.typed = Some(TypedAstToken::TypedArgument(type_arg.clone()));
if let Some(abi_def_ident) = namespace
.submodule(&abi_call_path.prefixes)
.and_then(|module| module.symbols().get(&abi_call_path.suffix))
.and_then(|decl| decl.get_decl_ident())
{
token.type_def = Some(TypeDefinition::Ident(abi_def_ident));
}
}
}
}
_ => {}
};
}

Expand Down
7 changes: 7 additions & 0 deletions sway-lsp/tests/fixtures/tokens/variables/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ fn example_function(variable: Result<Option<u32>, u32>) -> Result<Option<u32>, u
variable
}

abi TestAbi {}

fn main() {
// Variable usage: Variable Declarations
let variable1 = 10;
Expand Down Expand Up @@ -53,4 +55,9 @@ fn main() {

// Complex type ascriptions
let variable7: Result<Option<u32>, u32> = variable2;

// ContractCaller
use std::constants::ZERO_B256;
let variable8: ContractCaller<TestAbi> = abi(TestAbi, ZERO_B256);
let variable9: ContractCaller<_> = abi(TestAbi, ZERO_B256);
}
51 changes: 30 additions & 21 deletions sway-lsp/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,9 +905,9 @@ async fn go_to_definition_for_variables() {

let mut go_to = GotoDefinition {
req_uri: &uri,
req_line: 18,
req_line: 20,
req_char: 34,
def_line: 17,
def_line: 19,
def_start_char: 8,
def_end_char: 17,
def_path: uri.as_str(),
Expand All @@ -916,63 +916,72 @@ async fn go_to_definition_for_variables() {
let _ = lsp::definition_check(&mut service, &go_to, &mut i).await;

// Function arguments
go_to.def_line = 18;
definition_check_with_req_offset(&mut service, &mut go_to, 23, 35, &mut i).await;
go_to.def_line = 20;
definition_check_with_req_offset(&mut service, &mut go_to, 25, 35, &mut i).await;

// Struct fields
go_to.def_line = 17;
definition_check_with_req_offset(&mut service, &mut go_to, 26, 45, &mut i).await;
go_to.def_line = 19;
definition_check_with_req_offset(&mut service, &mut go_to, 28, 45, &mut i).await;

// Enum fields
go_to.def_line = 17;
definition_check_with_req_offset(&mut service, &mut go_to, 29, 39, &mut i).await;
go_to.def_line = 19;
definition_check_with_req_offset(&mut service, &mut go_to, 31, 39, &mut i).await;

// Tuple elements
go_to.def_line = 19;
definition_check_with_req_offset(&mut service, &mut go_to, 32, 20, &mut i).await;
go_to.def_line = 21;
definition_check_with_req_offset(&mut service, &mut go_to, 34, 20, &mut i).await;

// Array elements
go_to.def_line = 20;
definition_check_with_req_offset(&mut service, &mut go_to, 35, 20, &mut i).await;
go_to.def_line = 22;
definition_check_with_req_offset(&mut service, &mut go_to, 37, 20, &mut i).await;

// Scoped declarations
go_to.def_line = 39;
go_to.def_line = 41;
go_to.def_start_char = 12;
go_to.def_end_char = 21;
definition_check_with_req_offset(&mut service, &mut go_to, 40, 13, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 42, 13, &mut i).await;

// If let scopes
go_to.def_line = 45;
go_to.def_line = 47;
go_to.def_start_char = 38;
go_to.def_end_char = 39;
definition_check_with_req_offset(&mut service, &mut go_to, 45, 47, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 47, 47, &mut i).await;

// Shadowing
go_to.def_line = 45;
go_to.def_line = 47;
go_to.def_start_char = 8;
go_to.def_end_char = 17;
definition_check_with_req_offset(&mut service, &mut go_to, 48, 29, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 50, 29, &mut i).await;

// Variable type ascriptions
go_to.def_line = 6;
go_to.def_start_char = 5;
go_to.def_end_char = 16;
definition_check_with_req_offset(&mut service, &mut go_to, 51, 21, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 53, 21, &mut i).await;

// Complex type ascriptions
go_to.def_line = 60;
go_to.def_start_char = 9;
go_to.def_end_char = 15;
go_to.def_path = "sway-lib-std/src/result.sw";
definition_check_with_req_offset(&mut service, &mut go_to, 54, 22, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 56, 22, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 11, 31, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 11, 60, &mut i).await;
go_to.def_line = 80;
go_to.def_path = "sway-lib-std/src/option.sw";
definition_check_with_req_offset(&mut service, &mut go_to, 54, 28, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 56, 28, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 11, 39, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 11, 68, &mut i).await;

// ContractCaller
go_to.def_line = 15;
go_to.def_start_char = 4;
go_to.def_end_char = 11;
go_to.def_path = uri.as_str();
definition_check_with_req_offset(&mut service, &mut go_to, 60, 34, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 60, 50, &mut i).await;
definition_check_with_req_offset(&mut service, &mut go_to, 61, 50, &mut i).await;

shutdown_and_exit(&mut service).await;
}

Expand Down

0 comments on commit 74bf48c

Please sign in to comment.