@@ -57,27 +57,34 @@ pub(crate) fn unresolved_field(
5757}
5858
5959fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<Assist>> {
60- let mut fixes = if d.method_with_same_name_exists { method_fix(ctx, &d.expr) } else { None };
61- if let Some(fix) = add_field_fix(ctx, d) {
62- fixes.get_or_insert_with(Vec::new).extend(fix);
60+ let mut fixes = Vec::new();
61+ if d.method_with_same_name_exists {
62+ fixes.extend(method_fix(ctx, &d.expr));
63+ }
64+ fixes.extend(field_fix(ctx, d));
65+ if fixes.is_empty() {
66+ None
67+ } else {
68+ Some(fixes)
6369 }
64- fixes
6570}
6671
67- fn add_field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<Assist>> {
72+ // FIXME: Add Snippet Support
73+ fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Assist> {
6874 // Get the FileRange of the invalid field access
6975 let root = ctx.sema.db.parse_or_expand(d.expr.file_id);
7076 let expr = d.expr.value.to_node(&root);
7177
7278 let error_range = ctx.sema.original_range_opt(expr.syntax())?;
79+ let field_name = d.name.as_str()?;
7380 // Convert the receiver to an ADT
74- let adt = d.receiver.as_adt()?;
81+ let adt = d.receiver.strip_references(). as_adt()?;
7582 let target_module = adt.module(ctx.sema.db);
7683
7784 let suggested_type =
7885 if let Some(new_field_type) = ctx.sema.type_of_expr(&expr).map(|v| v.adjusted()) {
7986 let display =
80- new_field_type.display_source_code(ctx.sema.db, target_module.into(), true ).ok();
87+ new_field_type.display_source_code(ctx.sema.db, target_module.into(), false ).ok();
8188 make::ty(display.as_deref().unwrap_or("()"))
8289 } else {
8390 make::ty("()")
@@ -87,9 +94,6 @@ fn add_field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Opti
8794 return None;
8895 }
8996
90- // FIXME: Add Snippet Support
91- let field_name = d.name.as_str()?;
92-
9397 match adt {
9498 Adt::Struct(adt_struct) => {
9599 add_field_to_struct_fix(ctx, adt_struct, field_name, suggested_type, error_range)
@@ -100,13 +104,14 @@ fn add_field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Opti
100104 _ => None,
101105 }
102106}
107+
103108fn add_variant_to_union(
104109 ctx: &DiagnosticsContext<'_>,
105110 adt_union: Union,
106111 field_name: &str,
107112 suggested_type: Type,
108113 error_range: FileRange,
109- ) -> Option<Vec< Assist> > {
114+ ) -> Option<Assist> {
110115 let adt_source = adt_union.source(ctx.sema.db)?;
111116 let adt_syntax = adt_source.syntax();
112117 let Some(field_list) = adt_source.value.record_field_list() else {
@@ -120,22 +125,23 @@ fn add_variant_to_union(
120125
121126 let mut src_change_builder = SourceChangeBuilder::new(range.file_id);
122127 src_change_builder.insert(offset, record_field);
123- Some(vec![ Assist {
128+ Some(Assist {
124129 id: AssistId("add-variant-to-union", AssistKind::QuickFix),
125130 label: Label::new("Add field to union".to_owned()),
126131 group: None,
127132 target: error_range.range,
128133 source_change: Some(src_change_builder.finish()),
129134 trigger_signature_help: false,
130- }] )
135+ })
131136}
137+
132138fn add_field_to_struct_fix(
133139 ctx: &DiagnosticsContext<'_>,
134140 adt_struct: Struct,
135141 field_name: &str,
136142 suggested_type: Type,
137143 error_range: FileRange,
138- ) -> Option<Vec< Assist> > {
144+ ) -> Option<Assist> {
139145 let struct_source = adt_struct.source(ctx.sema.db)?;
140146 let struct_syntax = struct_source.syntax();
141147 let struct_range = struct_syntax.original_file_range(ctx.sema.db);
@@ -162,14 +168,14 @@ fn add_field_to_struct_fix(
162168
163169 // FIXME: Allow for choosing a visibility modifier see https://github.com/rust-lang/rust-analyzer/issues/11563
164170 src_change_builder.insert(offset, record_field);
165- Some(vec![ Assist {
171+ Some(Assist {
166172 id: AssistId("add-field-to-record-struct", AssistKind::QuickFix),
167173 label: Label::new("Add field to Record Struct".to_owned()),
168174 group: None,
169175 target: error_range.range,
170176 source_change: Some(src_change_builder.finish()),
171177 trigger_signature_help: false,
172- }] )
178+ })
173179 }
174180 None => {
175181 // Add a field list to the Unit Struct
@@ -193,21 +199,22 @@ fn add_field_to_struct_fix(
193199 }
194200 src_change_builder.replace(semi_colon.text_range(), record_field_list.to_string());
195201
196- Some(vec![ Assist {
202+ Some(Assist {
197203 id: AssistId("convert-unit-struct-to-record-struct", AssistKind::QuickFix),
198204 label: Label::new("Convert Unit Struct to Record Struct and add field".to_owned()),
199205 group: None,
200206 target: error_range.range,
201207 source_change: Some(src_change_builder.finish()),
202208 trigger_signature_help: false,
203- }] )
209+ })
204210 }
205211 Some(FieldList::TupleFieldList(_tuple)) => {
206212 // FIXME: Add support for Tuple Structs. Tuple Structs are not sent to this diagnostic
207213 None
208214 }
209215 }
210216}
217+
211218/// Used to determine the layout of the record field in the struct.
212219fn record_field_layout(
213220 visibility: Option<Visibility>,
@@ -242,15 +249,16 @@ fn record_field_layout(
242249
243250 Some((offset, format!("{comma}{indent}{record_field}{trailing_new_line}")))
244251}
252+
245253// FIXME: We should fill out the call here, move the cursor and trigger signature help
246254fn method_fix(
247255 ctx: &DiagnosticsContext<'_>,
248256 expr_ptr: &InFile<AstPtr<ast::Expr>>,
249- ) -> Option<Vec< Assist> > {
257+ ) -> Option<Assist> {
250258 let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
251259 let expr = expr_ptr.value.to_node(&root);
252260 let FileRange { range, file_id } = ctx.sema.original_range_opt(expr.syntax())?;
253- Some(vec![ Assist {
261+ Some(Assist {
254262 id: AssistId("expected-field-found-method-call-fix", AssistKind::QuickFix),
255263 label: Label::new("Use parentheses to call the method".to_owned()),
256264 group: None,
@@ -260,7 +268,7 @@ fn method_fix(
260268 TextEdit::insert(range.end(), "()".to_owned()),
261269 )),
262270 trigger_signature_help: false,
263- }] )
271+ })
264272}
265273#[cfg(test)]
266274mod tests {
0 commit comments