From 33ef3d769e43056628d696677481eaf3a7270fe7 Mon Sep 17 00:00:00 2001 From: GearsDatapacks Date: Mon, 20 Jan 2025 17:19:34 +0000 Subject: [PATCH] Allow renaming of variables inside bit array segments --- compiler-core/src/ast.rs | 40 ++++++++++++++++- compiler-core/src/ast/visit.rs | 43 +++++++++++++++++++ compiler-core/src/language_server/engine.rs | 36 ++++++++++++++++ compiler-core/src/language_server/rename.rs | 22 ++++++++++ .../src/language_server/tests/rename.rs | 36 ++++++++++++++++ ...local_variable_from_bit_array_pattern.snap | 27 ++++++++++++ ...e_local_variable_in_bit_array_pattern.snap | 27 ++++++++++++ 7 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__rename__rename_local_variable_from_bit_array_pattern.snap create mode 100644 compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__rename__rename_local_variable_in_bit_array_pattern.snap diff --git a/compiler-core/src/ast.rs b/compiler-core/src/ast.rs index 16c4c7c502d..42fc05c0bec 100644 --- a/compiler-core/src/ast.rs +++ b/compiler-core/src/ast.rs @@ -1951,7 +1951,6 @@ impl TypedPattern { | Pattern::VarUsage { .. } | Pattern::Assign { .. } | Pattern::Discard { .. } - | Pattern::BitArray { .. } | Pattern::StringPrefix { .. } | Pattern::Invalid { .. } => Some(Located::Pattern(self)), @@ -1973,6 +1972,11 @@ impl TypedPattern { .or_else(|| tail.as_ref().and_then(|p| p.find_node(byte_index))), Pattern::Tuple { elems, .. } => elems.iter().find_map(|p| p.find_node(byte_index)), + + Pattern::BitArray { segments, .. } => segments + .iter() + .find_map(|segment| segment.find_node(byte_index)) + .or(Some(Located::Pattern(self))), } .or(Some(Located::Pattern(self))) } @@ -2049,6 +2053,16 @@ impl TypedExprBitArraySegment { } } +impl TypedPatternBitArraySegment { + pub fn find_node(&self, byte_index: u32) -> Option> { + self.value.find_node(byte_index).or_else(|| { + self.options + .iter() + .find_map(|option| option.find_node(byte_index)) + }) + } +} + pub type TypedConstantBitArraySegmentOption = BitArrayOption; #[derive(Debug, PartialEq, Eq, Clone)] @@ -2178,6 +2192,30 @@ impl BitArrayOption { } } +impl BitArrayOption { + pub fn find_node(&self, byte_index: u32) -> Option> { + match self { + BitArrayOption::Bytes { .. } + | BitArrayOption::Int { .. } + | BitArrayOption::Float { .. } + | BitArrayOption::Bits { .. } + | BitArrayOption::Utf8 { .. } + | BitArrayOption::Utf16 { .. } + | BitArrayOption::Utf32 { .. } + | BitArrayOption::Utf8Codepoint { .. } + | BitArrayOption::Utf16Codepoint { .. } + | BitArrayOption::Utf32Codepoint { .. } + | BitArrayOption::Signed { .. } + | BitArrayOption::Unsigned { .. } + | BitArrayOption::Big { .. } + | BitArrayOption::Little { .. } + | BitArrayOption::Native { .. } + | BitArrayOption::Unit { .. } => None, + BitArrayOption::Size { value, .. } => value.find_node(byte_index), + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum TodoKind { Keyword, diff --git a/compiler-core/src/ast/visit.rs b/compiler-core/src/ast/visit.rs index 42a026eaec9..da1d43be276 100644 --- a/compiler-core/src/ast/visit.rs +++ b/compiler-core/src/ast/visit.rs @@ -486,6 +486,10 @@ pub trait Visit<'ast> { visit_typed_pattern_bit_array(self, location, segments); } + fn visit_typed_pattern_bit_array_option(&mut self, option: &'ast BitArrayOption) { + visit_typed_pattern_bit_array_option(self, option); + } + fn visit_typed_pattern_string_prefix( &mut self, location: &'ast SrcSpan, @@ -1582,6 +1586,45 @@ pub fn visit_typed_pattern_bit_array<'a, V>( { for segment in segments { v.visit_typed_pattern(&segment.value); + for option in segment.options.iter() { + v.visit_typed_pattern_bit_array_option(option); + } + } +} + +pub fn visit_typed_pattern_bit_array_option<'a, V>( + v: &mut V, + option: &'a BitArrayOption, +) where + V: Visit<'a> + ?Sized, +{ + match option { + BitArrayOption::Bytes { location: _ } => { /* TODO */ } + BitArrayOption::Int { location: _ } => { /* TODO */ } + BitArrayOption::Float { location: _ } => { /* TODO */ } + BitArrayOption::Bits { location: _ } => { /* TODO */ } + BitArrayOption::Utf8 { location: _ } => { /* TODO */ } + BitArrayOption::Utf16 { location: _ } => { /* TODO */ } + BitArrayOption::Utf32 { location: _ } => { /* TODO */ } + BitArrayOption::Utf8Codepoint { location: _ } => { /* TODO */ } + BitArrayOption::Utf16Codepoint { location: _ } => { /* TODO */ } + BitArrayOption::Utf32Codepoint { location: _ } => { /* TODO */ } + BitArrayOption::Signed { location: _ } => { /* TODO */ } + BitArrayOption::Unsigned { location: _ } => { /* TODO */ } + BitArrayOption::Big { location: _ } => { /* TODO */ } + BitArrayOption::Little { location: _ } => { /* TODO */ } + BitArrayOption::Native { location: _ } => { /* TODO */ } + BitArrayOption::Size { + location: _, + value, + short_form: _, + } => { + v.visit_typed_pattern(value); + } + BitArrayOption::Unit { + location: _, + value: _, + } => { /* TODO */ } } } diff --git a/compiler-core/src/language_server/engine.rs b/compiler-core/src/language_server/engine.rs index 06ac2bb503b..9ac478d6a60 100644 --- a/compiler-core/src/language_server/engine.rs +++ b/compiler-core/src/language_server/engine.rs @@ -525,6 +525,17 @@ where | VariableOrigin::LabelShorthand(_) => success_response, VariableOrigin::Generated => None, }, + Located::Pattern(Pattern::VarUsage { constructor, .. }) => constructor + .as_ref() + .and_then(|constructor| match &constructor.variant { + ValueConstructorVariant::LocalVariable { origin, .. } => match origin { + VariableOrigin::Variable(_) + | VariableOrigin::AssignmentPattern + | VariableOrigin::LabelShorthand(_) => success_response, + VariableOrigin::Generated => None, + }, + _ => None, + }), Located::Pattern(Pattern::Assign { .. }) => success_response, Located::Arg(arg) => match &arg.names { ArgNames::Named { .. } | ArgNames::NamedLabelled { .. } => success_response, @@ -578,6 +589,31 @@ where ), VariableOrigin::Generated => None, }, + Located::Pattern(Pattern::VarUsage { constructor, .. }) => constructor + .as_ref() + .and_then(|constructor| match &constructor.variant { + ValueConstructorVariant::LocalVariable { location, origin } => match origin + { + VariableOrigin::Variable(_) | VariableOrigin::AssignmentPattern => { + rename_local_variable( + module, + &lines, + ¶ms, + *location, + VariableRenameKind::Variable, + ) + } + VariableOrigin::LabelShorthand(_) => rename_local_variable( + module, + &lines, + ¶ms, + *location, + VariableRenameKind::LabelShorthand, + ), + VariableOrigin::Generated => None, + }, + _ => None, + }), Located::Pattern(Pattern::Assign { location, .. }) => rename_local_variable( module, &lines, diff --git a/compiler-core/src/language_server/rename.rs b/compiler-core/src/language_server/rename.rs index 9419ea83c82..0d6edcd53be 100644 --- a/compiler-core/src/language_server/rename.rs +++ b/compiler-core/src/language_server/rename.rs @@ -117,4 +117,26 @@ impl<'ast> Visit<'ast> for RenameLocalVariable { self.references.push(*location) } } + + fn visit_typed_pattern_var_usage( + &mut self, + location: &'ast SrcSpan, + _name: &'ast EcoString, + constructor: &'ast Option, + _type_: &'ast std::sync::Arc, + ) { + let variant = match constructor { + Some(constructor) => &constructor.variant, + None => return, + }; + match variant { + ValueConstructorVariant::LocalVariable { + location: definition_location, + .. + } if *definition_location == self.definition_location => { + self.references.push(*location) + } + _ => {} + } + } } diff --git a/compiler-core/src/language_server/tests/rename.rs b/compiler-core/src/language_server/tests/rename.rs index 9b8bd8b4ba2..09412cd0ac4 100644 --- a/compiler-core/src/language_server/tests/rename.rs +++ b/compiler-core/src/language_server/tests/rename.rs @@ -282,6 +282,42 @@ pub fn main() { ); } +#[test] +fn rename_local_variable_in_bit_array_pattern() { + assert_rename!( + " +pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool { + let prefix_size = bit_size(prefix) + + case bits { + <> if pref == prefix -> True + _ -> False + } +} +", + "size_of_prefix", + find_position_of("prefix_size =").to_selection() + ); +} + +#[test] +fn rename_local_variable_from_bit_array_pattern() { + assert_rename!( + " +pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool { + let prefix_size = bit_size(prefix) + + case bits { + <> if pref == prefix -> True + _ -> False + } +} +", + "size_of_prefix", + find_position_of("prefix_size)").to_selection() + ); +} + #[test] fn no_rename_keyword() { assert_no_rename!( diff --git a/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__rename__rename_local_variable_from_bit_array_pattern.snap b/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__rename__rename_local_variable_from_bit_array_pattern.snap new file mode 100644 index 00000000000..17caf9b3efe --- /dev/null +++ b/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__rename__rename_local_variable_from_bit_array_pattern.snap @@ -0,0 +1,27 @@ +--- +source: compiler-core/src/language_server/tests/rename.rs +expression: "\npub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {\n let prefix_size = bit_size(prefix)\n\n case bits {\n <> if pref == prefix -> True\n _ -> False\n }\n}\n" +--- +----- BEFORE RENAME + +pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool { + let prefix_size = bit_size(prefix) + + case bits { + <> if pref == prefix -> True + ↑ + _ -> False + } +} + + +----- AFTER RENAME + +pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool { + let size_of_prefix = bit_size(prefix) + + case bits { + <> if pref == prefix -> True + _ -> False + } +} diff --git a/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__rename__rename_local_variable_in_bit_array_pattern.snap b/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__rename__rename_local_variable_in_bit_array_pattern.snap new file mode 100644 index 00000000000..fae10100348 --- /dev/null +++ b/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__rename__rename_local_variable_in_bit_array_pattern.snap @@ -0,0 +1,27 @@ +--- +source: compiler-core/src/language_server/tests/rename.rs +expression: "\npub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {\n let prefix_size = bit_size(prefix)\n\n case bits {\n <> if pref == prefix -> True\n _ -> False\n }\n}\n" +--- +----- BEFORE RENAME + +pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool { + let prefix_size = bit_size(prefix) + ↑ + + case bits { + <> if pref == prefix -> True + _ -> False + } +} + + +----- AFTER RENAME + +pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool { + let size_of_prefix = bit_size(prefix) + + case bits { + <> if pref == prefix -> True + _ -> False + } +}