Skip to main content

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

1use ra_ap_syntax::ast::{self, HasName};
2
3use crate::{AstCtx, Example, Violation};
4
5#[rustfmt::skip]
6const EXAMPLES: &[Example] = &[
7    Example {
8        label: "get_ method",
9        code: "struct S;\nimpl S {\n    fn get_name(&self) {}\n}",
10        pass: false,
11    },
12    Example {
13        label: "get_ trait method",
14        code: "trait T {\n    fn get_len(&self) -> usize;\n}",
15        pass: false,
16    },
17    Example {
18        label: "plain get passes",
19        code: "struct S;\nimpl S {\n    fn get(&self) {}\n}",
20        pass: true,
21    },
22    Example {
23        label: "get_mut passes",
24        code: "struct S;\nimpl S {\n    fn get_mut(&mut self) {}\n}",
25        pass: true,
26    },
27    Example {
28        label: "get_unchecked_mut passes",
29        code: "struct S;\nimpl S {\n    fn get_unchecked_mut(&mut self) {}\n}",
30        pass: true,
31    },
32    Example {
33        label: "get_or_insert_with passes",
34        code: "struct S;\nimpl S {\n    fn get_or_insert_with(&mut self) {}\n}",
35        pass: true,
36    },
37    Example {
38        label: "free fn is not a getter",
39        code: "fn get_config() {}",
40        pass: true,
41    },
42    Example {
43        label: "associated fn without receiver",
44        code: "struct S;\nimpl S {\n    fn get_default() -> S { S }\n}",
45        pass: true,
46    },
47    Example {
48        label: "getter in test module",
49        code: "#[cfg(test)]\nmod tests {\n    struct S;\n    impl S {\n        fn get_name(&self) {}\n    }\n}",
50        pass: true,
51    },
52];
53
54crate::ast_rule!(
55    getter_prefix,
56    "Flag methods named `get_something` — Rust getters are named after the field (C-GETTER).",
57    "The `get_` prefix is noise: the std convention is `fn name(&self)`, with `get`/`get_mut` reserved for keyed or checked access.",
58    Low,
59);
60
61const ALLOWED: &[&str] = &[
62    "get",
63    "get_mut",
64    "get_unchecked",
65    "get_unchecked_mut",
66    "get_or_insert_with",
67    "get_or_init",
68];
69
70fn check_getter_prefix(ctx: &AstCtx<'_>) -> Vec<Violation> {
71    ctx.nodes::<ast::Fn>()
72        .filter(|function| {
73            !ctx.is_in_test(function)
74                && function
75                    .param_list()
76                    .is_some_and(|params| params.self_param().is_some())
77        })
78        .filter_map(|function| {
79            let name = function.name()?;
80            let name_text = name.text();
81            let field = name_text.strip_prefix("get_")?;
82
83            (!field.is_empty() && !ALLOWED.contains(&name_text.as_str())).then(|| {
84                ctx.violation(
85                    &name,
86                    format!(
87                        "getter `{name_text}` — name it `{field}` after what it returns (C-GETTER)"
88                    ),
89                )
90            })
91        })
92        .collect()
93}
94
95crate::tidy_ast_test!(check_getter_prefix, {
96    crate::example_tests!(EXAMPLES, check_getter_prefix);
97});