diff options
| author | BazookaMusic <sotirisdragonas@gmail.com> | 2025-06-01 00:44:33 +0200 |
|---|---|---|
| committer | BazookaMusic <sotirisdragonas@gmail.com> | 2025-06-01 00:44:33 +0200 |
| commit | e3d26cdbb6b02aa2524044d7e2db202a940ce891 (patch) | |
| tree | 767ee4ef0c03f4e15952397ad4ec13012a3787a9 /src | |
| parent | 01a1908a46079331001321db67b09689e0f2b050 (diff) | |
| download | rust-e3d26cdbb6b02aa2524044d7e2db202a940ce891.tar.gz rust-e3d26cdbb6b02aa2524044d7e2db202a940ce891.zip | |
Allow assist edit for converting structs to appear also on struct keyword and on visibility
Diffstat (limited to 'src')
3 files changed, 192 insertions, 6 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs index 5d75e445861..fa9fab7d78b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs @@ -7,7 +7,7 @@ use syntax::{ match_ast, ted, }; -use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder}; +use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder, utils::find_struct_definition_from_cursor}; // Assist: convert_named_struct_to_tuple_struct // @@ -56,8 +56,7 @@ pub(crate) fn convert_named_struct_to_tuple_struct( // XXX: We don't currently provide this assist for struct definitions inside macros, but if we // are to lift this limitation, don't forget to make `edit_struct_def()` consider macro files // too. - let name = ctx.find_node_at_offset::<ast::Name>()?; - let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?; + let strukt = find_struct_definition_from_cursor(ctx)?; let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?; let record_fields = match field_list { ast::FieldList::RecordFieldList(it) => it, @@ -294,6 +293,89 @@ impl A { } #[test] + fn convert_simple_struct_cursor_on_struct_keyword() { + check_assist( + convert_named_struct_to_tuple_struct, + r#" +struct Inner; +struct$0 A { inner: Inner } + +impl A { + fn new(inner: Inner) -> A { + A { inner } + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.inner + } +}"#, + r#" +struct Inner; +struct A(Inner); + +impl A { + fn new(inner: Inner) -> A { + A(inner) + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.0 + } +}"#, + ); + } + + #[test] + fn convert_simple_struct_cursor_on_visibility_keyword() { + check_assist( + convert_named_struct_to_tuple_struct, + r#" +struct Inner; +pub$0 struct A { inner: Inner } + +impl A { + fn new(inner: Inner) -> A { + A { inner } + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.inner + } +}"#, + r#" +struct Inner; +struct A(Inner); + +impl A { + fn new(inner: Inner) -> A { + A(inner) + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.0 + } +}"#, + ); + } + + + #[test] fn convert_struct_referenced_via_self_kw() { check_assist( convert_named_struct_to_tuple_struct, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 0c0b93bcfbc..5c2a3cdc305 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -6,7 +6,7 @@ use syntax::{ match_ast, ted, }; -use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder}; +use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder, utils::find_struct_definition_from_cursor}; // Assist: convert_tuple_struct_to_named_struct // @@ -51,8 +51,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { - let name = ctx.find_node_at_offset::<ast::Name>()?; - let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?; + let strukt = find_struct_definition_from_cursor(ctx)?; let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?; let tuple_fields = match field_list { ast::FieldList::TupleFieldList(it) => it, @@ -317,6 +316,88 @@ impl A { } #[test] + fn convert_simple_struct_cursor_on_struct_keyword() { + check_assist( + convert_tuple_struct_to_named_struct, + r#" +struct Inner; +struct$0 A(Inner); + +impl A { + fn new(inner: Inner) -> A { + A(inner) + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.0 + } +}"#, + r#" +struct Inner; +struct A { field1: Inner } + +impl A { + fn new(inner: Inner) -> A { + A { field1: inner } + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.field1 + } +}"#, + ); + } + + #[test] + fn convert_simple_struct_cursor_on_visibility_keyword() { + check_assist( + convert_tuple_struct_to_named_struct, + r#" +struct Inner; +pub$0 struct A(Inner); + +impl A { + fn new(inner: Inner) -> A { + A(inner) + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.0 + } +}"#, + r#" +struct Inner; +pub struct A { field1: Inner } + +impl A { + fn new(inner: Inner) -> A { + A { field1: inner } + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.field1 + } +}"#, + ); + } + + #[test] fn convert_struct_referenced_via_self_kw() { check_assist( convert_tuple_struct_to_named_struct, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index ef6914fda1d..1c0e022d01e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -1,5 +1,7 @@ //! Assorted functions shared by several assists. +use either::Either; + pub(crate) use gen_trait_fn_body::gen_trait_fn_body; use hir::{ DisplayTarget, HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution, @@ -1146,3 +1148,24 @@ pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bo }); is_const } + +/// Gets the struct definition from a context +pub(crate) fn find_struct_definition_from_cursor(ctx: &AssistContext<'_>) +-> Option<Either<ast::Struct, ast::Variant>> +{ + ctx.find_node_at_offset::<ast::Name>().and_then(|name| name.syntax().parent()) + .or(find_struct_keyword(ctx).and_then(|kw| kw.parent())) + .or(ctx.find_node_at_offset::<ast::Visibility>().and_then(|visibility| visibility.syntax().parent())) + .and_then(<Either<ast::Struct, ast::Variant>>::cast) +} + +fn find_struct_keyword(ctx: &AssistContext<'_>) -> Option<SyntaxToken> { + // Attempt to find the token at the current cursor offset + ctx + .token_at_offset() + .find(|leaf| match leaf.kind() { + STRUCT_KW => true, + _ => false, + }) +} + |
