From c64ca9c9588a25d48cd6a3d74dcd662e49daefd4 Mon Sep 17 00:00:00 2001 From: Gavin Morrow Date: Mon, 22 Jun 2026 14:41:15 -0400 Subject: [PATCH] Allow triggering rename or references in as clause --- compiler-core/src/ast.rs | 6 ++++-- compiler-core/src/build.rs | 19 +++++++++++++++++ language-server/src/engine.rs | 25 +++++++++++++++++------ language-server/src/reference.rs | 35 ++++++++++++++++++++++++++++---- 4 files changed, 73 insertions(+), 12 deletions(-) diff --git a/compiler-core/src/ast.rs b/compiler-core/src/ast.rs index 1cd6905c9..07aeee5f6 100644 --- a/compiler-core/src/ast.rs +++ b/compiler-core/src/ast.rs @@ -1005,7 +1005,7 @@ impl TypedImport { location, imported_name_location, name, - as_name: _, + as_name, }) = self .unqualified_values .iter() @@ -1018,6 +1018,7 @@ impl TypedImport { is_type: false, location, imported_name_location, + as_name: as_name.as_ref(), }, )); } @@ -1026,7 +1027,7 @@ impl TypedImport { location, imported_name_location, name, - as_name: _, + as_name, }) = self .unqualified_types .iter() @@ -1039,6 +1040,7 @@ impl TypedImport { is_type: true, location, imported_name_location, + as_name: as_name.as_ref(), }, )); } diff --git a/compiler-core/src/build.rs b/compiler-core/src/build.rs index 388c6f4fa..4e4a90a92 100644 --- a/compiler-core/src/build.rs +++ b/compiler-core/src/build.rs @@ -429,9 +429,28 @@ pub struct UnqualifiedImport<'a> { /// The location excluding the potential `as ...` clause, or the `type` keyword. /// For example, in `type Wibble as Wobble`, it covers `Wibble`. pub imported_name_location: &'a SrcSpan, + pub as_name: Option<&'a EcoString>, } impl<'a> UnqualifiedImport<'a> { + /// If the import is aliased, it is the start of the alias. Otherwise, it is + /// the start of the imported name. + /// + /// For example, in `type Wibble as Wobble`, the used name will start at + /// `Wobble`. In `type Wibble`, it will start at `Wibble`. + pub fn used_name_start(&self) -> u32 { + match self.as_name { + // For aliases, the location span will cover the whole of `type + // Wibble as Wobble`. + // So, the used name will start 6 chars (length of `Wobble`) before + // the span ends. + Some(as_name) => self.location.end - as_name.len() as u32, + // For non-aliased imports, use the start of the imported name + // location. It covers `Wibble` in `type Wibble as Wobble`. + None => self.imported_name_location.start, + } + } + pub fn name_kind(&self) -> Named { let is_upname = match self.name.chars().next() { Some(c) => c.is_uppercase(), diff --git a/language-server/src/engine.rs b/language-server/src/engine.rs index 762186977..a06a4322f 100644 --- a/language-server/src/engine.rs +++ b/language-server/src/engine.rs @@ -888,12 +888,14 @@ where Referenced::ModuleValue { module, location, + name_start, target_kind, .. } | Referenced::ModuleType { module, location, + name_start, target_kind, .. }, @@ -904,6 +906,21 @@ where RenameTarget::Unqualified | RenameTarget::Definition => true, }; if rename_allowed { + // The location field is sometimes larger than the + // location of the actual name. In most cases they are + // the same, but in import statements that are for types + // and/or are aliased, the location is larger than the + // name. + // + // For example, in `import m.{type Wibble as Wobble}`, + // location will cover `type Wibble as Wobble` but + // the name is just `Wobble`. In every case (including + // non-imports), the name is at the very end of the + // location span. + let location = SrcSpan { + start: name_start, + end: location.end, + }; success_response(location) } else { None @@ -1134,12 +1151,7 @@ where )) } }, - Some(Referenced::ModuleType { - module, - name, - location, - .. - }) if location.contains(byte_index) => match search_scope { + Some(Referenced::ModuleType { module, name, .. }) => match search_scope { FindReferencesSearchScope::AllModules => Some(find_module_references( module, name, @@ -1312,6 +1324,7 @@ where is_type, location, imported_name_location: _, + as_name: _, }) => this .compiler .get_module_interface(module_name.as_str()) diff --git a/language-server/src/reference.rs b/language-server/src/reference.rs index 42733d7f6..623360a42 100644 --- a/language-server/src/reference.rs +++ b/language-server/src/reference.rs @@ -41,6 +41,12 @@ pub enum Referenced { module: EcoString, name: EcoString, location: SrcSpan, + /// The starting position of the name. + /// + /// For example, when location covers an aliased import statement, e.g. + /// `wibble as wobble`, this will point to the start of `wobble`. + /// In all other cases, this is the same as `location.start`. + name_start: u32, name_kind: Named, target_kind: RenameTarget, }, @@ -48,6 +54,14 @@ pub enum Referenced { module: EcoString, name: EcoString, location: SrcSpan, + /// The starting position of the name. + /// + /// For example, when location covers an aliased import statement, e.g. + /// `type Wibble as Wobble`, this will point to the start of `Wobble`. + /// When location covers a non-aliased import statement, e.g. `type + /// Wibble`, this will point to the start of `Wibble`. + /// In all other cases, this is the same as `location.start`. + name_start: u32, target_kind: RenameTarget, }, TypeVariable { @@ -161,6 +175,7 @@ pub fn reference_for_ast_node( module: module.clone(), name: name.clone(), location: *location, + name_start: location.start, name_kind: Named::Function, target_kind: RenameTarget::Unqualified, }), @@ -181,6 +196,7 @@ pub fn reference_for_ast_node( module: module_name.clone(), name: label.clone(), location: SrcSpan::new(*field_start, location.end), + name_start: *field_start, name_kind: Named::Function, target_kind: RenameTarget::Qualified, }), @@ -197,6 +213,7 @@ pub fn reference_for_ast_node( module: current_module.clone(), name: name.clone(), location: *location, + name_start: location.start, name_kind: Named::Function, target_kind: RenameTarget::Definition, }), @@ -216,6 +233,7 @@ pub fn reference_for_ast_node( module: module.clone(), name: name.clone(), location: *location, + name_start: location.start, name_kind: Named::CustomTypeVariant, target_kind: RenameTarget::Unqualified, }), @@ -234,6 +252,7 @@ pub fn reference_for_ast_node( module: module_name.clone(), name: label.clone(), location: SrcSpan::new(*field_start, location.end), + name_start: *field_start, name_kind: Named::CustomTypeVariant, target_kind: RenameTarget::Qualified, }), @@ -245,6 +264,7 @@ pub fn reference_for_ast_node( module: current_module.clone(), name: name.clone(), location: *name_location, + name_start: name_location.start, name_kind: Named::CustomTypeVariant, target_kind: RenameTarget::Definition, }), @@ -257,6 +277,7 @@ pub fn reference_for_ast_node( module: constructor.module.clone(), name: constructor.name.clone(), location: *location, + name_start: location.start, name_kind: Named::CustomTypeVariant, target_kind: if module_select.is_some() { RenameTarget::Qualified @@ -287,6 +308,7 @@ pub fn reference_for_ast_node( module, name, location, + name_start: location.start, target_kind, }) } @@ -312,6 +334,7 @@ pub fn reference_for_ast_node( module: current_module.clone(), name: name.clone(), location: *name_location, + name_start: name_location.start, target_kind: RenameTarget::Definition, }), Located::ModuleName { @@ -375,6 +398,7 @@ pub fn reference_for_ast_node( module: module_name.clone(), name: label.clone(), location: SrcSpan::new(*field_start, location.end), + name_start: *field_start, name_kind: Named::Function, target_kind: RenameTarget::Qualified, }), @@ -384,22 +408,25 @@ pub fn reference_for_ast_node( name, module, is_type, - location: _, - imported_name_location, + location, + imported_name_location: _, + as_name: _, }, ) => { if is_type { Some(Referenced::ModuleType { module: module.clone(), name: name.clone(), - location: *imported_name_location, + location: *location, + name_start: import.used_name_start(), target_kind: RenameTarget::Unqualified, }) } else { Some(Referenced::ModuleValue { module: module.clone(), name: name.clone(), - location: *imported_name_location, + location: *location, + name_start: import.used_name_start(), name_kind: import.name_kind(), target_kind: RenameTarget::Unqualified, }) -- 2.51.2