From 1d2772c2c7dc0a42d8a9429d24ea41412add61b3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 14 Jun 2021 13:15:05 +0300 Subject: internal: move diagnostics to a new crate --- crates/ide_diagnostics/src/field_shorthand.rs | 203 ++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 crates/ide_diagnostics/src/field_shorthand.rs (limited to 'crates/ide_diagnostics/src/field_shorthand.rs') diff --git a/crates/ide_diagnostics/src/field_shorthand.rs b/crates/ide_diagnostics/src/field_shorthand.rs new file mode 100644 index 000000000..0b6af9965 --- /dev/null +++ b/crates/ide_diagnostics/src/field_shorthand.rs @@ -0,0 +1,203 @@ +//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both +//! expressions and patterns. + +use ide_db::{base_db::FileId, source_change::SourceChange}; +use syntax::{ast, match_ast, AstNode, SyntaxNode}; +use text_edit::TextEdit; + +use crate::{fix, Diagnostic, Severity}; + +pub(super) fn check(acc: &mut Vec, file_id: FileId, node: &SyntaxNode) { + match_ast! { + match node { + ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it), + ast::RecordPat(it) => check_pat_field_shorthand(acc, file_id, it), + _ => () + } + }; +} + +fn check_expr_field_shorthand( + acc: &mut Vec, + file_id: FileId, + record_expr: ast::RecordExpr, +) { + let record_field_list = match record_expr.record_expr_field_list() { + Some(it) => it, + None => return, + }; + for record_field in record_field_list.fields() { + let (name_ref, expr) = match record_field.name_ref().zip(record_field.expr()) { + Some(it) => it, + None => continue, + }; + + let field_name = name_ref.syntax().text().to_string(); + let field_expr = expr.syntax().text().to_string(); + let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); + if field_name != field_expr || field_name_is_tup_index { + continue; + } + + let mut edit_builder = TextEdit::builder(); + edit_builder.delete(record_field.syntax().text_range()); + edit_builder.insert(record_field.syntax().text_range().start(), field_name); + let edit = edit_builder.finish(); + + let field_range = record_field.syntax().text_range(); + acc.push( + Diagnostic::new("use-field-shorthand", "Shorthand struct initialization", field_range) + .severity(Severity::WeakWarning) + .with_fixes(Some(vec![fix( + "use_expr_field_shorthand", + "Use struct shorthand initialization", + SourceChange::from_text_edit(file_id, edit), + field_range, + )])), + ); + } +} + +fn check_pat_field_shorthand( + acc: &mut Vec, + file_id: FileId, + record_pat: ast::RecordPat, +) { + let record_pat_field_list = match record_pat.record_pat_field_list() { + Some(it) => it, + None => return, + }; + for record_pat_field in record_pat_field_list.fields() { + let (name_ref, pat) = match record_pat_field.name_ref().zip(record_pat_field.pat()) { + Some(it) => it, + None => continue, + }; + + let field_name = name_ref.syntax().text().to_string(); + let field_pat = pat.syntax().text().to_string(); + let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); + if field_name != field_pat || field_name_is_tup_index { + continue; + } + + let mut edit_builder = TextEdit::builder(); + edit_builder.delete(record_pat_field.syntax().text_range()); + edit_builder.insert(record_pat_field.syntax().text_range().start(), field_name); + let edit = edit_builder.finish(); + + let field_range = record_pat_field.syntax().text_range(); + acc.push( + Diagnostic::new("use-field-shorthand", "Shorthand struct pattern", field_range) + .severity(Severity::WeakWarning) + .with_fixes(Some(vec![fix( + "use_pat_field_shorthand", + "Use struct field shorthand", + SourceChange::from_text_edit(file_id, edit), + field_range, + )])), + ); + } +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_diagnostics, check_fix}; + + #[test] + fn test_check_expr_field_shorthand() { + check_diagnostics( + r#" +struct A { a: &'static str } +fn main() { A { a: "hello" } } +"#, + ); + check_diagnostics( + r#" +struct A(usize); +fn main() { A { 0: 0 } } +"#, + ); + + check_fix( + r#" +struct A { a: &'static str } +fn main() { + let a = "haha"; + A { a$0: a } +} +"#, + r#" +struct A { a: &'static str } +fn main() { + let a = "haha"; + A { a } +} +"#, + ); + + check_fix( + r#" +struct A { a: &'static str, b: &'static str } +fn main() { + let a = "haha"; + let b = "bb"; + A { a$0: a, b } +} +"#, + r#" +struct A { a: &'static str, b: &'static str } +fn main() { + let a = "haha"; + let b = "bb"; + A { a, b } +} +"#, + ); + } + + #[test] + fn test_check_pat_field_shorthand() { + check_diagnostics( + r#" +struct A { a: &'static str } +fn f(a: A) { let A { a: hello } = a; } +"#, + ); + check_diagnostics( + r#" +struct A(usize); +fn f(a: A) { let A { 0: 0 } = a; } +"#, + ); + + check_fix( + r#" +struct A { a: &'static str } +fn f(a: A) { + let A { a$0: a } = a; +} +"#, + r#" +struct A { a: &'static str } +fn f(a: A) { + let A { a } = a; +} +"#, + ); + + check_fix( + r#" +struct A { a: &'static str, b: &'static str } +fn f(a: A) { + let A { a$0: a, b } = a; +} +"#, + r#" +struct A { a: &'static str, b: &'static str } +fn f(a: A) { + let A { a, b } = a; +} +"#, + ); + } +} -- cgit v1.2.3