Skip to main content

wowlab_tidy/languages/rust/rules/style/
long_compound_name.rs

1use ra_ap_syntax::ast;
2
3use super::naming;
4use crate::{AstCtx, Example, Violation};
5
6#[rustfmt::skip]
7const EXAMPLES: &[Example] = &[
8    Example {
9        label: "five-word struct name",
10        code: "struct GlobalApplicationConfigManagerImpl;",
11        pass: false,
12    },
13    Example {
14        label: "five-word enum name",
15        code: "enum BookingRequestQueueItemState { A }",
16        pass: false,
17    },
18    Example {
19        label: "five-word trait name",
20        code: "trait AsyncRemoteAccountDataSource {}",
21        pass: false,
22    },
23    Example {
24        label: "five-word type alias",
25        code: "type SharedRemoteAccountDataCache = ();",
26        pass: false,
27    },
28    Example {
29        label: "two-word name",
30        code: "struct AppConfig;",
31        pass: true,
32    },
33    Example {
34        label: "four words is at the threshold",
35        code: "struct HtmlParserConfigBuilder;",
36        pass: true,
37    },
38    Example {
39        label: "acronym run counts as one word",
40        code: "struct HTMLParserConfigBuilder;",
41        pass: true,
42    },
43    Example {
44        label: "long name in test module",
45        code: "#[cfg(test)]\nmod tests {\n    struct GlobalApplicationConfigManagerFake;\n}",
46        pass: true,
47    },
48];
49
50crate::ast_rule!(
51    long_compound_name,
52    "Flag type definitions whose CamelCase name compounds more than threshold words.",
53    "Rust item names are short: `AppConfig` over `GlobalApplicationConfig`; long compounds hide the item's essence (M-SHORT-NAMES).",
54    Low,
55    params { threshold: i64 = 4 },
56);
57
58fn check_long_compound_name(ctx: &AstCtx<'_>) -> Vec<Violation> {
59    let threshold = ctx
60        .file
61        .config
62        .get_usize("rust_long_compound_name", &PARAMS[0]);
63
64    ctx.nodes::<ast::Item>()
65        .filter(|item| !ctx.is_in_test(item))
66        .filter_map(|item| {
67            let name = naming::type_def_name(&item)?;
68            let name_text = name.text();
69            let words = naming::segments(&name_text).len();
70
71            (words > threshold).then(|| {
72                ctx.violation(
73                    &name,
74                    format!(
75                        "type name `{name_text}` compounds {words} words (max {threshold}) — shorten it"
76                    ),
77                )
78            })
79        })
80        .collect()
81}
82
83crate::tidy_ast_test!(check_long_compound_name, {
84    crate::example_tests!(EXAMPLES, check_long_compound_name);
85});