wowlab_tidy/languages/rust/rules/style/
redundant_field_names.rs1use ra_ap_syntax::{AstNode, ast};
2
3use crate::{AstCtx, Example, Fix, Violation, infra::parse};
4
5#[rustfmt::skip]
6const EXAMPLES: &[Example] = &[
7 Example {
8 label: "redundant field name",
9 code: "struct S { x: i32 }\nfn f(x: i32) -> S { S { x: x } }",
10 pass: false,
11 },
12 Example {
13 label: "shorthand field init",
14 code: "struct S { x: i32 }\nfn f(x: i32) -> S { S { x } }",
15 pass: true,
16 },
17 Example {
18 label: "different name and value",
19 code: "struct S { x: i32 }\nfn f(y: i32) -> S { S { x: y } }",
20 pass: true,
21 },
22 Example {
23 label: "redundant in test",
24 code: "#[cfg(test)]\nmod tests {\n struct S { x: i32 }\n fn t(x: i32) -> S { S { x: x } }\n}",
25 pass: true,
26 },
27];
28
29crate::ast_rule!(
30 redundant_field_names,
31 "Flag `Foo { x: x }` — use shorthand `Foo { x }` instead.",
32 "Rust supports field init shorthand (Foo { x } instead of Foo { x: x }). The long form is needless noise.",
33 Low,
34 fix_redundant_field_names,
35);
36
37fn check_redundant_field_names(ctx: &AstCtx<'_>) -> Vec<Violation> {
38 ctx.nodes::<ast::RecordExprField>()
39 .filter(|field| !ctx.is_in_test(field) && field.colon_token().is_some())
40 .filter_map(|field| {
41 let name = field.name_ref()?;
42 let ast::Expr::PathExpr(path) = field.expr()? else {
43 return None;
44 };
45
46 (path.syntax().text().to_string() == name.text()).then(|| {
47 let name_text = name.text();
48
49 ctx.violation(
50 &name,
51 format!(
52 "redundant field initializer `{name_text}: {name_text}` — use shorthand `{name_text}`"
53 ),
54 )
55 })
56 })
57 .collect()
58}
59
60fn fix_redundant_field_names(ctx: &AstCtx<'_>, v: &Violation) -> Option<Fix> {
61 let line = ctx.file.line(v.line)?;
62 let name = parse::redundant_field_name(&v.message)?;
63 let redundant = format!("{name}: {name}");
64
65 line.contains(&redundant)
66 .then(|| Fix::replace_line(v.line, line.replacen(&redundant, name, 1)))
67}
68
69crate::tidy_ast_test!(check_redundant_field_names, {
70 crate::example_tests!(EXAMPLES, check_redundant_field_names);
71 crate::fix_tests!(ast, check_redundant_field_names, fix_redundant_field_names);
72});