wowlab_tidy/languages/rust/rules/style/
getter_prefix.rs1use 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});