2020-10-15 10:07:53 -05:00
|
|
|
//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both
|
|
|
|
//! expressions and patterns.
|
|
|
|
|
2021-01-14 15:43:36 -06:00
|
|
|
use ide_db::{base_db::FileId, source_change::SourceChange};
|
2020-10-15 10:07:53 -05:00
|
|
|
use syntax::{ast, match_ast, AstNode, SyntaxNode};
|
|
|
|
use text_edit::TextEdit;
|
|
|
|
|
2021-06-14 05:15:05 -05:00
|
|
|
use crate::{fix, Diagnostic, Severity};
|
2020-10-15 10:07:53 -05:00
|
|
|
|
2021-06-14 13:23:59 -05:00
|
|
|
pub(crate) fn field_shorthand(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) {
|
2020-10-15 10:07:53 -05:00
|
|
|
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<Diagnostic>,
|
|
|
|
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();
|
2020-10-20 10:48:43 -05:00
|
|
|
acc.push(
|
2021-06-13 14:11:33 -05:00
|
|
|
Diagnostic::new("use-field-shorthand", "Shorthand struct initialization", field_range)
|
|
|
|
.severity(Severity::WeakWarning)
|
2021-05-17 18:11:07 -05:00
|
|
|
.with_fixes(Some(vec![fix(
|
2021-04-12 09:58:01 -05:00
|
|
|
"use_expr_field_shorthand",
|
2020-10-20 10:48:43 -05:00
|
|
|
"Use struct shorthand initialization",
|
2021-01-14 15:43:36 -06:00
|
|
|
SourceChange::from_text_edit(file_id, edit),
|
2020-10-20 10:48:43 -05:00
|
|
|
field_range,
|
2021-05-17 18:11:07 -05:00
|
|
|
)])),
|
2020-10-20 10:48:43 -05:00
|
|
|
);
|
2020-10-15 10:07:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_pat_field_shorthand(
|
|
|
|
acc: &mut Vec<Diagnostic>,
|
|
|
|
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();
|
2021-06-13 14:11:33 -05:00
|
|
|
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,
|
|
|
|
)])),
|
|
|
|
);
|
2020-10-15 10:07:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-06-14 05:15:05 -05:00
|
|
|
use crate::tests::{check_diagnostics, check_fix};
|
2020-10-15 10:07:53 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_check_expr_field_shorthand() {
|
2021-06-13 11:27:14 -05:00
|
|
|
check_diagnostics(
|
2020-10-15 10:07:53 -05:00
|
|
|
r#"
|
|
|
|
struct A { a: &'static str }
|
2022-03-20 10:26:48 -05:00
|
|
|
fn main() { A { a: "hello" }; }
|
2020-10-15 10:07:53 -05:00
|
|
|
"#,
|
|
|
|
);
|
2021-06-13 11:27:14 -05:00
|
|
|
check_diagnostics(
|
2020-10-15 10:07:53 -05:00
|
|
|
r#"
|
|
|
|
struct A(usize);
|
2022-03-20 10:26:48 -05:00
|
|
|
fn main() { A { 0: 0 }; }
|
2020-10-15 10:07:53 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_fix(
|
|
|
|
r#"
|
|
|
|
struct A { a: &'static str }
|
|
|
|
fn main() {
|
|
|
|
let a = "haha";
|
2022-03-20 10:26:48 -05:00
|
|
|
A { a$0: a };
|
2020-10-15 10:07:53 -05:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct A { a: &'static str }
|
|
|
|
fn main() {
|
|
|
|
let a = "haha";
|
2022-03-20 10:26:48 -05:00
|
|
|
A { a };
|
2020-10-15 10:07:53 -05:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_fix(
|
|
|
|
r#"
|
|
|
|
struct A { a: &'static str, b: &'static str }
|
|
|
|
fn main() {
|
|
|
|
let a = "haha";
|
|
|
|
let b = "bb";
|
2022-03-20 10:26:48 -05:00
|
|
|
A { a$0: a, b };
|
2020-10-15 10:07:53 -05:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct A { a: &'static str, b: &'static str }
|
|
|
|
fn main() {
|
|
|
|
let a = "haha";
|
|
|
|
let b = "bb";
|
2022-03-20 10:26:48 -05:00
|
|
|
A { a, b };
|
2020-10-15 10:07:53 -05:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_check_pat_field_shorthand() {
|
2021-06-13 11:27:14 -05:00
|
|
|
check_diagnostics(
|
2020-10-15 10:07:53 -05:00
|
|
|
r#"
|
|
|
|
struct A { a: &'static str }
|
|
|
|
fn f(a: A) { let A { a: hello } = a; }
|
|
|
|
"#,
|
|
|
|
);
|
2021-06-13 11:27:14 -05:00
|
|
|
check_diagnostics(
|
2020-10-15 10:07:53 -05:00
|
|
|
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) {
|
2021-01-06 14:15:48 -06:00
|
|
|
let A { a$0: a } = a;
|
2020-10-15 10:07:53 -05:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
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) {
|
2021-01-06 14:15:48 -06:00
|
|
|
let A { a$0: a, b } = a;
|
2020-10-15 10:07:53 -05:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct A { a: &'static str, b: &'static str }
|
|
|
|
fn f(a: A) {
|
|
|
|
let A { a, b } = a;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|