From db8fbb99ce6e60c072250bada004de9645431a43 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 17 May 2021 11:40:34 +0300 Subject: minor: extract fix to file --- .../src/diagnostics/fixes/fill_missing_fields.rs | 192 +++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 crates/ide/src/diagnostics/fixes/fill_missing_fields.rs (limited to 'crates/ide/src/diagnostics/fixes') diff --git a/crates/ide/src/diagnostics/fixes/fill_missing_fields.rs b/crates/ide/src/diagnostics/fixes/fill_missing_fields.rs new file mode 100644 index 000000000..123c2f0af --- /dev/null +++ b/crates/ide/src/diagnostics/fixes/fill_missing_fields.rs @@ -0,0 +1,192 @@ +use hir::{db::AstDatabase, diagnostics::MissingFields, Semantics}; +use ide_assists::AssistResolveStrategy; +use ide_db::{source_change::SourceChange, RootDatabase}; +use syntax::{algo, ast::make, AstNode}; +use text_edit::TextEdit; + +use crate::{ + diagnostics::{fix, fixes::DiagnosticWithFix}, + Assist, +}; + +impl DiagnosticWithFix for MissingFields { + fn fix( + &self, + sema: &Semantics, + _resolve: &AssistResolveStrategy, + ) -> Option { + // Note that although we could add a diagnostics to + // fill the missing tuple field, e.g : + // `struct A(usize);` + // `let a = A { 0: () }` + // but it is uncommon usage and it should not be encouraged. + if self.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) { + return None; + } + + let root = sema.db.parse_or_expand(self.file)?; + let field_list_parent = self.field_list_parent.to_node(&root); + let old_field_list = field_list_parent.record_expr_field_list()?; + let new_field_list = old_field_list.clone_for_update(); + for f in self.missed_fields.iter() { + let field = + make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit())) + .clone_for_update(); + new_field_list.add_field(field); + } + + let edit = { + let mut builder = TextEdit::builder(); + algo::diff(&old_field_list.syntax(), &new_field_list.syntax()) + .into_text_edit(&mut builder); + builder.finish() + }; + Some(fix( + "fill_missing_fields", + "Fill struct fields", + SourceChange::from_text_edit(self.file.original_file(sema.db), edit), + sema.original_range(&field_list_parent.syntax()).range, + )) + } +} + +#[cfg(test)] +mod tests { + use crate::diagnostics::tests::{check_fix, check_no_diagnostics}; + + #[test] + fn test_fill_struct_fields_empty() { + check_fix( + r#" +struct TestStruct { one: i32, two: i64 } + +fn test_fn() { + let s = TestStruct {$0}; +} +"#, + r#" +struct TestStruct { one: i32, two: i64 } + +fn test_fn() { + let s = TestStruct { one: (), two: () }; +} +"#, + ); + } + + #[test] + fn test_fill_struct_fields_self() { + check_fix( + r#" +struct TestStruct { one: i32 } + +impl TestStruct { + fn test_fn() { let s = Self {$0}; } +} +"#, + r#" +struct TestStruct { one: i32 } + +impl TestStruct { + fn test_fn() { let s = Self { one: () }; } +} +"#, + ); + } + + #[test] + fn test_fill_struct_fields_enum() { + check_fix( + r#" +enum Expr { + Bin { lhs: Box, rhs: Box } +} + +impl Expr { + fn new_bin(lhs: Box, rhs: Box) -> Expr { + Expr::Bin {$0 } + } +} +"#, + r#" +enum Expr { + Bin { lhs: Box, rhs: Box } +} + +impl Expr { + fn new_bin(lhs: Box, rhs: Box) -> Expr { + Expr::Bin { lhs: (), rhs: () } + } +} +"#, + ); + } + + #[test] + fn test_fill_struct_fields_partial() { + check_fix( + r#" +struct TestStruct { one: i32, two: i64 } + +fn test_fn() { + let s = TestStruct{ two: 2$0 }; +} +"#, + r" +struct TestStruct { one: i32, two: i64 } + +fn test_fn() { + let s = TestStruct{ two: 2, one: () }; +} +", + ); + } + + #[test] + fn test_fill_struct_fields_raw_ident() { + check_fix( + r#" +struct TestStruct { r#type: u8 } + +fn test_fn() { + TestStruct { $0 }; +} +"#, + r" +struct TestStruct { r#type: u8 } + +fn test_fn() { + TestStruct { r#type: () }; +} +", + ); + } + + #[test] + fn test_fill_struct_fields_no_diagnostic() { + check_no_diagnostics( + r#" +struct TestStruct { one: i32, two: i64 } + +fn test_fn() { + let one = 1; + let s = TestStruct{ one, two: 2 }; +} + "#, + ); + } + + #[test] + fn test_fill_struct_fields_no_diagnostic_on_spread() { + check_no_diagnostics( + r#" +struct TestStruct { one: i32, two: i64 } + +fn test_fn() { + let one = 1; + let s = TestStruct{ ..a }; +} +"#, + ); + } +} -- cgit v1.2.3