garbage_code_hunter/rules/
advanced_rust.rs1use std::path::Path;
2use syn::{File, visit::Visit, ExprClosure, ItemTrait, ItemImpl, GenericParam, Lifetime};
3
4use crate::analyzer::{CodeIssue, Severity, RoastLevel};
5use crate::rules::Rule;
6
7pub struct ComplexClosureRule;
8
9impl Rule for ComplexClosureRule {
10 fn name(&self) -> &'static str {
11 "complex-closure"
12 }
13
14 fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
15 let mut visitor = ClosureVisitor::new(file_path.to_path_buf());
16 visitor.visit_file(syntax_tree);
17 visitor.issues
18 }
19}
20
21pub struct LifetimeAbuseRule;
22
23impl Rule for LifetimeAbuseRule {
24 fn name(&self) -> &'static str {
25 "lifetime-abuse"
26 }
27
28 fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
29 let mut visitor = LifetimeVisitor::new(file_path.to_path_buf());
30 visitor.visit_file(syntax_tree);
31 visitor.issues
32 }
33}
34
35pub struct TraitComplexityRule;
36
37impl Rule for TraitComplexityRule {
38 fn name(&self) -> &'static str {
39 "trait-complexity"
40 }
41
42 fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
43 let mut visitor = TraitVisitor::new(file_path.to_path_buf());
44 visitor.visit_file(syntax_tree);
45 visitor.issues
46 }
47}
48
49pub struct GenericAbuseRule;
50
51impl Rule for GenericAbuseRule {
52 fn name(&self) -> &'static str {
53 "generic-abuse"
54 }
55
56 fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
57 let mut visitor = GenericVisitor::new(file_path.to_path_buf());
58 visitor.visit_file(syntax_tree);
59 visitor.issues
60 }
61}
62
63struct ClosureVisitor {
64 file_path: std::path::PathBuf,
65 issues: Vec<CodeIssue>,
66 closure_depth: usize,
67}
68
69impl ClosureVisitor {
70 fn new(file_path: std::path::PathBuf) -> Self {
71 Self {
72 file_path,
73 issues: Vec::new(),
74 closure_depth: 0,
75 }
76 }
77
78 fn check_closure_complexity(&mut self, closure: &ExprClosure) {
79 if self.closure_depth > 2 {
81 let messages = vec![
82 "闭包套闭包?你这是在写俄罗斯套娃还是在考验读者的智商?",
83 "嵌套闭包比我的人际关系还复杂",
84 "这闭包嵌套得像洋葱一样,剥一层哭一次",
85 "闭包嵌套过深,建议拆分成独立函数",
86 ];
87
88 self.issues.push(CodeIssue {
89 file_path: self.file_path.clone(),
90 line: 1, column: 1,
92 rule_name: "complex-closure".to_string(),
93 message: messages[self.issues.len() % messages.len()].to_string(),
94 severity: Severity::Spicy,
95 roast_level: RoastLevel::Sarcastic,
96 });
97 }
98
99 if closure.inputs.len() > 5 {
101 let messages = vec![
102 "这个闭包的参数比我的借口还多",
103 "闭包参数过多,你确定不是在写函数?",
104 "这么多参数的闭包,建议改成正经函数",
105 ];
106
107 self.issues.push(CodeIssue {
108 file_path: self.file_path.clone(),
109 line: 1,
110 column: 1,
111 rule_name: "complex-closure".to_string(),
112 message: messages[self.issues.len() % messages.len()].to_string(),
113 severity: Severity::Mild,
114 roast_level: RoastLevel::Gentle,
115 });
116 }
117 }
118}
119
120impl<'ast> Visit<'ast> for ClosureVisitor {
121 fn visit_expr_closure(&mut self, closure: &'ast ExprClosure) {
122 self.closure_depth += 1;
123 self.check_closure_complexity(closure);
124 syn::visit::visit_expr_closure(self, closure);
125 self.closure_depth -= 1;
126 }
127}
128
129struct LifetimeVisitor {
130 file_path: std::path::PathBuf,
131 issues: Vec<CodeIssue>,
132 lifetime_count: usize,
133}
134
135impl LifetimeVisitor {
136 fn new(file_path: std::path::PathBuf) -> Self {
137 Self {
138 file_path,
139 issues: Vec::new(),
140 lifetime_count: 0,
141 }
142 }
143}
144
145impl<'ast> Visit<'ast> for LifetimeVisitor {
146 fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
147 self.lifetime_count += 1;
148
149 if self.lifetime_count > 5 {
151 let messages = vec![
152 "生命周期标注比我的生命还复杂",
153 "这么多生命周期,你是在写哲学论文吗?",
154 "生命周期滥用,建议重新设计数据结构",
155 "生命周期多到让人怀疑人生",
156 ];
157
158 self.issues.push(CodeIssue {
159 file_path: self.file_path.clone(),
160 line: 1,
161 column: 1,
162 rule_name: "lifetime-abuse".to_string(),
163 message: messages[self.issues.len() % messages.len()].to_string(),
164 severity: Severity::Spicy,
165 roast_level: RoastLevel::Sarcastic,
166 });
167 }
168
169 syn::visit::visit_lifetime(self, lifetime);
170 }
171}
172
173struct TraitVisitor {
174 file_path: std::path::PathBuf,
175 issues: Vec<CodeIssue>,
176}
177
178impl TraitVisitor {
179 fn new(file_path: std::path::PathBuf) -> Self {
180 Self {
181 file_path,
182 issues: Vec::new(),
183 }
184 }
185
186 fn check_trait_complexity(&mut self, trait_item: &ItemTrait) {
187 if trait_item.items.len() > 10 {
189 let messages = vec![
190 "这个 trait 的方法比我的借口还多",
191 "trait 方法过多,违反了单一职责原则",
192 "这个 trait 比瑞士军刀还要全能",
193 "trait 臃肿,建议拆分成多个小 trait",
194 ];
195
196 self.issues.push(CodeIssue {
197 file_path: self.file_path.clone(),
198 line: 1,
199 column: 1,
200 rule_name: "trait-complexity".to_string(),
201 message: messages[self.issues.len() % messages.len()].to_string(),
202 severity: Severity::Spicy,
203 roast_level: RoastLevel::Sarcastic,
204 });
205 }
206
207 if trait_item.generics.params.len() > 3 {
209 let messages = vec![
210 "泛型参数比我的密码还复杂",
211 "这么多泛型,你是在写数学公式吗?",
212 "泛型滥用,建议简化设计",
213 ];
214
215 self.issues.push(CodeIssue {
216 file_path: self.file_path.clone(),
217 line: 1,
218 column: 1,
219 rule_name: "trait-complexity".to_string(),
220 message: messages[self.issues.len() % messages.len()].to_string(),
221 severity: Severity::Mild,
222 roast_level: RoastLevel::Gentle,
223 });
224 }
225 }
226}
227
228impl<'ast> Visit<'ast> for TraitVisitor {
229 fn visit_item_trait(&mut self, trait_item: &'ast ItemTrait) {
230 self.check_trait_complexity(trait_item);
231 syn::visit::visit_item_trait(self, trait_item);
232 }
233}
234
235struct GenericVisitor {
236 file_path: std::path::PathBuf,
237 issues: Vec<CodeIssue>,
238}
239
240impl GenericVisitor {
241 fn new(file_path: std::path::PathBuf) -> Self {
242 Self {
243 file_path,
244 issues: Vec::new(),
245 }
246 }
247
248 fn check_generic_abuse(&mut self, generics: &syn::Generics) {
249 if generics.params.len() > 5 {
250 let messages = vec![
251 "泛型参数比我的购物清单还长",
252 "这么多泛型,编译器都要哭了",
253 "泛型滥用,建议重新设计架构",
254 "泛型多到让人怀疑这还是 Rust 吗",
255 ];
256
257 self.issues.push(CodeIssue {
258 file_path: self.file_path.clone(),
259 line: 1,
260 column: 1,
261 rule_name: "generic-abuse".to_string(),
262 message: messages[self.issues.len() % messages.len()].to_string(),
263 severity: Severity::Spicy,
264 roast_level: RoastLevel::Sarcastic,
265 });
266 }
267
268 for param in &generics.params {
270 if let GenericParam::Type(type_param) = param {
271 let name = type_param.ident.to_string();
272 if name.len() == 1 && !matches!(name.as_str(), "T" | "U" | "V" | "E" | "K") {
273 let messages = vec![
274 format!("泛型参数 '{}' 的命名创意约等于零", name),
275 format!("泛型 '{}' 的名字比我的耐心还短", name),
276 format!("用 '{}' 做泛型名?建议用更有意义的名字", name),
277 ];
278
279 self.issues.push(CodeIssue {
280 file_path: self.file_path.clone(),
281 line: 1,
282 column: 1,
283 rule_name: "generic-abuse".to_string(),
284 message: messages[self.issues.len() % messages.len()].clone(),
285 severity: Severity::Mild,
286 roast_level: RoastLevel::Gentle,
287 });
288 }
289 }
290 }
291 }
292}
293
294impl<'ast> Visit<'ast> for GenericVisitor {
295 fn visit_item_fn(&mut self, func: &'ast syn::ItemFn) {
296 self.check_generic_abuse(&func.sig.generics);
297 syn::visit::visit_item_fn(self, func);
298 }
299
300 fn visit_item_struct(&mut self, struct_item: &'ast syn::ItemStruct) {
301 self.check_generic_abuse(&struct_item.generics);
302 syn::visit::visit_item_struct(self, struct_item);
303 }
304
305 fn visit_item_enum(&mut self, enum_item: &'ast syn::ItemEnum) {
306 self.check_generic_abuse(&enum_item.generics);
307 syn::visit::visit_item_enum(self, enum_item);
308 }
309
310 fn visit_item_impl(&mut self, impl_item: &'ast ItemImpl) {
311 self.check_generic_abuse(&impl_item.generics);
312 syn::visit::visit_item_impl(self, impl_item);
313 }
314}