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