diff --git a/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 6901589896..358e0c43c2 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -1,5 +1,3 @@ -use std::iter; - use either::Either; use hir::{Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union, db::ExpandDatabase}; use ide_db::text_edit::TextEdit; @@ -194,17 +192,20 @@ fn add_field_to_struct_fix( Some(make::visibility_pub_crate()) }; // FIXME: Allow for choosing a visibility modifier see https://github.com/rust-lang/rust-analyzer/issues/11563 - let indent = IndentLevel::from_node(struct_syntax.value) + 1; + let indent = IndentLevel::from_node(struct_syntax.value); - let field = make::record_field(visibility, field_name, suggested_type).indent(indent); - let record_field_list = make::record_field_list(iter::once(field)); + let field = + make::record_field(visibility, field_name, suggested_type).indent(indent + 1); // A Unit Struct with no `;` is invalid syntax. We should not suggest this fix. let semi_colon = algo::skip_trivia_token(struct_syntax.value.last_token()?, Direction::Prev)?; if semi_colon.kind() != SyntaxKind::SEMICOLON { return None; } - src_change_builder.replace(semi_colon.text_range(), record_field_list.to_string()); + src_change_builder.replace( + semi_colon.text_range(), + format!(" {{\n{}{field},\n{indent}}}", indent + 1), + ); Some(Assist { id: AssistId::quick_fix("convert-unit-struct-to-record-struct"), @@ -230,7 +231,7 @@ fn record_field_layout( field_list: ast::RecordFieldList, struct_syntax: &SyntaxNode, ) -> Option<(TextSize, String)> { - let (offset, needs_comma, trailing_new_line, indent) = match field_list.fields().last() { + let (offset, needs_comma, indent) = match field_list.fields().last() { Some(record_field) => { let syntax = algo::skip_trivia_token(field_list.r_curly_token()?, Direction::Prev)?; @@ -239,19 +240,22 @@ fn record_field_layout( ( last_field_syntax.text_range().end(), syntax.kind() != SyntaxKind::COMMA, - false, last_field_indent, ) } // Empty Struct. Add a field right before the closing brace None => { let indent = IndentLevel::from_node(struct_syntax) + 1; - let offset = field_list.r_curly_token()?.text_range().start(); - (offset, false, true, indent) + let offset = field_list.l_curly_token()?.text_range().end(); + (offset, false, indent) } }; - let comma = if needs_comma { ",\n" } else { "" }; - let trailing_new_line = if trailing_new_line { "\n" } else { "" }; + let trailing_new_line = if !field_list.syntax().text().contains_char('\n') { + format!("\n{}", field_list.indent_level()) + } else { + String::new() + }; + let comma = if needs_comma { ",\n" } else { "\n" }; let record_field = make::record_field(visibility, name, suggested_type); Some((offset, format!("{comma}{indent}{record_field}{trailing_new_line}"))) @@ -377,18 +381,24 @@ fn foo() { fn unresolved_field_fix_on_unit() { check_fix( r#" + mod indent { struct Foo; fn foo() { Foo.bar$0; } + } "#, r#" - struct Foo{ bar: () } + mod indent { + struct Foo { + bar: (), + } fn foo() { Foo.bar; } + } "#, ); } @@ -396,6 +406,7 @@ fn foo() { fn unresolved_field_fix_on_empty() { check_fix( r#" + mod indent { struct Foo{ } @@ -403,8 +414,10 @@ fn foo() { let foo = Foo{}; foo.bar$0; } + } "#, r#" + mod indent { struct Foo{ bar: () } @@ -413,6 +426,32 @@ fn foo() { let foo = Foo{}; foo.bar; } + } + "#, + ); + + check_fix( + r#" + mod indent { + struct Foo {} + + fn foo() { + let foo = Foo{}; + foo.bar$0; + } + } + "#, + r#" + mod indent { + struct Foo { + bar: () + } + + fn foo() { + let foo = Foo{}; + foo.bar; + } + } "#, ); }