Skip to content

Commit e3d26cd

Browse files
committed
Allow assist edit for converting structs to appear also on struct keyword and on visibility
1 parent 01a1908 commit e3d26cd

File tree

3 files changed

+192
-6
lines changed

3 files changed

+192
-6
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use syntax::{
77
match_ast, ted,
88
};
99

10-
use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
10+
use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder, utils::find_struct_definition_from_cursor};
1111

1212
// Assist: convert_named_struct_to_tuple_struct
1313
//
@@ -56,8 +56,7 @@ pub(crate) fn convert_named_struct_to_tuple_struct(
5656
// XXX: We don't currently provide this assist for struct definitions inside macros, but if we
5757
// are to lift this limitation, don't forget to make `edit_struct_def()` consider macro files
5858
// too.
59-
let name = ctx.find_node_at_offset::<ast::Name>()?;
60-
let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?;
59+
let strukt = find_struct_definition_from_cursor(ctx)?;
6160
let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
6261
let record_fields = match field_list {
6362
ast::FieldList::RecordFieldList(it) => it,
@@ -293,6 +292,89 @@ impl A {
293292
);
294293
}
295294

295+
#[test]
296+
fn convert_simple_struct_cursor_on_struct_keyword() {
297+
check_assist(
298+
convert_named_struct_to_tuple_struct,
299+
r#"
300+
struct Inner;
301+
struct$0 A { inner: Inner }
302+
303+
impl A {
304+
fn new(inner: Inner) -> A {
305+
A { inner }
306+
}
307+
308+
fn new_with_default() -> A {
309+
A::new(Inner)
310+
}
311+
312+
fn into_inner(self) -> Inner {
313+
self.inner
314+
}
315+
}"#,
316+
r#"
317+
struct Inner;
318+
struct A(Inner);
319+
320+
impl A {
321+
fn new(inner: Inner) -> A {
322+
A(inner)
323+
}
324+
325+
fn new_with_default() -> A {
326+
A::new(Inner)
327+
}
328+
329+
fn into_inner(self) -> Inner {
330+
self.0
331+
}
332+
}"#,
333+
);
334+
}
335+
336+
#[test]
337+
fn convert_simple_struct_cursor_on_visibility_keyword() {
338+
check_assist(
339+
convert_named_struct_to_tuple_struct,
340+
r#"
341+
struct Inner;
342+
pub$0 struct A { inner: Inner }
343+
344+
impl A {
345+
fn new(inner: Inner) -> A {
346+
A { inner }
347+
}
348+
349+
fn new_with_default() -> A {
350+
A::new(Inner)
351+
}
352+
353+
fn into_inner(self) -> Inner {
354+
self.inner
355+
}
356+
}"#,
357+
r#"
358+
struct Inner;
359+
struct A(Inner);
360+
361+
impl A {
362+
fn new(inner: Inner) -> A {
363+
A(inner)
364+
}
365+
366+
fn new_with_default() -> A {
367+
A::new(Inner)
368+
}
369+
370+
fn into_inner(self) -> Inner {
371+
self.0
372+
}
373+
}"#,
374+
);
375+
}
376+
377+
296378
#[test]
297379
fn convert_struct_referenced_via_self_kw() {
298380
check_assist(

src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use syntax::{
66
match_ast, ted,
77
};
88

9-
use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
9+
use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder, utils::find_struct_definition_from_cursor};
1010

1111
// Assist: convert_tuple_struct_to_named_struct
1212
//
@@ -51,8 +51,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
5151
acc: &mut Assists,
5252
ctx: &AssistContext<'_>,
5353
) -> Option<()> {
54-
let name = ctx.find_node_at_offset::<ast::Name>()?;
55-
let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?;
54+
let strukt = find_struct_definition_from_cursor(ctx)?;
5655
let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
5756
let tuple_fields = match field_list {
5857
ast::FieldList::TupleFieldList(it) => it,
@@ -300,6 +299,88 @@ impl A {
300299
struct Inner;
301300
struct A { field1: Inner }
302301
302+
impl A {
303+
fn new(inner: Inner) -> A {
304+
A { field1: inner }
305+
}
306+
307+
fn new_with_default() -> A {
308+
A::new(Inner)
309+
}
310+
311+
fn into_inner(self) -> Inner {
312+
self.field1
313+
}
314+
}"#,
315+
);
316+
}
317+
318+
#[test]
319+
fn convert_simple_struct_cursor_on_struct_keyword() {
320+
check_assist(
321+
convert_tuple_struct_to_named_struct,
322+
r#"
323+
struct Inner;
324+
struct$0 A(Inner);
325+
326+
impl A {
327+
fn new(inner: Inner) -> A {
328+
A(inner)
329+
}
330+
331+
fn new_with_default() -> A {
332+
A::new(Inner)
333+
}
334+
335+
fn into_inner(self) -> Inner {
336+
self.0
337+
}
338+
}"#,
339+
r#"
340+
struct Inner;
341+
struct A { field1: Inner }
342+
343+
impl A {
344+
fn new(inner: Inner) -> A {
345+
A { field1: inner }
346+
}
347+
348+
fn new_with_default() -> A {
349+
A::new(Inner)
350+
}
351+
352+
fn into_inner(self) -> Inner {
353+
self.field1
354+
}
355+
}"#,
356+
);
357+
}
358+
359+
#[test]
360+
fn convert_simple_struct_cursor_on_visibility_keyword() {
361+
check_assist(
362+
convert_tuple_struct_to_named_struct,
363+
r#"
364+
struct Inner;
365+
pub$0 struct A(Inner);
366+
367+
impl A {
368+
fn new(inner: Inner) -> A {
369+
A(inner)
370+
}
371+
372+
fn new_with_default() -> A {
373+
A::new(Inner)
374+
}
375+
376+
fn into_inner(self) -> Inner {
377+
self.0
378+
}
379+
}"#,
380+
r#"
381+
struct Inner;
382+
pub struct A { field1: Inner }
383+
303384
impl A {
304385
fn new(inner: Inner) -> A {
305386
A { field1: inner }

src/tools/rust-analyzer/crates/ide-assists/src/utils.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Assorted functions shared by several assists.
22
3+
use either::Either;
4+
35
pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
46
use hir::{
57
DisplayTarget, HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution,
@@ -1146,3 +1148,24 @@ pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bo
11461148
});
11471149
is_const
11481150
}
1151+
1152+
/// Gets the struct definition from a context
1153+
pub(crate) fn find_struct_definition_from_cursor(ctx: &AssistContext<'_>)
1154+
-> Option<Either<ast::Struct, ast::Variant>>
1155+
{
1156+
ctx.find_node_at_offset::<ast::Name>().and_then(|name| name.syntax().parent())
1157+
.or(find_struct_keyword(ctx).and_then(|kw| kw.parent()))
1158+
.or(ctx.find_node_at_offset::<ast::Visibility>().and_then(|visibility| visibility.syntax().parent()))
1159+
.and_then(<Either<ast::Struct, ast::Variant>>::cast)
1160+
}
1161+
1162+
fn find_struct_keyword(ctx: &AssistContext<'_>) -> Option<SyntaxToken> {
1163+
// Attempt to find the token at the current cursor offset
1164+
ctx
1165+
.token_at_offset()
1166+
.find(|leaf| match leaf.kind() {
1167+
STRUCT_KW => true,
1168+
_ => false,
1169+
})
1170+
}
1171+

0 commit comments

Comments
 (0)