Skip to content

Commit 34e7e79

Browse files
committed
Auto merge of #17993 - ChayimFriedman2:convert-to-tuple-attrs, r=Veykril
Consider field attributes when converting from tuple to named struct and the opposite Fixes #17983. I tried to use the `SourceChangeBuilder::make_mut()` API, but it duplicated the attribute...
2 parents cd377d9 + b3fcd8e commit 34e7e79

File tree

2 files changed

+49
-11
lines changed

2 files changed

+49
-11
lines changed

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

+26-5
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use either::Either;
22
use ide_db::{defs::Definition, search::FileReference};
33
use itertools::Itertools;
44
use syntax::{
5-
ast::{self, AstNode, HasGenericParams, HasVisibility},
6-
match_ast, SyntaxKind,
5+
ast::{self, AstNode, HasAttrs, HasGenericParams, HasVisibility},
6+
match_ast, ted, SyntaxKind,
77
};
88

99
use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
@@ -87,9 +87,14 @@ fn edit_struct_def(
8787
) {
8888
// Note that we don't need to consider macro files in this function because this is
8989
// currently not triggered for struct definitions inside macro calls.
90-
let tuple_fields = record_fields
91-
.fields()
92-
.filter_map(|f| Some(ast::make::tuple_field(f.visibility(), f.ty()?)));
90+
let tuple_fields = record_fields.fields().filter_map(|f| {
91+
let field = ast::make::tuple_field(f.visibility(), f.ty()?).clone_for_update();
92+
ted::insert_all(
93+
ted::Position::first_child_of(field.syntax()),
94+
f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(),
95+
);
96+
Some(field)
97+
});
9398
let tuple_fields = ast::make::tuple_field_list(tuple_fields);
9499
let record_fields_text_range = record_fields.syntax().text_range();
95100

@@ -975,6 +980,22 @@ impl HasAssoc for Struct {
975980
let Self::Assoc { value } = a;
976981
}
977982
}
983+
"#,
984+
);
985+
}
986+
987+
#[test]
988+
fn fields_with_attrs() {
989+
check_assist(
990+
convert_named_struct_to_tuple_struct,
991+
r#"
992+
pub struct $0Foo {
993+
#[my_custom_attr]
994+
value: u32,
995+
}
996+
"#,
997+
r#"
998+
pub struct Foo(#[my_custom_attr] u32);
978999
"#,
9791000
);
9801001
}

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

+23-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use either::Either;
22
use ide_db::defs::{Definition, NameRefClass};
33
use syntax::{
4-
ast::{self, AstNode, HasGenericParams, HasVisibility},
5-
match_ast, SyntaxKind, SyntaxNode,
4+
ast::{self, AstNode, HasAttrs, HasGenericParams, HasVisibility},
5+
match_ast, ted, SyntaxKind, SyntaxNode,
66
};
77

88
use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
@@ -83,10 +83,14 @@ fn edit_struct_def(
8383
tuple_fields: ast::TupleFieldList,
8484
names: Vec<ast::Name>,
8585
) {
86-
let record_fields = tuple_fields
87-
.fields()
88-
.zip(names)
89-
.filter_map(|(f, name)| Some(ast::make::record_field(f.visibility(), name, f.ty()?)));
86+
let record_fields = tuple_fields.fields().zip(names).filter_map(|(f, name)| {
87+
let field = ast::make::record_field(f.visibility(), name, f.ty()?).clone_for_update();
88+
ted::insert_all(
89+
ted::Position::first_child_of(field.syntax()),
90+
f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(),
91+
);
92+
Some(field)
93+
});
9094
let record_fields = ast::make::record_field_list(record_fields);
9195
let tuple_fields_text_range = tuple_fields.syntax().text_range();
9296

@@ -904,6 +908,19 @@ where
904908
T: Foo,
905909
{ pub field1: T }
906910
911+
"#,
912+
);
913+
}
914+
915+
#[test]
916+
fn fields_with_attrs() {
917+
check_assist(
918+
convert_tuple_struct_to_named_struct,
919+
r#"
920+
pub struct $0Foo(#[my_custom_attr] u32);
921+
"#,
922+
r#"
923+
pub struct Foo { #[my_custom_attr] field1: u32 }
907924
"#,
908925
);
909926
}

0 commit comments

Comments
 (0)