garbage_code_hunter/rules/
comprehensive_rust.rs

1use std::path::Path;
2use syn::{File, visit::Visit, TypeReference, TypeSlice, 
3          TypePath, TypeTraitObject, ExprAsync, ExprAwait, ItemMod, 
4          Macro, PatSlice, PatTuple, ExprUnsafe, ExprMatch, 
5          ItemForeignMod, ForeignItem, ItemFn};
6
7use crate::analyzer::{CodeIssue, Severity, RoastLevel};
8use crate::rules::Rule;
9
10pub struct ChannelAbuseRule;
11pub struct AsyncAbuseRule;
12pub struct DynTraitAbuseRule;
13pub struct UnsafeAbuseRule;
14pub struct FFIAbuseRule;
15pub struct MacroAbuseRule;
16pub struct ModuleComplexityRule;
17pub struct PatternMatchingAbuseRule;
18pub struct ReferenceAbuseRule;
19pub struct BoxAbuseRule;
20pub struct SliceAbuseRule;
21
22impl Rule for ChannelAbuseRule {
23    fn name(&self) -> &'static str {
24        "channel-abuse"
25    }
26
27    fn check(&self, file_path: &Path, syntax_tree: &File, content: &str) -> Vec<CodeIssue> {
28        let mut visitor = ChannelVisitor::new(file_path.to_path_buf());
29        visitor.visit_file(syntax_tree);
30        
31        // Also check for channel-related imports and usage in content
32        if content.contains("std::sync::mpsc") || content.contains("tokio::sync") {
33            visitor.channel_count += content.matches("channel").count();
34            visitor.channel_count += content.matches("Sender").count();
35            visitor.channel_count += content.matches("Receiver").count();
36        }
37        
38        visitor.check_channel_overuse();
39        visitor.issues
40    }
41}
42
43impl Rule for AsyncAbuseRule {
44    fn name(&self) -> &'static str {
45        "async-abuse"
46    }
47
48    fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
49        let mut visitor = AsyncVisitor::new(file_path.to_path_buf());
50        visitor.visit_file(syntax_tree);
51        visitor.issues
52    }
53}
54
55impl Rule for DynTraitAbuseRule {
56    fn name(&self) -> &'static str {
57        "dyn-trait-abuse"
58    }
59
60    fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
61        let mut visitor = DynTraitVisitor::new(file_path.to_path_buf());
62        visitor.visit_file(syntax_tree);
63        visitor.issues
64    }
65}
66
67impl Rule for UnsafeAbuseRule {
68    fn name(&self) -> &'static str {
69        "unsafe-abuse"
70    }
71
72    fn check(&self, file_path: &Path, syntax_tree: &File, content: &str) -> Vec<CodeIssue> {
73        let mut visitor = UnsafeVisitor::new(file_path.to_path_buf());
74        visitor.visit_file(syntax_tree);
75        
76        // 检查内容中的 unsafe 关键字使用
77        visitor.check_unsafe_in_content(content);
78        visitor.issues
79    }
80}
81
82impl Rule for FFIAbuseRule {
83    fn name(&self) -> &'static str {
84        "ffi-abuse"
85    }
86
87    fn check(&self, file_path: &Path, syntax_tree: &File, content: &str) -> Vec<CodeIssue> {
88        let mut visitor = FFIVisitor::new(file_path.to_path_buf());
89        visitor.visit_file(syntax_tree);
90        
91        // 检查内容中的 FFI 相关模式
92        visitor.check_ffi_patterns_in_content(content);
93        visitor.issues
94    }
95}
96
97impl Rule for MacroAbuseRule {
98    fn name(&self) -> &'static str {
99        "macro-abuse"
100    }
101
102    fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
103        let mut visitor = MacroVisitor::new(file_path.to_path_buf());
104        visitor.visit_file(syntax_tree);
105        visitor.issues
106    }
107}
108
109impl Rule for ModuleComplexityRule {
110    fn name(&self) -> &'static str {
111        "module-complexity"
112    }
113
114    fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
115        let mut visitor = ModuleVisitor::new(file_path.to_path_buf());
116        visitor.visit_file(syntax_tree);
117        visitor.issues
118    }
119}
120
121impl Rule for PatternMatchingAbuseRule {
122    fn name(&self) -> &'static str {
123        "pattern-matching-abuse"
124    }
125
126    fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
127        let mut visitor = PatternVisitor::new(file_path.to_path_buf());
128        visitor.visit_file(syntax_tree);
129        visitor.issues
130    }
131}
132
133impl Rule for ReferenceAbuseRule {
134    fn name(&self) -> &'static str {
135        "reference-abuse"
136    }
137
138    fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
139        let mut visitor = ReferenceVisitor::new(file_path.to_path_buf());
140        visitor.visit_file(syntax_tree);
141        visitor.issues
142    }
143}
144
145impl Rule for BoxAbuseRule {
146    fn name(&self) -> &'static str {
147        "box-abuse"
148    }
149
150    fn check(&self, file_path: &Path, syntax_tree: &File, content: &str) -> Vec<CodeIssue> {
151        let mut visitor = BoxVisitor::new(file_path.to_path_buf());
152        visitor.visit_file(syntax_tree);
153        
154        // Check for Box usage in content since ExprBox doesn't exist in syn 2.0
155        let box_count = content.matches("Box::new").count() + content.matches("Box<").count();
156        if box_count > 8 {
157            let messages = vec![
158                "Box 用得比快递还频繁",
159                "这么多 Box,你是在开仓库吗?",
160                "Box 过多,堆内存都要爆炸了",
161                "Box 滥用,建议考虑栈分配",
162                "这么多 Box,内存分配器都累了",
163            ];
164
165            visitor.issues.push(CodeIssue {
166                file_path: file_path.to_path_buf(),
167                line: 1,
168                column: 1,
169                rule_name: "box-abuse".to_string(),
170                message: messages[0].to_string(),
171                severity: Severity::Spicy,
172                roast_level: RoastLevel::Sarcastic,
173            });
174        }
175        
176        visitor.issues
177    }
178}
179
180impl Rule for SliceAbuseRule {
181    fn name(&self) -> &'static str {
182        "slice-abuse"
183    }
184
185    fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
186        let mut visitor = SliceVisitor::new(file_path.to_path_buf());
187        visitor.visit_file(syntax_tree);
188        visitor.issues
189    }
190}
191
192// Channel Visitor
193struct ChannelVisitor {
194    file_path: std::path::PathBuf,
195    issues: Vec<CodeIssue>,
196    channel_count: usize,
197}
198
199impl ChannelVisitor {
200    fn new(file_path: std::path::PathBuf) -> Self {
201        Self {
202            file_path,
203            issues: Vec::new(),
204            channel_count: 0,
205        }
206    }
207
208    fn check_channel_overuse(&mut self) {
209        if self.channel_count > 5 {
210            let messages = vec![
211                "Channel 用得比我发微信还频繁,你确定不是在写聊天软件?",
212                "这么多 Channel,你是想开通讯公司吗?",
213                "Channel 滥用!你的程序比电话交换机还复杂",
214                "Channel 数量超标,建议重新设计架构",
215                "这么多 Channel,我怀疑你在写分布式系统",
216            ];
217
218            self.issues.push(CodeIssue {
219                file_path: self.file_path.clone(),
220                line: 1,
221                column: 1,
222                rule_name: "channel-abuse".to_string(),
223                message: messages[self.issues.len() % messages.len()].to_string(),
224                severity: Severity::Spicy,
225                roast_level: RoastLevel::Sarcastic,
226            });
227        }
228    }
229}
230
231impl<'ast> Visit<'ast> for ChannelVisitor {
232    fn visit_type_path(&mut self, type_path: &'ast TypePath) {
233        let path_str = quote::quote!(#type_path).to_string();
234        if path_str.contains("Sender") || path_str.contains("Receiver") || path_str.contains("channel") {
235            self.channel_count += 1;
236        }
237        syn::visit::visit_type_path(self, type_path);
238    }
239}
240
241// Async Visitor
242struct AsyncVisitor {
243    file_path: std::path::PathBuf,
244    issues: Vec<CodeIssue>,
245    async_count: usize,
246    await_count: usize,
247}
248
249impl AsyncVisitor {
250    fn new(file_path: std::path::PathBuf) -> Self {
251        Self {
252            file_path,
253            issues: Vec::new(),
254            async_count: 0,
255            await_count: 0,
256        }
257    }
258
259    fn check_async_abuse(&mut self) {
260        if self.async_count > 10 {
261            let messages = vec![
262                "Async 函数比我的异步人生还要复杂",
263                "这么多 async,你确定不是在写 JavaScript?",
264                "Async 滥用!建议学习一下同步编程的美好",
265                "异步函数过多,小心把自己绕晕了",
266            ];
267
268            self.issues.push(CodeIssue {
269                file_path: self.file_path.clone(),
270                line: 1,
271                column: 1,
272                rule_name: "async-abuse".to_string(),
273                message: messages[self.issues.len() % messages.len()].to_string(),
274                severity: Severity::Spicy,
275                roast_level: RoastLevel::Sarcastic,
276            });
277        }
278
279        if self.await_count > 20 {
280            let messages = vec![
281                "Await 用得比我等外卖还频繁",
282                "这么多 await,你的程序是在等什么?世界末日吗?",
283                "Await 过度使用,建议批量处理",
284                "等待次数过多,你的程序比我还有耐心",
285            ];
286
287            self.issues.push(CodeIssue {
288                file_path: self.file_path.clone(),
289                line: 1,
290                column: 1,
291                rule_name: "async-abuse".to_string(),
292                message: messages[self.issues.len() % messages.len()].to_string(),
293                severity: Severity::Mild,
294                roast_level: RoastLevel::Gentle,
295            });
296        }
297    }
298}
299
300impl<'ast> Visit<'ast> for AsyncVisitor {
301    fn visit_expr_async(&mut self, _async_expr: &'ast ExprAsync) {
302        self.async_count += 1;
303        self.check_async_abuse();
304        syn::visit::visit_expr_async(self, _async_expr);
305    }
306
307    fn visit_expr_await(&mut self, _await_expr: &'ast ExprAwait) {
308        self.await_count += 1;
309        self.check_async_abuse();
310        syn::visit::visit_expr_await(self, _await_expr);
311    }
312}
313
314// Dyn Trait Visitor
315struct DynTraitVisitor {
316    file_path: std::path::PathBuf,
317    issues: Vec<CodeIssue>,
318    dyn_count: usize,
319}
320
321impl DynTraitVisitor {
322    fn new(file_path: std::path::PathBuf) -> Self {
323        Self {
324            file_path,
325            issues: Vec::new(),
326            dyn_count: 0,
327        }
328    }
329}
330
331impl<'ast> Visit<'ast> for DynTraitVisitor {
332    fn visit_type_trait_object(&mut self, trait_object: &'ast TypeTraitObject) {
333        self.dyn_count += 1;
334        
335        if self.dyn_count > 5 {
336            let messages = vec![
337                "Dyn trait 用得比我换工作还频繁",
338                "这么多动态分发,性能都跑到哪里去了?",
339                "Dyn trait 滥用,你确定不是在写 Python?",
340                "动态 trait 过多,编译器优化都哭了",
341                "这么多 dyn,你的程序比变色龙还善变",
342            ];
343
344            self.issues.push(CodeIssue {
345                file_path: self.file_path.clone(),
346                line: 1,
347                column: 1,
348                rule_name: "dyn-trait-abuse".to_string(),
349                message: messages[self.issues.len() % messages.len()].to_string(),
350                severity: Severity::Spicy,
351                roast_level: RoastLevel::Sarcastic,
352            });
353        }
354        
355        syn::visit::visit_type_trait_object(self, trait_object);
356    }
357}
358
359// Unsafe Visitor
360struct UnsafeVisitor {
361    file_path: std::path::PathBuf,
362    issues: Vec<CodeIssue>,
363    unsafe_count: usize,
364    unsafe_fn_count: usize,
365    unsafe_impl_count: usize,
366    unsafe_trait_count: usize,
367}
368
369impl UnsafeVisitor {
370    fn new(file_path: std::path::PathBuf) -> Self {
371        Self {
372            file_path,
373            issues: Vec::new(),
374            unsafe_count: 0,
375            unsafe_fn_count: 0,
376            unsafe_impl_count: 0,
377            unsafe_trait_count: 0,
378        }
379    }
380    
381    fn check_unsafe_in_content(&mut self, content: &str) {
382        // 检查 unsafe 函数
383        let unsafe_fn_matches = content.matches("unsafe fn").count();
384        self.unsafe_fn_count += unsafe_fn_matches;
385        
386        // 检查 unsafe impl
387        let unsafe_impl_matches = content.matches("unsafe impl").count();
388        self.unsafe_impl_count += unsafe_impl_matches;
389        
390        // 检查 unsafe trait
391        let unsafe_trait_matches = content.matches("unsafe trait").count();
392        self.unsafe_trait_count += unsafe_trait_matches;
393        
394        // 检查原始指针操作
395        let raw_ptr_count = content.matches("*const").count() + content.matches("*mut").count();
396        
397        // 检查内存操作函数
398        let dangerous_ops = [
399            "std::ptr::write", "std::ptr::read", "std::ptr::copy",
400            "std::mem::transmute", "std::mem::forget", "std::mem::uninitialized",
401            "std::slice::from_raw_parts", "std::str::from_utf8_unchecked",
402            "Box::from_raw", "Vec::from_raw_parts", "String::from_raw_parts"
403        ];
404        
405        let mut dangerous_op_count = 0;
406        for op in &dangerous_ops {
407            dangerous_op_count += content.matches(op).count();
408        }
409        
410        self.generate_unsafe_issues(raw_ptr_count, dangerous_op_count);
411    }
412    
413    fn generate_unsafe_issues(&mut self, raw_ptr_count: usize, dangerous_op_count: usize) {
414        // 检查 unsafe 函数过多
415        if self.unsafe_fn_count > 2 {
416            let messages = vec![
417                "Unsafe 函数比我的黑历史还多!你确定这还是 Rust 吗?",
418                "这么多 unsafe 函数,Rust 的安全保证都被你玩坏了",
419                "Unsafe 函数过多,建议重新考虑设计架构",
420                "你的 unsafe 函数让 Rust 编译器都开始怀疑人生了",
421            ];
422            
423            self.issues.push(CodeIssue {
424                file_path: self.file_path.clone(),
425                line: 1,
426                column: 1,
427                rule_name: "unsafe-abuse".to_string(),
428                message: messages[self.issues.len() % messages.len()].to_string(),
429                severity: Severity::Nuclear,
430                roast_level: RoastLevel::Savage,
431            });
432        }
433        
434        // 检查原始指针过多
435        if raw_ptr_count > 5 {
436            let messages = vec![
437                "原始指针用得比我换手机还频繁,你这是在写 C 语言吗?",
438                "这么多原始指针,内存安全已经不在服务区了",
439                "原始指针过多,建议使用安全的 Rust 抽象",
440                "你的指针操作让 Valgrind 都要加班了",
441            ];
442            
443            self.issues.push(CodeIssue {
444                file_path: self.file_path.clone(),
445                line: 1,
446                column: 1,
447                rule_name: "unsafe-abuse".to_string(),
448                message: messages[self.issues.len() % messages.len()].to_string(),
449                severity: Severity::Nuclear,
450                roast_level: RoastLevel::Savage,
451            });
452        }
453        
454        // 检查危险操作过多
455        if dangerous_op_count > 3 {
456            let messages = vec![
457                "危险的内存操作比我的危险驾驶还要多!",
458                "这些危险操作让我想起了 C++ 的恐怖回忆",
459                "内存操作过于危险,建议使用安全替代方案",
460                "你的代码比走钢丝还危险,小心内存泄漏!",
461            ];
462            
463            self.issues.push(CodeIssue {
464                file_path: self.file_path.clone(),
465                line: 1,
466                column: 1,
467                rule_name: "unsafe-abuse".to_string(),
468                message: messages[self.issues.len() % messages.len()].to_string(),
469                severity: Severity::Nuclear,
470                roast_level: RoastLevel::Savage,
471            });
472        }
473    }
474}
475
476impl<'ast> Visit<'ast> for UnsafeVisitor {
477    fn visit_expr_unsafe(&mut self, _unsafe_expr: &'ast ExprUnsafe) {
478        self.unsafe_count += 1;
479        
480        let messages = vec![
481            "Unsafe 代码!你这是在玩火还是在挑战 Rust 的底线?",
482            "又见 unsafe!安全性是什么?能吃吗?",
483            "Unsafe 使用者,恭喜你获得了'内存安全破坏者'称号",
484            "这个 unsafe 让我想起了 C 语言的恐怖回忆",
485            "Unsafe 代码:让 Rust 程序员夜不能寐的存在",
486        ];
487
488        let severity = if self.unsafe_count > 3 {
489            Severity::Nuclear
490        } else {
491            Severity::Spicy
492        };
493
494        self.issues.push(CodeIssue {
495            file_path: self.file_path.clone(),
496            line: 1,
497            column: 1,
498            rule_name: "unsafe-abuse".to_string(),
499            message: messages[self.issues.len() % messages.len()].to_string(),
500            severity,
501            roast_level: RoastLevel::Savage,
502        });
503        
504        syn::visit::visit_expr_unsafe(self, _unsafe_expr);
505    }
506    
507    fn visit_item_fn(&mut self, item_fn: &'ast ItemFn) {
508        if item_fn.sig.unsafety.is_some() {
509            self.unsafe_fn_count += 1;
510        }
511        syn::visit::visit_item_fn(self, item_fn);
512    }
513}
514
515// FFI Visitor
516struct FFIVisitor {
517    file_path: std::path::PathBuf,
518    issues: Vec<CodeIssue>,
519    extern_block_count: usize,
520    extern_fn_count: usize,
521    c_repr_count: usize,
522}
523
524impl FFIVisitor {
525    fn new(file_path: std::path::PathBuf) -> Self {
526        Self {
527            file_path,
528            issues: Vec::new(),
529            extern_block_count: 0,
530            extern_fn_count: 0,
531            c_repr_count: 0,
532        }
533    }
534    
535    fn check_ffi_patterns_in_content(&mut self, content: &str) {
536        // 检查 C 表示法
537        self.c_repr_count += content.matches("#[repr(C)]").count();
538        
539        // 检查 C 字符串操作
540        let c_string_ops = [
541            "CString", "CStr", "c_char", "c_void", "c_int", "c_long",
542            "std::ffi::", "libc::", "std::os::raw::"
543        ];
544        
545        let mut c_ops_count = 0;
546        for op in &c_string_ops {
547            c_ops_count += content.matches(op).count();
548        }
549        
550        // 检查动态库加载
551        let dll_ops = ["libloading", "dlopen", "LoadLibrary", "GetProcAddress"];
552        let mut dll_count = 0;
553        for op in &dll_ops {
554            dll_count += content.matches(op).count();
555        }
556        
557        self.generate_ffi_issues(c_ops_count, dll_count);
558    }
559    
560    fn generate_ffi_issues(&mut self, c_ops_count: usize, dll_count: usize) {
561        // 检查 extern 块过多
562        if self.extern_block_count > 2 {
563            let messages = vec![
564                "Extern 块比我的前任还多,你这是要和多少种语言交互?",
565                "这么多 extern 块,你确定不是在写多语言翻译器?",
566                "FFI 接口过多,建议封装成统一的抽象层",
567                "外部接口比我的社交关系还复杂!",
568            ];
569            
570            self.issues.push(CodeIssue {
571                file_path: self.file_path.clone(),
572                line: 1,
573                column: 1,
574                rule_name: "ffi-abuse".to_string(),
575                message: messages[self.issues.len() % messages.len()].to_string(),
576                severity: Severity::Spicy,
577                roast_level: RoastLevel::Sarcastic,
578            });
579        }
580        
581        // 检查 C 操作过多
582        if c_ops_count > 10 {
583            let messages = vec![
584                "C 语言操作比我的 C 语言作业还多,你确定这是 Rust 项目?",
585                "这么多 C FFI,Rust 的安全性都要哭了",
586                "C 接口过多,建议使用更安全的 Rust 绑定",
587                "你的 FFI 代码让我想起了指针地狱的恐怖",
588            ];
589            
590            self.issues.push(CodeIssue {
591                file_path: self.file_path.clone(),
592                line: 1,
593                column: 1,
594                rule_name: "ffi-abuse".to_string(),
595                message: messages[self.issues.len() % messages.len()].to_string(),
596                severity: Severity::Nuclear,
597                roast_level: RoastLevel::Savage,
598            });
599        }
600        
601        // 检查动态库加载
602        if dll_count > 0 {
603            let messages = vec![
604                "动态库加载!你这是在运行时玩杂技吗?",
605                "动态加载库,小心加载到病毒!",
606                "运行时库加载,调试的时候准备哭吧",
607                "动态库操作,你的程序比变形金刚还会变身",
608            ];
609            
610            self.issues.push(CodeIssue {
611                file_path: self.file_path.clone(),
612                line: 1,
613                column: 1,
614                rule_name: "ffi-abuse".to_string(),
615                message: messages[self.issues.len() % messages.len()].to_string(),
616                severity: Severity::Spicy,
617                roast_level: RoastLevel::Sarcastic,
618            });
619        }
620        
621        // 检查 repr(C) 过多
622        if self.c_repr_count > 5 {
623            let messages = vec![
624                "repr(C) 用得比我说 C 语言还频繁!",
625                "这么多 C 表示法,你的结构体都要移民到 C 语言了",
626                "C 表示法过多,内存布局都要乱套了",
627                "repr(C) 滥用,Rust 的零成本抽象在哭泣",
628            ];
629            
630            self.issues.push(CodeIssue {
631                file_path: self.file_path.clone(),
632                line: 1,
633                column: 1,
634                rule_name: "ffi-abuse".to_string(),
635                message: messages[self.issues.len() % messages.len()].to_string(),
636                severity: Severity::Spicy,
637                roast_level: RoastLevel::Sarcastic,
638            });
639        }
640    }
641}
642
643impl<'ast> Visit<'ast> for FFIVisitor {
644    fn visit_item_foreign_mod(&mut self, foreign_mod: &'ast ItemForeignMod) {
645        self.extern_block_count += 1;
646        
647        // 统计外部函数数量
648        for item in &foreign_mod.items {
649            if matches!(item, ForeignItem::Fn(_)) {
650                self.extern_fn_count += 1;
651            }
652        }
653        
654        // 检查 extern 函数过多
655        if self.extern_fn_count > 10 {
656            let messages = vec![
657                "外部函数比我的外卖订单还多!",
658                "这么多 extern 函数,你是在开联合国大会吗?",
659                "外部接口过多,建议分模块管理",
660                "FFI 函数数量超标,小心接口管理混乱",
661            ];
662            
663            self.issues.push(CodeIssue {
664                file_path: self.file_path.clone(),
665                line: 1,
666                column: 1,
667                rule_name: "ffi-abuse".to_string(),
668                message: messages[self.issues.len() % messages.len()].to_string(),
669                severity: Severity::Spicy,
670                roast_level: RoastLevel::Sarcastic,
671            });
672        }
673        
674        syn::visit::visit_item_foreign_mod(self, foreign_mod);
675    }
676    
677    fn visit_item_fn(&mut self, item_fn: &'ast ItemFn) {
678        // 检查是否是 extern "C" 函数
679        if let Some(abi) = &item_fn.sig.abi {
680            if let Some(abi_name) = &abi.name {
681                if abi_name.value() == "C" {
682                    self.extern_fn_count += 1;
683                }
684            }
685        }
686        syn::visit::visit_item_fn(self, item_fn);
687    }
688}
689
690// Macro Visitor
691struct MacroVisitor {
692    file_path: std::path::PathBuf,
693    issues: Vec<CodeIssue>,
694    macro_count: usize,
695}
696
697impl MacroVisitor {
698    fn new(file_path: std::path::PathBuf) -> Self {
699        Self {
700            file_path,
701            issues: Vec::new(),
702            macro_count: 0,
703        }
704    }
705}
706
707impl<'ast> Visit<'ast> for MacroVisitor {
708    fn visit_macro(&mut self, _macro: &'ast Macro) {
709        self.macro_count += 1;
710        
711        if self.macro_count > 10 {
712            let messages = vec![
713                "宏定义比我的借口还多",
714                "这么多宏,你确定不是在写 C 语言?",
715                "宏滥用!编译时间都被你搞长了",
716                "宏过多,调试的时候准备哭吧",
717                "这么多宏,IDE 都要罢工了",
718            ];
719
720            self.issues.push(CodeIssue {
721                file_path: self.file_path.clone(),
722                line: 1,
723                column: 1,
724                rule_name: "macro-abuse".to_string(),
725                message: messages[self.issues.len() % messages.len()].to_string(),
726                severity: Severity::Mild,
727                roast_level: RoastLevel::Gentle,
728            });
729        }
730        
731        syn::visit::visit_macro(self, _macro);
732    }
733}
734
735// Module Visitor
736struct ModuleVisitor {
737    file_path: std::path::PathBuf,
738    issues: Vec<CodeIssue>,
739    module_depth: usize,
740    max_depth: usize,
741}
742
743impl ModuleVisitor {
744    fn new(file_path: std::path::PathBuf) -> Self {
745        Self {
746            file_path,
747            issues: Vec::new(),
748            module_depth: 0,
749            max_depth: 0,
750        }
751    }
752}
753
754impl<'ast> Visit<'ast> for ModuleVisitor {
755    fn visit_item_mod(&mut self, _module: &'ast ItemMod) {
756        self.module_depth += 1;
757        self.max_depth = self.max_depth.max(self.module_depth);
758        
759        if self.module_depth > 5 {
760            let messages = vec![
761                "模块嵌套比俄罗斯套娃还深",
762                "这模块结构比我的家族关系还复杂",
763                "模块嵌套过深,建议重新组织代码结构",
764                "这么深的模块,找个函数比找宝藏还难",
765            ];
766
767            self.issues.push(CodeIssue {
768                file_path: self.file_path.clone(),
769                line: 1,
770                column: 1,
771                rule_name: "module-complexity".to_string(),
772                message: messages[self.issues.len() % messages.len()].to_string(),
773                severity: Severity::Spicy,
774                roast_level: RoastLevel::Sarcastic,
775            });
776        }
777        
778        syn::visit::visit_item_mod(self, _module);
779        self.module_depth -= 1;
780    }
781}
782
783// Pattern Visitor
784struct PatternVisitor {
785    file_path: std::path::PathBuf,
786    issues: Vec<CodeIssue>,
787    complex_pattern_count: usize,
788}
789
790impl PatternVisitor {
791    fn new(file_path: std::path::PathBuf) -> Self {
792        Self {
793            file_path,
794            issues: Vec::new(),
795            complex_pattern_count: 0,
796        }
797    }
798
799    fn check_pattern_complexity(&mut self, pattern_type: &str) {
800        self.complex_pattern_count += 1;
801        
802        if self.complex_pattern_count > 15 {
803            let messages = vec![
804                format!("{}模式匹配比我的感情生活还复杂", pattern_type),
805                format!("这么多{}模式,你是在写解谜游戏吗?", pattern_type),
806                format!("{}模式过多,建议简化逻辑", pattern_type),
807                format!("复杂的{}模式让代码可读性直线下降", pattern_type),
808            ];
809
810            self.issues.push(CodeIssue {
811                file_path: self.file_path.clone(),
812                line: 1,
813                column: 1,
814                rule_name: "pattern-matching-abuse".to_string(),
815                message: messages[self.issues.len() % messages.len()].to_string(),
816                severity: Severity::Mild,
817                roast_level: RoastLevel::Gentle,
818            });
819        }
820    }
821}
822
823impl<'ast> Visit<'ast> for PatternVisitor {
824    fn visit_pat_tuple(&mut self, _tuple_pat: &'ast PatTuple) {
825        self.check_pattern_complexity("元组");
826        syn::visit::visit_pat_tuple(self, _tuple_pat);
827    }
828
829    fn visit_pat_slice(&mut self, _slice_pat: &'ast PatSlice) {
830        self.check_pattern_complexity("切片");
831        syn::visit::visit_pat_slice(self, _slice_pat);
832    }
833
834    fn visit_expr_match(&mut self, match_expr: &'ast ExprMatch) {
835        if match_expr.arms.len() > 10 {
836            let messages = vec![
837                "Match 分支比我的人生选择还多",
838                "这么多 match 分支,你确定不是在写状态机?",
839                "Match 分支过多,建议重构",
840                "这个 match 比电视遥控器的按钮还多",
841            ];
842
843            self.issues.push(CodeIssue {
844                file_path: self.file_path.clone(),
845                line: 1,
846                column: 1,
847                rule_name: "pattern-matching-abuse".to_string(),
848                message: messages[self.issues.len() % messages.len()].to_string(),
849                severity: Severity::Spicy,
850                roast_level: RoastLevel::Sarcastic,
851            });
852        }
853        syn::visit::visit_expr_match(self, match_expr);
854    }
855}
856
857// Reference Visitor
858struct ReferenceVisitor {
859    file_path: std::path::PathBuf,
860    issues: Vec<CodeIssue>,
861    reference_count: usize,
862}
863
864impl ReferenceVisitor {
865    fn new(file_path: std::path::PathBuf) -> Self {
866        Self {
867            file_path,
868            issues: Vec::new(),
869            reference_count: 0,
870        }
871    }
872}
873
874impl<'ast> Visit<'ast> for ReferenceVisitor {
875    fn visit_type_reference(&mut self, _ref_type: &'ast TypeReference) {
876        self.reference_count += 1;
877        
878        if self.reference_count > 20 {
879            let messages = vec![
880                "引用比我的社交关系还复杂",
881                "这么多引用,你确定不是在写指针迷宫?",
882                "引用过多,小心借用检查器罢工",
883                "引用数量超标,建议重新设计数据结构",
884            ];
885
886            self.issues.push(CodeIssue {
887                file_path: self.file_path.clone(),
888                line: 1,
889                column: 1,
890                rule_name: "reference-abuse".to_string(),
891                message: messages[self.issues.len() % messages.len()].to_string(),
892                severity: Severity::Mild,
893                roast_level: RoastLevel::Gentle,
894            });
895        }
896        
897        syn::visit::visit_type_reference(self, _ref_type);
898    }
899}
900
901// Box Visitor
902struct BoxVisitor {
903    #[allow(dead_code)]
904    file_path: std::path::PathBuf,
905    issues: Vec<CodeIssue>,
906}
907
908impl BoxVisitor {
909    fn new(file_path: std::path::PathBuf) -> Self {
910        Self {
911            file_path,
912            issues: Vec::new(),
913        }
914    }
915}
916
917impl<'ast> Visit<'ast> for BoxVisitor {
918    // Box detection is handled in the rule implementation via content analysis
919}
920
921// Slice Visitor
922struct SliceVisitor {
923    file_path: std::path::PathBuf,
924    issues: Vec<CodeIssue>,
925    slice_count: usize,
926}
927
928impl SliceVisitor {
929    fn new(file_path: std::path::PathBuf) -> Self {
930        Self {
931            file_path,
932            issues: Vec::new(),
933            slice_count: 0,
934        }
935    }
936}
937
938impl<'ast> Visit<'ast> for SliceVisitor {
939    fn visit_type_slice(&mut self, _slice_type: &'ast TypeSlice) {
940        self.slice_count += 1;
941        
942        if self.slice_count > 15 {
943            let messages = vec![
944                "切片比我切菜还频繁",
945                "这么多切片,你是在开水果店吗?",
946                "切片过多,数组都被你切碎了",
947                "Slice 滥用,建议使用 Vec",
948            ];
949
950            self.issues.push(CodeIssue {
951                file_path: self.file_path.clone(),
952                line: 1,
953                column: 1,
954                rule_name: "slice-abuse".to_string(),
955                message: messages[self.issues.len() % messages.len()].to_string(),
956                severity: Severity::Mild,
957                roast_level: RoastLevel::Gentle,
958            });
959        }
960        
961        syn::visit::visit_type_slice(self, _slice_type);
962    }
963}