garbage_code_hunter/rules/
naming.rs

1use regex::Regex;
2use std::path::Path;
3use syn::{visit::Visit, File, Ident};
4
5use crate::analyzer::{CodeIssue, RoastLevel, Severity};
6use crate::rules::Rule;
7
8pub struct TerribleNamingRule;
9
10impl Rule for TerribleNamingRule {
11    fn name(&self) -> &'static str {
12        "terrible-naming"
13    }
14
15    fn check(
16        &self,
17        file_path: &Path,
18        syntax_tree: &File,
19        _content: &str,
20        lang: &str,
21    ) -> Vec<CodeIssue> {
22        let mut visitor = NamingVisitor::new(file_path.to_path_buf(), lang);
23        visitor.visit_file(syntax_tree);
24        visitor.issues
25    }
26}
27
28pub struct SingleLetterVariableRule;
29
30impl Rule for SingleLetterVariableRule {
31    fn name(&self) -> &'static str {
32        "single-letter-variable"
33    }
34
35    fn check(
36        &self,
37        file_path: &Path,
38        syntax_tree: &File,
39        _content: &str,
40        lang: &str,
41    ) -> Vec<CodeIssue> {
42        let mut visitor = SingleLetterVisitor::new(file_path.to_path_buf(), lang);
43        visitor.visit_file(syntax_tree);
44        visitor.issues
45    }
46}
47
48struct NamingVisitor {
49    file_path: std::path::PathBuf,
50    issues: Vec<CodeIssue>,
51    terrible_names: Regex,
52    lang: String,
53}
54
55impl NamingVisitor {
56    fn new(file_path: std::path::PathBuf, lang: &str) -> Self {
57        let terrible_names = Regex::new(r"^(data|info|temp|tmp|val|value|item|thing|stuff|obj|object|manager|handler|helper|util|utils|a|b|c|d|e|f|g|h|test|func|function)(\d+)?$").unwrap();
58
59        Self {
60            file_path,
61            issues: Vec::new(),
62            terrible_names,
63            lang: lang.to_string(),
64        }
65    }
66
67    fn check_name(&mut self, ident: &Ident, context: &str) {
68        let name = ident.to_string();
69
70        if self.terrible_names.is_match(&name.to_lowercase()) {
71            // 根据语言设置选择消息
72            let messages = if self.lang == "zh-CN" {
73                // 中文消息
74                let ctx = if context == "函数名" {
75                    "函数名"
76                } else {
77                    "变量名"
78                };
79                vec![
80                    format!("{} '{}' - 比我的编程技能还要抽象", ctx, name),
81                    format!(
82                        "{} '{}' - 这个名字告诉我你已经放弃治疗了,建议直接转行卖煎饼果子",
83                        ctx, name
84                    ),
85                    format!(
86                        "{} '{}' - 用这个做名字?你是想让维护代码的人哭着辞职吗?",
87                        ctx, name
88                    ),
89                    format!("{} '{}' - 恭喜你发明了最没有意义的标识符", ctx, name),
90                    format!("{} '{}' - 创意程度约等于给孩子起名叫'小明'", ctx, name),
91                    format!(
92                        "{} '{}' - 看到这个名字,我的智商都下降了,现在只能数到3了",
93                        ctx, name
94                    ),
95                ]
96            } else {
97                // 英文消息
98                let ctx = if context == "Function" {
99                    "Function"
100                } else {
101                    "Variable"
102                };
103                vec![
104                    format!("{} '{}' - more abstract than my programming skills", ctx, name),
105                    format!("{} '{}' - this name tells me you've given up on life and should sell hotdogs", ctx, name),
106                    format!("{} '{}' - using this name? trying to make maintainers cry and quit?", ctx, name),
107                    format!("{} '{}' - congrats on inventing the most meaningless identifier", ctx, name),
108                    format!("{} '{}' - creativity level of naming a kid 'Child'", ctx, name),
109                    format!("{} '{}' - seeing this name, my IQ dropped to single digits", ctx, name),
110                ]
111            };
112
113            let message_index =
114                (self.issues.len() + name.len() + name.chars().next().unwrap_or('a') as usize)
115                    % messages.len();
116
117            self.issues.push(CodeIssue {
118                file_path: self.file_path.clone(),
119                line: self.issues.len() + 2, // 简单的行号估算,避免都是1:1
120                column: (name.len() % 10) + 1, // 基于名字长度的列号
121                rule_name: "terrible-naming".to_string(),
122                message: messages[message_index].clone(),
123                severity: Severity::Spicy,
124                roast_level: RoastLevel::Sarcastic,
125            });
126        }
127    }
128}
129
130impl<'ast> Visit<'ast> for NamingVisitor {
131    fn visit_ident(&mut self, ident: &'ast Ident) {
132        let context = if self.lang == "zh-CN" {
133            "变量名"
134        } else {
135            "Variable"
136        };
137        self.check_name(ident, context);
138        syn::visit::visit_ident(self, ident);
139    }
140
141    // 添加函数名检测
142    fn visit_item_fn(&mut self, func: &'ast syn::ItemFn) {
143        let context = if self.lang == "zh-CN" {
144            "函数名"
145        } else {
146            "Function"
147        };
148        self.check_name(&func.sig.ident, context);
149        syn::visit::visit_item_fn(self, func);
150    }
151}
152
153#[allow(dead_code)]
154struct SingleLetterVisitor {
155    file_path: std::path::PathBuf,
156    issues: Vec<CodeIssue>,
157    lang: String,
158}
159
160impl SingleLetterVisitor {
161    fn new(file_path: std::path::PathBuf, lang: &str) -> Self {
162        Self {
163            file_path,
164            issues: Vec::new(),
165            lang: lang.to_string(),
166        }
167    }
168}
169
170impl<'ast> Visit<'ast> for SingleLetterVisitor {
171    fn visit_pat_ident(&mut self, pat_ident: &'ast syn::PatIdent) {
172        let name = pat_ident.ident.to_string();
173
174        // Exclude common single-letter variables (like loop counters i, j, k)
175        if name.len() == 1 && !matches!(name.as_str(), "i" | "j" | "k" | "x" | "y" | "z") {
176            let messages = [
177                format!("单字母变量 '{name}'?你是在写数学公式还是在折磨读代码的人?"),
178                format!("变量 '{name}'?这是变量名还是你键盘坏了?"),
179                format!("用 '{name}' 做变量名,你可能需要一本《如何给变量起名》的书"),
180                format!("单字母变量 '{name}':让代码比古埃及象形文字还难懂"),
181                format!("变量 '{name}' 的信息量约等于一个句号"),
182            ];
183
184            let message_index =
185                (self.issues.len() + name.len() + name.chars().next().unwrap_or('a') as usize)
186                    % messages.len();
187
188            self.issues.push(CodeIssue {
189                file_path: self.file_path.clone(),
190                line: self.issues.len() + 10, // 不同的行号范围
191                column: (name.len() % 5) + 1,
192                rule_name: "single-letter-variable".to_string(),
193                message: messages[message_index].clone(),
194                severity: Severity::Mild,
195                roast_level: RoastLevel::Gentle,
196            });
197        }
198
199        syn::visit::visit_pat_ident(self, pat_ident);
200    }
201}