diff --git a/sway-lsp/src/traverse/parsed_tree.rs b/sway-lsp/src/traverse/parsed_tree.rs index 9b591ddbc55..3c5adbd17be 100644 --- a/sway-lsp/src/traverse/parsed_tree.rs +++ b/sway-lsp/src/traverse/parsed_tree.rs @@ -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}, @@ -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 { .. } => (), diff --git a/sway-lsp/src/traverse/typed_tree.rs b/sway-lsp/src/traverse/typed_tree.rs index 15c1fa43a9b..ba7364a686c 100644 --- a/sway-lsp/src/traverse/typed_tree.rs +++ b/sway-lsp/src/traverse/typed_tree.rs @@ -710,13 +710,11 @@ 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 @@ -724,6 +722,13 @@ impl<'a> TypedTree<'a> { .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); @@ -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)); + } + } + } } + _ => {} }; } diff --git a/sway-lsp/tests/fixtures/tokens/variables/src/main.sw b/sway-lsp/tests/fixtures/tokens/variables/src/main.sw index 26e54f8db4b..bc4ff864d22 100644 --- a/sway-lsp/tests/fixtures/tokens/variables/src/main.sw +++ b/sway-lsp/tests/fixtures/tokens/variables/src/main.sw @@ -13,6 +13,8 @@ fn example_function(variable: Result, u32>) -> Result, u variable } +abi TestAbi {} + fn main() { // Variable usage: Variable Declarations let variable1 = 10; @@ -53,4 +55,9 @@ fn main() { // Complex type ascriptions let variable7: Result, u32> = variable2; + + // ContractCaller + use std::constants::ZERO_B256; + let variable8: ContractCaller = abi(TestAbi, ZERO_B256); + let variable9: ContractCaller<_> = abi(TestAbi, ZERO_B256); } diff --git a/sway-lsp/tests/lib.rs b/sway-lsp/tests/lib.rs index c06c4ec7454..032b57d400e 100644 --- a/sway-lsp/tests/lib.rs +++ b/sway-lsp/tests/lib.rs @@ -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(), @@ -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; }