diff --git a/sway-core/src/parse_tree/declaration.rs b/sway-core/src/parse_tree/declaration.rs index 9b34e4d00f3..5ec9a1d438d 100644 --- a/sway-core/src/parse_tree/declaration.rs +++ b/sway-core/src/parse_tree/declaration.rs @@ -12,10 +12,10 @@ mod type_parameter; mod variable; pub(crate) use abi::*; -pub(crate) use constant::*; +pub use constant::*; pub use function::*; pub(crate) use impl_trait::*; -pub(crate) use r#enum::*; +pub use r#enum::*; pub use r#struct::*; pub use r#trait::*; pub(crate) use reassignment::*; diff --git a/sway-core/src/parse_tree/declaration/abi.rs b/sway-core/src/parse_tree/declaration/abi.rs index 49878df8288..961d2511894 100644 --- a/sway-core/src/parse_tree/declaration/abi.rs +++ b/sway-core/src/parse_tree/declaration/abi.rs @@ -10,11 +10,11 @@ use pest::iterators::Pair; #[derive(Debug, Clone)] pub struct AbiDeclaration { /// The name of the abi trait (also known as a "contract trait") - pub(crate) name: Ident, + pub name: Ident, /// The methods a contract is required to implement in order opt in to this interface - pub(crate) interface_surface: Vec, + pub interface_surface: Vec, /// The methods provided to a contract "for free" upon opting in to this interface - pub(crate) methods: Vec, + pub methods: Vec, pub(crate) span: Span, } diff --git a/sway-core/src/parse_tree/declaration/enum.rs b/sway-core/src/parse_tree/declaration/enum.rs index 3bcd3e3bd0f..40886d01c5f 100644 --- a/sway-core/src/parse_tree/declaration/enum.rs +++ b/sway-core/src/parse_tree/declaration/enum.rs @@ -19,14 +19,14 @@ use pest::iterators::Pair; pub struct EnumDeclaration { pub name: Ident, pub(crate) type_parameters: Vec, - pub(crate) variants: Vec, + pub variants: Vec, pub(crate) span: Span, pub visibility: Visibility, } #[derive(Debug, Clone)] -pub(crate) struct EnumVariant { - pub(crate) name: Ident, +pub struct EnumVariant { + pub name: Ident, pub(crate) r#type: TypeInfo, pub(crate) tag: usize, pub(crate) span: Span, diff --git a/sway-core/src/parse_tree/declaration/function.rs b/sway-core/src/parse_tree/declaration/function.rs index 7a87508600a..1195dff582b 100644 --- a/sway-core/src/parse_tree/declaration/function.rs +++ b/sway-core/src/parse_tree/declaration/function.rs @@ -20,9 +20,9 @@ pub struct FunctionDeclaration { pub name: Ident, pub visibility: Visibility, pub body: CodeBlock, - pub(crate) parameters: Vec, + pub parameters: Vec, pub span: Span, - pub(crate) return_type: TypeInfo, + pub return_type: TypeInfo, pub(crate) type_parameters: Vec, pub(crate) return_type_span: Span, } @@ -193,8 +193,8 @@ impl FunctionDeclaration { } #[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct FunctionParameter { - pub(crate) name: Ident, +pub struct FunctionParameter { + pub name: Ident, pub(crate) type_id: TypeId, pub(crate) type_span: Span, } diff --git a/sway-core/src/parse_tree/declaration/impl_trait.rs b/sway-core/src/parse_tree/declaration/impl_trait.rs index adf7374b6d3..54f970bdeb4 100644 --- a/sway-core/src/parse_tree/declaration/impl_trait.rs +++ b/sway-core/src/parse_tree/declaration/impl_trait.rs @@ -9,7 +9,7 @@ use pest::iterators::Pair; #[derive(Debug, Clone)] pub struct ImplTrait { - pub(crate) trait_name: CallPath, + pub trait_name: CallPath, pub(crate) type_implementing_for: TypeInfo, pub(crate) type_implementing_for_span: Span, pub(crate) type_arguments: Vec, @@ -22,7 +22,7 @@ pub struct ImplTrait { /// like `impl MyType { fn foo { .. } }` #[derive(Debug, Clone)] pub struct ImplSelf { - pub(crate) type_implementing_for: TypeInfo, + pub type_implementing_for: TypeInfo, pub(crate) type_implementing_for_span: Span, pub(crate) type_parameters: Vec, pub functions: Vec, diff --git a/sway-core/src/parse_tree/declaration/struct.rs b/sway-core/src/parse_tree/declaration/struct.rs index 9b175809290..c15e3453492 100644 --- a/sway-core/src/parse_tree/declaration/struct.rs +++ b/sway-core/src/parse_tree/declaration/struct.rs @@ -14,15 +14,15 @@ use pest::iterators::Pair; #[derive(Debug, Clone)] pub struct StructDeclaration { pub name: Ident, - pub(crate) fields: Vec, + pub fields: Vec, pub(crate) type_parameters: Vec, pub visibility: Visibility, pub(crate) span: Span, } #[derive(Debug, Clone)] -pub(crate) struct StructField { - pub(crate) name: Ident, +pub struct StructField { + pub name: Ident, pub(crate) r#type: TypeInfo, pub(crate) span: Span, pub(crate) type_span: Span, diff --git a/sway-core/src/parse_tree/declaration/trait.rs b/sway-core/src/parse_tree/declaration/trait.rs index 8710346ce3f..3dfd98e5813 100644 --- a/sway-core/src/parse_tree/declaration/trait.rs +++ b/sway-core/src/parse_tree/declaration/trait.rs @@ -138,10 +138,10 @@ impl Supertrait { } #[derive(Debug, Clone, Eq, PartialEq)] -pub(crate) struct TraitFn { - pub(crate) name: Ident, - pub(crate) parameters: Vec, - pub(crate) return_type: TypeInfo, +pub struct TraitFn { + pub name: Ident, + pub parameters: Vec, + pub return_type: TypeInfo, pub(crate) return_type_span: Span, } diff --git a/sway-core/src/parse_tree/expression/asm.rs b/sway-core/src/parse_tree/expression/asm.rs index 9b1dda94a7e..e70ca1fddc0 100644 --- a/sway-core/src/parse_tree/expression/asm.rs +++ b/sway-core/src/parse_tree/expression/asm.rs @@ -100,7 +100,7 @@ impl AsmExpression { } #[derive(Debug, Clone)] -pub(crate) struct AsmOp { +pub struct AsmOp { pub(crate) op_name: Ident, pub(crate) op_args: Vec, pub(crate) span: Span, @@ -136,7 +136,7 @@ impl PartialEq for AsmOp { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct AsmRegister { +pub struct AsmRegister { pub(crate) name: String, } diff --git a/sway-core/src/parse_tree/expression/method_name.rs b/sway-core/src/parse_tree/expression/method_name.rs index ce90c468c0c..c2b771ccf6f 100644 --- a/sway-core/src/parse_tree/expression/method_name.rs +++ b/sway-core/src/parse_tree/expression/method_name.rs @@ -17,7 +17,7 @@ pub enum MethodName { impl MethodName { /// To be used for error messages and debug strings - pub(crate) fn easy_name(&self) -> Ident { + pub fn easy_name(&self) -> Ident { match self { MethodName::FromType { call_path, .. } => call_path.suffix.clone(), MethodName::FromModule { method_name, .. } => method_name.clone(), diff --git a/sway-core/src/parse_tree/expression/mod.rs b/sway-core/src/parse_tree/expression/mod.rs index c1cdb672345..75ec41edaf5 100644 --- a/sway-core/src/parse_tree/expression/mod.rs +++ b/sway-core/src/parse_tree/expression/mod.rs @@ -26,7 +26,7 @@ pub(crate) use match_branch::MatchBranch; pub(crate) use match_condition::CatchAll; pub(crate) use match_condition::MatchCondition; use matcher::matcher; -pub(crate) use method_name::MethodName; +pub use method_name::MethodName; pub(crate) use scrutinee::{Scrutinee, StructScrutineeField}; pub(crate) use unary_op::UnaryOp; @@ -236,8 +236,8 @@ impl LazyOp { #[derive(Debug, Clone)] pub struct StructExpressionField { - pub(crate) name: Ident, - pub(crate) value: Expression, + pub name: Ident, + pub value: Expression, pub(crate) span: Span, } diff --git a/sway-lsp/src/capabilities/completion.rs b/sway-lsp/src/capabilities/completion.rs index 7589173dce4..61b70d9855f 100644 --- a/sway-lsp/src/capabilities/completion.rs +++ b/sway-lsp/src/capabilities/completion.rs @@ -34,14 +34,22 @@ pub fn to_completion_items(tokens: &[Token]) -> Vec { fn get_kind(token_type: &TokenType) -> Option { match token_type { - TokenType::Enum => Some(CompletionItemKind::ENUM), - TokenType::FunctionDeclaration(_) | &TokenType::FunctionApplication => { - Some(CompletionItemKind::FUNCTION) + TokenType::VariableDeclaration(_) | TokenType::VariableExpression => { + Some(CompletionItemKind::VARIABLE) } + TokenType::FunctionDeclaration(_) + | &TokenType::FunctionApplication + | TokenType::TraitFunction => Some(CompletionItemKind::FUNCTION), + TokenType::TraitDeclaration(_) | TokenType::ImplTrait => { + Some(CompletionItemKind::INTERFACE) + } + TokenType::StructDeclaration(_) | TokenType::Struct => Some(CompletionItemKind::STRUCT), + TokenType::EnumDeclaration(_) | TokenType::EnumVariant | TokenType::EnumApplication => { + Some(CompletionItemKind::ENUM) + } + TokenType::ConstantDeclaration(_) => Some(CompletionItemKind::CONSTANT), TokenType::Library => Some(CompletionItemKind::MODULE), - TokenType::Struct(_) => Some(CompletionItemKind::STRUCT), - TokenType::Variable(_) => Some(CompletionItemKind::VARIABLE), - TokenType::Trait(_) => Some(CompletionItemKind::INTERFACE), + TokenType::Reassignment => Some(CompletionItemKind::OPERATOR), _ => None, } } diff --git a/sway-lsp/src/capabilities/document_symbol.rs b/sway-lsp/src/capabilities/document_symbol.rs index fe20b14885f..b92487c9634 100644 --- a/sway-lsp/src/capabilities/document_symbol.rs +++ b/sway-lsp/src/capabilities/document_symbol.rs @@ -34,12 +34,17 @@ fn create_symbol_info(token: &Token, url: Url) -> SymbolInformation { fn get_kind(token_type: &TokenType) -> SymbolKind { match token_type { - TokenType::Enum => SymbolKind::ENUM, - TokenType::FunctionDeclaration(_) | &TokenType::FunctionApplication => SymbolKind::FUNCTION, + TokenType::VariableDeclaration(_) | TokenType::VariableExpression => SymbolKind::VARIABLE, + TokenType::FunctionDeclaration(_) + | TokenType::FunctionApplication + | TokenType::TraitFunction => SymbolKind::FUNCTION, + TokenType::TraitDeclaration(_) | TokenType::ImplTrait => SymbolKind::INTERFACE, + TokenType::StructDeclaration(_) | TokenType::Struct => SymbolKind::STRUCT, + TokenType::EnumDeclaration(_) | TokenType::EnumApplication => SymbolKind::ENUM, + TokenType::ConstantDeclaration(_) => SymbolKind::CONSTANT, TokenType::Library => SymbolKind::MODULE, - TokenType::Struct(_) => SymbolKind::STRUCT, - TokenType::Variable(_) => SymbolKind::VARIABLE, - TokenType::Trait(_) => SymbolKind::INTERFACE, TokenType::Reassignment => SymbolKind::OPERATOR, + // currently we return `variable` type as default + _ => SymbolKind::VARIABLE, } } diff --git a/sway-lsp/src/capabilities/hover.rs b/sway-lsp/src/capabilities/hover.rs index 7e65fa77f90..10362add831 100644 --- a/sway-lsp/src/capabilities/hover.rs +++ b/sway-lsp/src/capabilities/hover.rs @@ -41,7 +41,7 @@ pub fn get_hover_data(session: Arc, params: HoverParams) -> Option Hover { let value = match &token.token_type { - TokenType::Variable(var_details) => { + TokenType::VariableDeclaration(var_details) => { let var_type = match &var_details.var_body { VarBody::FunctionCall(fn_name) => get_var_type_from_fn(fn_name, documents), VarBody::Type(var_type) => var_type.clone(), @@ -56,17 +56,21 @@ fn get_hover_format(token: &Token, documents: &Documents) -> Hover { ) } TokenType::FunctionDeclaration(func_details) => func_details.signature.clone(), - TokenType::Struct(struct_details) => format!( + TokenType::StructDeclaration(struct_details) => format!( "{}struct {}", extract_visibility(&struct_details.visibility), &token.name ), - TokenType::Trait(trait_details) => format!( + TokenType::TraitDeclaration(trait_details) => format!( "{}trait {}", extract_visibility(&trait_details.visibility), &token.name ), - TokenType::Enum => format!("enum {}", &token.name), + TokenType::EnumDeclaration(enum_details) => format!( + "{}enum {}", + extract_visibility(&enum_details.visibility), + &token.name + ), _ => token.name.clone(), }; diff --git a/sway-lsp/src/capabilities/semantic_tokens.rs b/sway-lsp/src/capabilities/semantic_tokens.rs index 86a4a012d94..3f5cf98fa3c 100644 --- a/sway-lsp/src/capabilities/semantic_tokens.rs +++ b/sway-lsp/src/capabilities/semantic_tokens.rs @@ -71,24 +71,33 @@ fn create_semantic_token(next_token: &Token, prev_token: Option<&Token>) -> Sema } } -// these values should reflect indexes in `token_types` -static FUNCTION: u32 = 1; -static LIBRARY: u32 = 3; -static VARIABLE: u32 = 9; -static ENUM: u32 = 10; -static STRUCT: u32 = 11; -static TRAIT: u32 = 12; +/// these values should reflect indexes in `token_types` +#[repr(u32)] +enum TokenTypeIndex { + Function = 1, + Namespace = 3, + Parameter = 5, + Variable = 9, + Enum = 10, + Struct = 11, + Interface = 12, +} fn get_type(token_type: &TokenType) -> u32 { match token_type { - TokenType::FunctionDeclaration(_) | &TokenType::FunctionApplication => FUNCTION, - TokenType::Library => LIBRARY, - TokenType::Variable(_) => VARIABLE, - TokenType::Enum => ENUM, - TokenType::Struct(_) => STRUCT, - TokenType::Trait(_) => TRAIT, + TokenType::FunctionDeclaration(_) + | TokenType::FunctionApplication + | TokenType::TraitFunction => TokenTypeIndex::Function as u32, + TokenType::Library => TokenTypeIndex::Namespace as u32, + TokenType::FunctionParameter => TokenTypeIndex::Parameter as u32, + TokenType::VariableDeclaration(_) | TokenType::VariableExpression => { + TokenTypeIndex::Variable as u32 + } + TokenType::EnumDeclaration(_) => TokenTypeIndex::Enum as u32, + TokenType::StructDeclaration(_) | TokenType::Struct => TokenTypeIndex::Struct as u32, + TokenType::TraitDeclaration(_) | TokenType::ImplTrait => TokenTypeIndex::Interface as u32, // currently we return `variable` type as default - _ => VARIABLE, + _ => TokenTypeIndex::Variable as u32, } } diff --git a/sway-lsp/src/core/token.rs b/sway-lsp/src/core/token.rs index c6cb27d2761..9e13ae5508e 100644 --- a/sway-lsp/src/core/token.rs +++ b/sway-lsp/src/core/token.rs @@ -1,9 +1,17 @@ use super::token_type::{get_trait_details, TokenType, VariableDetails}; use crate::{ - core::token_type::{get_function_details, get_struct_details}, + core::token_type::{ + get_const_details, get_enum_details, get_function_details, get_struct_details, + get_struct_field_details, + }, utils::common::extract_var_body, }; -use sway_core::{AstNode, AstNodeContent, Declaration, Expression, VariableDeclaration, WhileLoop}; +use sway_core::parse_tree::MethodName; +use sway_core::type_engine::TypeInfo; +use sway_core::{ + AstNode, AstNodeContent, Declaration, Expression, FunctionDeclaration, FunctionParameter, + VariableDeclaration, WhileLoop, +}; use sway_types::{ident::Ident, span::Span}; use tower_lsp::lsp_types::{Position, Range}; @@ -63,7 +71,7 @@ impl Token { Token::new( ident.span(), name.into(), - TokenType::Variable(VariableDetails { + TokenType::VariableDeclaration(VariableDetails { is_mutable: var_dec.is_mutable, var_body, }), @@ -79,9 +87,16 @@ impl Token { } pub fn is_initial_declaration(&self) -> bool { - !matches!( + matches!( self.token_type, - TokenType::Reassignment | TokenType::FunctionApplication + TokenType::VariableDeclaration(_) + | TokenType::FunctionDeclaration(_) + | TokenType::TraitDeclaration(_) + | TokenType::StructDeclaration(_) + | TokenType::EnumDeclaration(_) + | TokenType::AbiDeclaration + | TokenType::ConstantDeclaration(_) + | TokenType::StorageFieldDeclaration ) } } @@ -101,6 +116,57 @@ pub fn traverse_node(node: AstNode, tokens: &mut Vec) { }; } +fn handle_function_parameter(parameter: &FunctionParameter, tokens: &mut Vec) { + let ident = ¶meter.name; + let name = ident.as_str(); + + tokens.push(Token::new( + ident.span(), + name.into(), + TokenType::FunctionParameter, + )); +} + +fn handle_function_declation(function_declaration: FunctionDeclaration, tokens: &mut Vec) { + let ident = &function_declaration.name; + let token = Token::from_ident( + ident, + TokenType::FunctionDeclaration(get_function_details( + &function_declaration.span, + function_declaration.visibility, + )), + ); + tokens.push(token); + + for param in function_declaration.parameters { + handle_function_parameter(¶m, tokens); + } + + handle_custom_type(&function_declaration.return_type, tokens); + + for node in function_declaration.body.contents { + traverse_node(node, tokens); + } +} + +fn handle_custom_type(type_info: &TypeInfo, tokens: &mut Vec) { + if let TypeInfo::Custom { name, .. } = type_info { + //Iterate through the tokens and find the first token that has the same name as the custom type. + //Extract the token type of the found token, this should help determine if the custom type + //is a struct or an enum. + let found_token = tokens.iter().find(|token| token.name == name.as_str()); + if let Some(token_type) = found_token.map(|token| &token.token_type) { + if let TokenType::StructDeclaration(_) = token_type { + let token = Token::from_ident(name, TokenType::Struct); + tokens.push(token); + } else if let TokenType::EnumDeclaration(_) = token_type { + let token = Token::from_ident(name, TokenType::EnumApplication); + tokens.push(token); + } + } + } +} + fn handle_declaration(declaration: Declaration, tokens: &mut Vec) { match declaration { Declaration::VariableDeclaration(variable) => { @@ -108,74 +174,282 @@ fn handle_declaration(declaration: Declaration, tokens: &mut Vec) { handle_expression(variable.body, tokens); } Declaration::FunctionDeclaration(func_dec) => { - let ident = &func_dec.name; + handle_function_declation(func_dec, tokens); + } + Declaration::TraitDeclaration(trait_dec) => { + let ident = &trait_dec.name; let token = Token::from_ident( ident, - TokenType::FunctionDeclaration(get_function_details(&func_dec)), + TokenType::TraitDeclaration(get_trait_details(&trait_dec)), ); tokens.push(token); - for node in func_dec.body.contents { - traverse_node(node, tokens); + for func_dec in trait_dec.methods { + handle_function_declation(func_dec, tokens); + } + } + Declaration::StructDeclaration(struct_dec) => { + let ident = &struct_dec.name; + let token = Token::from_ident( + ident, + TokenType::StructDeclaration(get_struct_details(&struct_dec)), + ); + tokens.push(token); + + for field in struct_dec.fields { + let token = Token::from_ident( + &field.name, + TokenType::StructField(get_struct_field_details(ident)), + ); + tokens.push(token); + } + } + Declaration::EnumDeclaration(enum_dec) => { + let ident = &enum_dec.name; + let token = Token::from_ident( + ident, + TokenType::EnumDeclaration(get_enum_details(&enum_dec)), + ); + tokens.push(token); + + for variant in enum_dec.variants { + let ident = &variant.name; + let token = Token::from_ident(ident, TokenType::EnumVariant); + tokens.push(token); } } Declaration::Reassignment(reassignment) => { let token_type = TokenType::Reassignment; let token = Token::from_span(reassignment.lhs_span(), token_type); tokens.push(token); - handle_expression(reassignment.rhs, tokens); } + Declaration::ImplTrait(impl_trait) => { + let ident = impl_trait.trait_name.suffix; + let token = Token::from_ident(&ident, TokenType::ImplTrait); + tokens.push(token); + + for func_dec in impl_trait.functions { + handle_function_declation(func_dec, tokens); + } + } + Declaration::ImplSelf(impl_self) => { + handle_custom_type(&impl_self.type_implementing_for, tokens); + + for func_dec in impl_self.functions { + handle_function_declation(func_dec, tokens); + } + } + Declaration::AbiDeclaration(abi_dec) => { + let ident = &abi_dec.name; + let token = Token::from_ident(ident, TokenType::AbiDeclaration); - Declaration::TraitDeclaration(trait_dec) => { - let ident = &trait_dec.name; - let token = Token::from_ident(ident, TokenType::Trait(get_trait_details(&trait_dec))); tokens.push(token); - for func_dec in trait_dec.methods { - for node in func_dec.body.contents { - traverse_node(node, tokens); + for func_dec in abi_dec.methods { + handle_function_declation(func_dec, tokens); + } + + for train_fn in abi_dec.interface_surface { + let ident = &train_fn.name; + let token = Token::from_ident(ident, TokenType::TraitFunction); + tokens.push(token); + + for param in train_fn.parameters { + handle_function_parameter(¶m, tokens); } + + handle_custom_type(&train_fn.return_type, tokens); } } - Declaration::StructDeclaration(struct_dec) => { - let ident = &struct_dec.name; - let token = - Token::from_ident(ident, TokenType::Struct(get_struct_details(&struct_dec))); + Declaration::ConstantDeclaration(const_dec) => { + let ident = &const_dec.name; + let token = Token::from_ident( + ident, + TokenType::ConstantDeclaration(get_const_details(&const_dec)), + ); tokens.push(token); } - Declaration::EnumDeclaration(enum_dec) => { - let ident = enum_dec.name; - let token = Token::from_ident(&ident, TokenType::Enum); - tokens.push(token); + Declaration::StorageDeclaration(storage_dec) => { + for field in storage_dec.fields { + let ident = &field.name; + let token = Token::from_ident(ident, TokenType::StorageFieldDeclaration); + tokens.push(token); + } } - _ => {} }; } fn handle_expression(exp: Expression, tokens: &mut Vec) { match exp { + Expression::Literal { .. } => {} + Expression::FunctionApplication { + name, arguments, .. + } => { + let ident = name.suffix; + let token = Token::from_ident(&ident, TokenType::FunctionApplication); + tokens.push(token); + + for exp in arguments { + handle_expression(exp, tokens); + } + } + Expression::LazyOperator { lhs, rhs, .. } => { + handle_expression(*lhs, tokens); + handle_expression(*rhs, tokens); + } + Expression::VariableExpression { name, .. } => { + let token = Token::from_ident(&name, TokenType::VariableExpression); + tokens.push(token); + } + Expression::Tuple { fields, .. } => { + for exp in fields { + handle_expression(exp, tokens); + } + } + Expression::TupleIndex { prefix, .. } => { + handle_expression(*prefix, tokens); + } + Expression::Array { contents, .. } => { + for exp in contents { + handle_expression(exp, tokens); + } + } + Expression::StructExpression { + struct_name, + fields, + .. + } => { + let ident = struct_name.suffix; + let token = Token::from_ident(&ident, TokenType::Struct); + tokens.push(token); + + for field in fields { + let token = Token::from_ident( + &field.name, + TokenType::StructExpressionField(get_struct_field_details(&ident)), + ); + tokens.push(token); + handle_expression(field.value, tokens); + } + } Expression::CodeBlock { span: _, contents } => { let nodes = contents.contents; - for node in nodes { traverse_node(node, tokens); } } - Expression::FunctionApplication { - name, arguments, .. + Expression::IfExp { + condition, + then, + r#else, + .. } => { - let ident = name.suffix; - let token = Token::from_ident(&ident, TokenType::FunctionApplication); + handle_expression(*condition, tokens); + handle_expression(*then, tokens); + if let Some(r#else) = r#else { + handle_expression(*r#else, tokens); + } + } + Expression::MatchExp { if_exp, .. } => { + handle_expression(*if_exp, tokens); + } + Expression::AsmExpression { .. } => { + //TODO handle asm expressions + } + Expression::MethodApplication { + method_name, + arguments, + contract_call_params, + .. + } => { + let ident = method_name.easy_name(); + let token = Token::from_ident(&ident, TokenType::MethodApplication); tokens.push(token); for exp in arguments { handle_expression(exp, tokens); } + + //TODO handle methods from imported modules + if let MethodName::FromType { + type_name: Some(type_name), + .. + } = &method_name + { + handle_custom_type(type_name, tokens); + } + + for field in contract_call_params { + let token = Token::from_ident( + &field.name, + TokenType::StructExpressionField(get_struct_field_details(&ident)), + ); + tokens.push(token); + handle_expression(field.value, tokens); + } + } + Expression::SubfieldExpression { prefix, .. } => { + handle_expression(*prefix, tokens); + //TODO handle field_to_access? + } + Expression::DelineatedPath { + call_path, args, .. + } => { + for prefix in call_path.prefixes { + //TODO find the correct token type for this! + let token = Token::from_ident(&prefix, TokenType::DelineatedPath); + tokens.push(token); + } + + let token = Token::from_ident(&call_path.suffix, TokenType::DelineatedPath); + tokens.push(token); + + for exp in args { + handle_expression(exp, tokens); + } + } + Expression::AbiCast { + abi_name, address, .. + } => { + let ident = abi_name.suffix; + let token = Token::from_ident(&ident, TokenType::AbiCast); + tokens.push(token); + + handle_expression(*address, tokens); + } + Expression::ArrayIndex { prefix, index, .. } => { + handle_expression(*prefix, tokens); + handle_expression(*index, tokens); + } + Expression::DelayedMatchTypeResolution { .. } => { + //Should we handle this since it gets removed during type checking anyway? + } + Expression::StorageAccess { field_names, .. } => { + for field in field_names { + let token = Token::from_ident(&field, TokenType::StorageAccess); + tokens.push(token); + } + } + Expression::IfLet { + expr, then, r#else, .. + } => { + handle_expression(*expr, tokens); + + if let Some(r#else) = r#else { + handle_expression(*r#else, tokens); + } + + for node in then.contents { + traverse_node(node, tokens); + } + } + Expression::SizeOfVal { exp, .. } => { + handle_expression(*exp, tokens); + } + Expression::BuiltinGetTypeProperty { .. } => { + //TODO handle built in get type property? } - // TODO - // handle other expressions - _ => {} } } diff --git a/sway-lsp/src/core/token_type.rs b/sway-lsp/src/core/token_type.rs index 572db3ddaee..cfae33ce61c 100644 --- a/sway-lsp/src/core/token_type.rs +++ b/sway-lsp/src/core/token_type.rs @@ -1,22 +1,45 @@ use crate::utils::function::extract_fn_signature; -use sway_core::{FunctionDeclaration, StructDeclaration, TraitDeclaration, Visibility}; +use sway_core::{ + ConstantDeclaration, EnumDeclaration, StructDeclaration, TraitDeclaration, Visibility, +}; +use sway_types::{Ident, Span}; #[derive(Debug, Clone, PartialEq)] pub enum TokenType { Library, - Variable(VariableDetails), + + VariableDeclaration(VariableDetails), FunctionDeclaration(FunctionDetails), - FunctionApplication, + TraitDeclaration(TraitDetails), + StructDeclaration(StructDetails), + EnumDeclaration(EnumDetails), Reassignment, - Enum, - Trait(TraitDetails), - Struct(StructDetails), + ImplTrait, + AbiDeclaration, + ConstantDeclaration(ConstDetails), + TraitFunction, + EnumVariant, + StorageFieldDeclaration, + + FunctionApplication, + VariableExpression, + Struct, + MethodApplication, + DelineatedPath, + AbiCast, + StorageAccess, + EnumApplication, + StructField(StructFieldDetails), + StructExpressionField(StructFieldDetails), + FunctionParameter, + Unknown, } -pub fn get_function_details(func_dec: &FunctionDeclaration) -> FunctionDetails { +/// Expects a span from either a FunctionDeclaration or a TypedFunctionDeclaration +pub fn get_function_details(span: &Span, visibility: Visibility) -> FunctionDetails { FunctionDetails { - signature: extract_fn_signature(func_dec), - visibility: func_dec.visibility, + signature: extract_fn_signature(span), + visibility, } } @@ -26,11 +49,30 @@ pub fn get_struct_details(struct_dec: &StructDeclaration) -> StructDetails { } } +pub fn get_struct_field_details(ident: &Ident) -> StructFieldDetails { + StructFieldDetails { + parent_ident: ident.clone(), + } +} + pub fn get_trait_details(trait_dec: &TraitDeclaration) -> TraitDetails { TraitDetails { visibility: trait_dec.visibility, } } + +pub fn get_enum_details(enum_dec: &EnumDeclaration) -> EnumDetails { + EnumDetails { + visibility: enum_dec.visibility, + } +} + +pub fn get_const_details(const_dec: &ConstantDeclaration) -> ConstDetails { + ConstDetails { + visibility: const_dec.visibility, + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct FunctionDetails { pub signature: String, @@ -56,12 +98,28 @@ pub struct TraitDetails { pub visibility: Visibility, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EnumDetails { + pub visibility: Visibility, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ConstDetails { + pub visibility: Visibility, +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct VariableDetails { pub is_mutable: bool, pub var_body: VarBody, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StructFieldDetails { + // Used for looking up the parent struct that the field is a part of + pub parent_ident: Ident, +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum VarBody { FunctionCall(String), diff --git a/sway-lsp/src/utils/function.rs b/sway-lsp/src/utils/function.rs index a4eb53ec9dd..87d6f547023 100644 --- a/sway-lsp/src/utils/function.rs +++ b/sway-lsp/src/utils/function.rs @@ -1,6 +1,7 @@ -use sway_core::FunctionDeclaration; +use sway_types::Span; -pub(crate) fn extract_fn_signature(func_dec: &FunctionDeclaration) -> String { - let value = func_dec.span.as_str(); +/// Expects a span from either a FunctionDeclaration or a TypedFunctionDeclaration +pub(crate) fn extract_fn_signature(span: &Span) -> String { + let value = span.as_str(); value.split('{').take(1).map(|v| v.trim()).collect() }