garbage-code-hunter 0.2.0

A humorous Rust code quality detector that roasts your garbage code
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
use std::path::Path;
use syn::{
    visit::Visit, ExprAsync, ExprAwait, ExprMatch, ExprUnsafe, File, ForeignItem, ItemFn,
    ItemForeignMod, ItemMod, Macro, PatSlice, PatTuple, TypePath, TypeTraitObject,
};

use crate::analyzer::{CodeIssue, Severity};
use crate::rules::Rule;
use crate::utils::{count_non_import_matches, find_line_of_str, get_position};

pub struct ChannelAbuseRule;
pub struct AsyncAbuseRule;
pub struct DynTraitAbuseRule;
pub struct UnsafeAbuseRule;
pub struct FFIAbuseRule;
pub struct MacroAbuseRule;
pub struct ModuleComplexityRule;
pub struct PatternMatchingAbuseRule;

impl Rule for ChannelAbuseRule {
    fn name(&self) -> &'static str {
        "channel-abuse"
    }

    fn check(
        &self,
        file_path: &Path,
        syntax_tree: &File,
        content: &str,
        lang: &str,
        is_test_file: bool,
    ) -> Vec<CodeIssue> {
        if is_test_file {
            return Vec::new();
        }
        let mut visitor = ChannelVisitor::new(file_path.to_path_buf(), lang);
        visitor.visit_file(syntax_tree);

        // Also check for channel-related usage in content (excluding imports)
        if content.contains("std::sync::mpsc") || content.contains("tokio::sync") {
            visitor.channel_count += count_non_import_matches(content, "channel");
            visitor.channel_count += count_non_import_matches(content, "Sender");
            visitor.channel_count += count_non_import_matches(content, "Receiver");
        }

        visitor.check_channel_overuse(content);
        visitor.issues
    }
}

impl Rule for AsyncAbuseRule {
    fn name(&self) -> &'static str {
        "async-abuse"
    }

    fn check(
        &self,
        file_path: &Path,
        syntax_tree: &File,
        _content: &str,
        lang: &str,
        is_test_file: bool,
    ) -> Vec<CodeIssue> {
        if is_test_file {
            return Vec::new();
        }
        let mut visitor = AsyncVisitor::new(file_path.to_path_buf(), lang);
        visitor.visit_file(syntax_tree);
        visitor.issues
    }
}

impl Rule for DynTraitAbuseRule {
    fn name(&self) -> &'static str {
        "dyn-trait-abuse"
    }

    fn check(
        &self,
        file_path: &Path,
        syntax_tree: &File,
        _content: &str,
        lang: &str,
        is_test_file: bool,
    ) -> Vec<CodeIssue> {
        if is_test_file {
            return Vec::new();
        }
        let mut visitor = DynTraitVisitor::new(file_path.to_path_buf(), lang);
        visitor.visit_file(syntax_tree);
        visitor.issues
    }
}

impl Rule for UnsafeAbuseRule {
    fn name(&self) -> &'static str {
        "unsafe-abuse"
    }

    fn check(
        &self,
        file_path: &Path,
        syntax_tree: &File,
        content: &str,
        lang: &str,
        is_test_file: bool,
    ) -> Vec<CodeIssue> {
        if is_test_file {
            return Vec::new();
        }
        let mut visitor = UnsafeVisitor::new(file_path.to_path_buf(), lang);
        visitor.visit_file(syntax_tree);

        // Check unsafe keyword usage in content
        visitor.check_unsafe_in_content(content);
        visitor.issues
    }
}

impl Rule for FFIAbuseRule {
    fn name(&self) -> &'static str {
        "ffi-abuse"
    }

    fn check(
        &self,
        file_path: &Path,
        syntax_tree: &File,
        content: &str,
        lang: &str,
        is_test_file: bool,
    ) -> Vec<CodeIssue> {
        if is_test_file {
            return Vec::new();
        }
        let mut visitor = FFIVisitor::new(file_path.to_path_buf(), lang);
        visitor.visit_file(syntax_tree);

        // Check FFI-related patterns in content
        visitor.check_ffi_patterns_in_content(content);
        visitor.issues
    }
}

impl Rule for MacroAbuseRule {
    fn name(&self) -> &'static str {
        "macro-abuse"
    }

    fn check(
        &self,
        file_path: &Path,
        syntax_tree: &File,
        _content: &str,
        lang: &str,
        is_test_file: bool,
    ) -> Vec<CodeIssue> {
        if is_test_file {
            return Vec::new();
        }

        let mut visitor = MacroVisitor::new(file_path.to_path_buf(), lang);
        visitor.visit_file(syntax_tree);
        visitor.issues
    }
}

impl Rule for ModuleComplexityRule {
    fn name(&self) -> &'static str {
        "module-complexity"
    }

    fn check(
        &self,
        file_path: &Path,
        syntax_tree: &File,
        _content: &str,
        lang: &str,
        is_test_file: bool,
    ) -> Vec<CodeIssue> {
        if is_test_file {
            return Vec::new();
        }
        let mut visitor = ModuleVisitor::new(file_path.to_path_buf(), lang);
        visitor.visit_file(syntax_tree);
        visitor.issues
    }
}

impl Rule for PatternMatchingAbuseRule {
    fn name(&self) -> &'static str {
        "pattern-matching-abuse"
    }

    fn check(
        &self,
        file_path: &Path,
        syntax_tree: &File,
        _content: &str,
        lang: &str,
        is_test_file: bool,
    ) -> Vec<CodeIssue> {
        if is_test_file {
            return Vec::new();
        }

        // Skip i18n/internationalization files (they legitimately have many match branches)
        let file_name = file_path.file_name().and_then(|f| f.to_str()).unwrap_or("");
        if file_name.contains("i18n") || file_name.contains("locale") || file_name.contains("lang")
        {
            return Vec::new();
        }

        let mut visitor = PatternVisitor::new(file_path.to_path_buf(), lang);
        visitor.visit_file(syntax_tree);
        visitor.issues
    }
}

// Channel Visitor
struct ChannelVisitor {
    file_path: std::path::PathBuf,
    issues: Vec<CodeIssue>,
    channel_count: usize,
    lang: String,
    last_position: (usize, usize),
}

impl ChannelVisitor {
    fn new(file_path: std::path::PathBuf, lang: &str) -> Self {
        Self {
            file_path,
            issues: Vec::new(),
            channel_count: 0,
            lang: lang.to_string(),
            last_position: (1, 1),
        }
    }

    fn check_channel_overuse(&mut self, content: &str) {
        // Only report if we actually found channel TYPE usage (not just string literals)
        // and the count exceeds threshold
        if self.channel_count > 5 {
            let messages = if self.lang == "zh-CN" {
                [
                    "Channel 用得比我发微信还频繁,你确定不是在写聊天软件?",
                    "这么多 Channel,你是想开通讯公司吗?",
                    "Channel 滥用!你的程序比电话交换机还复杂",
                    "Channel 数量超标,建议重新设计架构",
                    "这么多 Channel,我怀疑你在写分布式系统",
                ]
            } else {
                [
                    "You use channels more than I text - are you writing a chat app?",
                    "This many channels, planning to start a telecom company?",
                    "Channel abuse! Your program is more complex than a telephone switchboard",
                    "Channel count exceeds limits - consider redesigning the architecture",
                    "So many channels, I suspect you're building a distributed system",
                ]
            };

            let candidates = [
                find_line_of_str(content, "channel"),
                find_line_of_str(content, "Sender"),
                find_line_of_str(content, "Receiver"),
            ];
            let line = candidates
                .iter()
                .copied()
                .filter(|&l| l > 1)
                .min()
                .unwrap_or(1);

            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column: 1,
                rule_name: "channel-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Spicy,
            });
        }
    }
}

impl<'ast> Visit<'ast> for ChannelVisitor {
    fn visit_type_path(&mut self, type_path: &'ast TypePath) {
        let path_str = quote::quote!(#type_path).to_string();
        if path_str.contains("Sender")
            || path_str.contains("Receiver")
            || path_str.contains("channel")
        {
            self.channel_count += 1;
            self.last_position = get_position(type_path);
        }
        syn::visit::visit_type_path(self, type_path);
    }
}

// Async Visitor
struct AsyncVisitor {
    file_path: std::path::PathBuf,
    issues: Vec<CodeIssue>,
    async_count: usize,
    await_count: usize,
    lang: String,
    last_position: (usize, usize),
}

impl AsyncVisitor {
    fn new(file_path: std::path::PathBuf, lang: &str) -> Self {
        Self {
            file_path,
            issues: Vec::new(),
            async_count: 0,
            await_count: 0,
            lang: lang.to_string(),
            last_position: (1, 1),
        }
    }

    fn check_async_abuse(&mut self) {
        if self.async_count > 10 {
            let messages = if self.lang == "zh-CN" {
                [
                    "Async 函数比我的异步人生还要复杂",
                    "这么多 async,你确定不是在写 JavaScript?",
                    "Async 滥用!建议学习一下同步编程的美好",
                    "异步函数过多,小心把自己绕晕了",
                ]
            } else {
                [
                    "Async functions are more complex than my async life",
                    "So much async - are you sure you're not writing JavaScript?",
                    "Async abuse! Consider the beauty of synchronous programming",
                    "Too many async functions - careful not to confuse yourself",
                ]
            };

            let (line, column) = self.last_position;
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column,
                rule_name: "async-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Spicy,
            });
        }

        if self.await_count > 20 {
            let messages = if self.lang == "zh-CN" {
                [
                    "Await 用得比我等外卖还频繁",
                    "这么多 await,你的程序是在等什么?世界末日吗?",
                    "Await 过度使用,建议批量处理",
                    "等待次数过多,你的程序比我还有耐心",
                ]
            } else {
                [
                    "You await more than I wait for food delivery",
                    "So many awaits - what is your program waiting for, the apocalypse?",
                    "Excessive await usage - consider batching operations",
                    "Your program is more patient than I'll ever be",
                ]
            };

            let (line, column) = self.last_position;
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column,
                rule_name: "async-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Mild,
            });
        }
    }
}

impl<'ast> Visit<'ast> for AsyncVisitor {
    fn visit_expr_async(&mut self, _async_expr: &'ast ExprAsync) {
        self.async_count += 1;
        self.last_position = get_position(_async_expr);
        self.check_async_abuse();
        syn::visit::visit_expr_async(self, _async_expr);
    }

    fn visit_expr_await(&mut self, _await_expr: &'ast ExprAwait) {
        self.await_count += 1;
        self.last_position = get_position(_await_expr);
        self.check_async_abuse();
        syn::visit::visit_expr_await(self, _await_expr);
    }
}

// Dyn Trait Visitor
struct DynTraitVisitor {
    file_path: std::path::PathBuf,
    issues: Vec<CodeIssue>,
    dyn_count: usize,
    lang: String,
}

impl DynTraitVisitor {
    fn new(file_path: std::path::PathBuf, lang: &str) -> Self {
        Self {
            file_path,
            issues: Vec::new(),
            dyn_count: 0,
            lang: lang.to_string(),
        }
    }
}

impl<'ast> Visit<'ast> for DynTraitVisitor {
    fn visit_type_trait_object(&mut self, trait_object: &'ast TypeTraitObject) {
        self.dyn_count += 1;

        if self.dyn_count > 5 {
            let messages = if self.lang == "zh-CN" {
                [
                    "Dyn trait 用得比我换工作还频繁",
                    "这么多动态分发,性能都跑到哪里去了?",
                    "Dyn trait 滥用,你确定不是在写 Python?",
                    "动态 trait 过多,编译器优化都哭了",
                    "这么多 dyn,你的程序比变色龙还善变",
                ]
            } else {
                [
                    "You use dyn traits more often than I change jobs",
                    "So much dynamic dispatch - where did all the performance go?",
                    "dyn trait abuse - are you sure you're not writing Python?",
                    "Too many dynamic traits - the compiler optimizer is crying",
                    "So many dyns, your program is more wishy-washy than a chameleon",
                ]
            };

            let (line, column) = get_position(trait_object);
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column,
                rule_name: "dyn-trait-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Spicy,
            });
        }

        syn::visit::visit_type_trait_object(self, trait_object);
    }
}

// Unsafe Visitor
struct UnsafeVisitor {
    file_path: std::path::PathBuf,
    issues: Vec<CodeIssue>,
    unsafe_count: usize,
    unsafe_fn_count: usize,
    unsafe_impl_count: usize,
    unsafe_trait_count: usize,
    lang: String,
}

impl UnsafeVisitor {
    fn new(file_path: std::path::PathBuf, lang: &str) -> Self {
        Self {
            file_path,
            issues: Vec::new(),
            unsafe_count: 0,
            unsafe_fn_count: 0,
            unsafe_impl_count: 0,
            unsafe_trait_count: 0,
            lang: lang.to_string(),
        }
    }

    fn check_unsafe_in_content(&mut self, content: &str) {
        // Check unsafe functions
        let unsafe_fn_matches = content.matches("unsafe fn").count();
        self.unsafe_fn_count += unsafe_fn_matches;

        // Check unsafe impl
        let unsafe_impl_matches = content.matches("unsafe impl").count();
        self.unsafe_impl_count += unsafe_impl_matches;

        // Check unsafe trait
        let unsafe_trait_matches = content.matches("unsafe trait").count();
        self.unsafe_trait_count += unsafe_trait_matches;

        // Check raw pointer operations
        let raw_ptr_count = content.matches("*const").count() + content.matches("*mut").count();

        // Check memory operation functions
        let dangerous_ops = [
            "std::ptr::write",
            "std::ptr::read",
            "std::ptr::copy",
            "std::mem::transmute",
            "std::mem::forget",
            "std::mem::uninitialized",
            "std::slice::from_raw_parts",
            "std::str::from_utf8_unchecked",
            "Box::from_raw",
            "Vec::from_raw_parts",
            "String::from_raw_parts",
        ];

        let mut dangerous_op_count = 0;
        for op in &dangerous_ops {
            dangerous_op_count += content.matches(op).count();
        }

        self.generate_unsafe_issues(content, raw_ptr_count, dangerous_op_count);
    }

    fn generate_unsafe_issues(
        &mut self,
        content: &str,
        raw_ptr_count: usize,
        dangerous_op_count: usize,
    ) {
        // Check for excessive unsafe functions
        if self.unsafe_fn_count > 2 {
            let messages = if self.lang == "zh-CN" {
                [
                    "Unsafe 函数比我的黑历史还多!你确定这还是 Rust 吗?",
                    "这么多 unsafe 函数,Rust 的安全保证都被你玩坏了",
                    "Unsafe 函数过多,建议重新考虑设计架构",
                    "你的 unsafe 函数让 Rust 编译器都开始怀疑人生了",
                ]
            } else {
                [
                    "More unsafe functions than my dark secrets! Are you sure this is still Rust?",
                    "So many unsafe functions - Rust's safety guarantees are in shambles",
                    "Too many unsafe functions - consider redesigning the architecture",
                    "Your unsafe functions are making the Rust compiler question its life choices",
                ]
            };

            let line = find_line_of_str(content, "unsafe fn");
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column: 1,
                rule_name: "unsafe-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Nuclear,
            });
        }

        // Check for excessive raw pointers
        if raw_ptr_count > 5 {
            let messages = if self.lang == "zh-CN" {
                [
                    "原始指针用得比我换手机还频繁,你这是在写 C 语言吗?",
                    "这么多原始指针,内存安全已经不在服务区了",
                    "原始指针过多,建议使用安全的 Rust 抽象",
                    "你的指针操作让 Valgrind 都要加班了",
                ]
            } else {
                [
                    "You use raw pointers more than I change phones - are you writing C?",
                    "So many raw pointers, memory safety has left the building",
                    "Too many raw pointers - consider using safe Rust abstractions",
                    "Your pointer operations are making Valgrind work overtime",
                ]
            };

            let line = find_line_of_str(content, "*const");
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column: 1,
                rule_name: "unsafe-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Nuclear,
            });
        }

        // Check for excessive dangerous operations
        if dangerous_op_count > 3 {
            let messages = if self.lang == "zh-CN" {
                [
                    "危险的内存操作比我的危险驾驶还要多!",
                    "这些危险操作让我想起了 C++ 的恐怖回忆",
                    "内存操作过于危险,建议使用安全替代方案",
                    "你的代码比走钢丝还危险,小心内存泄漏!",
                ]
            } else {
                [
                    "More dangerous memory ops than my reckless driving!",
                    "These dangerous ops bring back terrifying C++ memories",
                    "Memory operations are too dangerous - use safe alternatives",
                    "Your code is more dangerous than tightrope walking - watch for memory leaks!",
                ]
            };

            let line = find_line_of_str(content, "std::ptr::write")
                .max(find_line_of_str(content, "std::mem::transmute"))
                .max(find_line_of_str(content, "from_raw"));
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column: 1,
                rule_name: "unsafe-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Nuclear,
            });
        }
    }
}

impl<'ast> Visit<'ast> for UnsafeVisitor {
    fn visit_expr_unsafe(&mut self, _unsafe_expr: &'ast ExprUnsafe) {
        self.unsafe_count += 1;

        let messages = if self.lang == "zh-CN" {
            [
                "Unsafe 代码!你这是在玩火还是在挑战 Rust 的底线?",
                "又见 unsafe!安全性是什么?能吃吗?",
                "Unsafe 使用者,恭喜你获得了'内存安全破坏者'称号",
                "这个 unsafe 让我想起了 C 语言的恐怖回忆",
                "Unsafe 代码:让 Rust 程序员夜不能寐的存在",
            ]
        } else {
            [
                "Unsafe code! Playing with fire or challenging Rust's limits?",
                "Unsafe again! What is safety, can you eat it?",
                "Unsafe user - congratulations, you've earned the 'Memory Safety Destroyer' title",
                "This unsafe brings back terrifying memories of C programming",
                "Unsafe code: the thing that keeps Rust programmers up at night",
            ]
        };

        let severity = if self.unsafe_count > 3 {
            Severity::Nuclear
        } else {
            Severity::Spicy
        };

        let (line, column) = get_position(_unsafe_expr);
        self.issues.push(CodeIssue {
            file_path: self.file_path.clone(),
            line,
            column,
            rule_name: "unsafe-abuse".to_string(),
            message: messages[self.issues.len() % messages.len()].to_string(),
            severity,
        });

        syn::visit::visit_expr_unsafe(self, _unsafe_expr);
    }

    fn visit_item_fn(&mut self, item_fn: &'ast ItemFn) {
        if item_fn.sig.unsafety.is_some() {
            self.unsafe_fn_count += 1;
        }
        syn::visit::visit_item_fn(self, item_fn);
    }
}

// FFI Visitor
struct FFIVisitor {
    file_path: std::path::PathBuf,
    issues: Vec<CodeIssue>,
    extern_block_count: usize,
    extern_fn_count: usize,
    c_repr_count: usize,
    lang: String,
}

impl FFIVisitor {
    fn new(file_path: std::path::PathBuf, lang: &str) -> Self {
        Self {
            file_path,
            issues: Vec::new(),
            extern_block_count: 0,
            extern_fn_count: 0,
            c_repr_count: 0,
            lang: lang.to_string(),
        }
    }

    fn check_ffi_patterns_in_content(&mut self, content: &str) {
        // Check C representation
        self.c_repr_count += content.matches("#[repr(C)]").count();

        // Check C string operations
        let c_string_ops = [
            "CString",
            "CStr",
            "c_char",
            "c_void",
            "c_int",
            "c_long",
            "std::ffi::",
            "libc::",
            "std::os::raw::",
        ];

        let mut c_ops_count = 0;
        for op in &c_string_ops {
            c_ops_count += content.matches(op).count();
        }

        // Check dynamic library loading
        let dll_ops = ["libloading", "dlopen", "LoadLibrary", "GetProcAddress"];
        let mut dll_count = 0;
        for op in &dll_ops {
            dll_count += content.matches(op).count();
        }

        self.generate_ffi_issues(content, c_ops_count, dll_count);
    }

    fn generate_ffi_issues(&mut self, content: &str, c_ops_count: usize, dll_count: usize) {
        // Check for excessive extern blocks
        if self.extern_block_count > 2 {
            let messages = if self.lang == "zh-CN" {
                [
                    "Extern 块比我的前任还多,你这是要和多少种语言交互?",
                    "这么多 extern 块,你确定不是在写多语言翻译器?",
                    "FFI 接口过多,建议封装成统一的抽象层",
                    "外部接口比我的社交关系还复杂!",
                ]
            } else {
                [
                    "More extern blocks than my exes - how many languages are you interfacing with?",
                    "So many extern blocks - are you building a multilingual translator?",
                    "Too many FFI interfaces - consider wrapping them in a unified abstraction layer",
                    "References are more complex than my social life!",
                ]
            };

            let line = find_line_of_str(content, "extern \"C\"");
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column: 1,
                rule_name: "ffi-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Spicy,
            });
        }

        // Check for excessive C operations
        if c_ops_count > 10 {
            let messages = if self.lang == "zh-CN" {
                [
                    "C 语言操作比我的 C 语言作业还多,你确定这是 Rust 项目?",
                    "这么多 C FFI,Rust 的安全性都要哭了",
                    "C 接口过多,建议使用更安全的 Rust 绑定",
                    "你的 FFI 代码让我想起了指针地狱的恐怖",
                ]
            } else {
                [
                    "More C operations than my C homework - are you sure this is a Rust project?",
                    "So much C FFI, Rust's safety guarantees are crying",
                    "Too many C interfaces - consider using safer Rust bindings",
                    "Your FFI code brings back the horrors of pointer hell",
                ]
            };

            let line =
                find_line_of_str(content, "CString").max(find_line_of_str(content, "std::ffi"));
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column: 1,
                rule_name: "ffi-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Nuclear,
            });
        }

        // Check dynamic library loading
        if dll_count > 0 {
            let messages = if self.lang == "zh-CN" {
                [
                    "动态库加载!你这是在运行时玩杂技吗?",
                    "动态加载库,小心加载到病毒!",
                    "运行时库加载,调试的时候准备哭吧",
                    "动态库操作,你的程序比变形金刚还会变身",
                ]
            } else {
                [
                    "Dynamic library loading! Are you performing acrobatics at runtime?",
                    "Dynamic loading - careful not to load a virus!",
                    "Runtime library loading - get ready to cry during debugging",
                    "Dynamic library ops - your program transforms more than a Transformer",
                ]
            };

            let line =
                find_line_of_str(content, "libloading").max(find_line_of_str(content, "dlopen"));
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column: 1,
                rule_name: "ffi-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Spicy,
            });
        }

        // Check for excessive repr(C)
        if self.c_repr_count > 5 {
            let messages = if self.lang == "zh-CN" {
                [
                    "repr(C) 用得比我说 C 语言还频繁!",
                    "这么多 C 表示法,你的结构体都要移民到 C 语言了",
                    "C 表示法过多,内存布局都要乱套了",
                    "repr(C) 滥用,Rust 的零成本抽象在哭泣",
                ]
            } else {
                [
                    "You use repr(C) more than I speak C!",
                    "So many C representations, your structs are emigrating to C",
                    "Too many C representations - memory layout is a mess",
                    "repr(C) abuse - Rust's zero-cost abstractions are weeping",
                ]
            };

            let line = find_line_of_str(content, "#[repr(C)]");
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column: 1,
                rule_name: "ffi-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Spicy,
            });
        }
    }
}

impl<'ast> Visit<'ast> for FFIVisitor {
    fn visit_item_foreign_mod(&mut self, foreign_mod: &'ast ItemForeignMod) {
        self.extern_block_count += 1;

        // Count external functions
        for item in &foreign_mod.items {
            if matches!(item, ForeignItem::Fn(_)) {
                self.extern_fn_count += 1;
            }
        }

        // Check for excessive extern functions
        if self.extern_fn_count > 10 {
            let messages = if self.lang == "zh-CN" {
                [
                    "外部函数比我的外卖订单还多!",
                    "这么多 extern 函数,你是在开联合国大会吗?",
                    "外部接口过多,建议分模块管理",
                    "FFI 函数数量超标,小心接口管理混乱",
                ]
            } else {
                [
                    "More extern functions than my food delivery orders!",
                    "So many extern functions - are you hosting a UN summit?",
                    "Too many external interfaces - consider modular management",
                    "FFI function count exceeds limits - watch out for interface chaos",
                ]
            };

            let (line, column) = get_position(foreign_mod);
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column,
                rule_name: "ffi-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Spicy,
            });
        }

        syn::visit::visit_item_foreign_mod(self, foreign_mod);
    }

    fn visit_item_fn(&mut self, item_fn: &'ast ItemFn) {
        // Check if it's an extern "C" function
        if let Some(abi) = &item_fn.sig.abi {
            if let Some(abi_name) = &abi.name {
                if abi_name.value() == "C" {
                    self.extern_fn_count += 1;
                }
            }
        }
        syn::visit::visit_item_fn(self, item_fn);
    }
}

// Macro Visitor
struct MacroVisitor {
    file_path: std::path::PathBuf,
    issues: Vec<CodeIssue>,
    macro_count: usize,
    lang: String,
}

impl MacroVisitor {
    fn new(file_path: std::path::PathBuf, lang: &str) -> Self {
        Self {
            file_path,
            issues: Vec::new(),
            macro_count: 0,
            lang: lang.to_string(),
        }
    }
}

impl<'ast> Visit<'ast> for MacroVisitor {
    fn visit_macro(&mut self, _macro: &'ast Macro) {
        self.macro_count += 1;

        // Only flag if there are many macros (threshold raised from 10 to 20)
        if self.macro_count > 20 && self.issues.is_empty() {
            let messages = if self.lang == "zh-CN" {
                [
                    "宏定义比我的借口还多",
                    "这么多宏,你确定不是在写 C 语言?",
                    "宏滥用!编译时间都被你搞长了",
                    "宏过多,调试的时候准备哭吧",
                    "这么多宏,IDE 都要罢工了",
                ]
            } else {
                [
                    "More macros than my excuses",
                    "So many macros - are you sure you're not writing C?",
                    "Macro abuse! You've inflated the compile times",
                    "Too many macros - get ready to cry during debugging",
                    "So many macros, your IDE is about to go on strike",
                ]
            };

            let (line, column) = get_position(_macro);
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column,
                rule_name: "macro-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Mild,
            });
        }

        syn::visit::visit_macro(self, _macro);
    }
}

// Module Visitor
struct ModuleVisitor {
    file_path: std::path::PathBuf,
    issues: Vec<CodeIssue>,
    module_depth: usize,
    max_depth: usize,
    lang: String,
}

impl ModuleVisitor {
    fn new(file_path: std::path::PathBuf, lang: &str) -> Self {
        Self {
            file_path,
            issues: Vec::new(),
            module_depth: 0,
            max_depth: 0,
            lang: lang.to_string(),
        }
    }
}

impl<'ast> Visit<'ast> for ModuleVisitor {
    fn visit_item_mod(&mut self, _module: &'ast ItemMod) {
        self.module_depth += 1;
        self.max_depth = self.max_depth.max(self.module_depth);

        if self.module_depth > 5 {
            let messages = if self.lang == "zh-CN" {
                [
                    "模块嵌套比俄罗斯套娃还深",
                    "这模块结构比我的家族关系还复杂",
                    "模块嵌套过深,建议重新组织代码结构",
                    "这么深的模块,找个函数比找宝藏还难",
                ]
            } else {
                [
                    "Module nesting is deeper than Russian dolls",
                    "This module structure is more complex than my family tree",
                    "Module nesting too deep - consider restructuring your code",
                    "Modules so deep, finding a function is harder than finding treasure",
                ]
            };

            let (line, column) = get_position(_module);
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column,
                rule_name: "module-complexity".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Spicy,
            });
        }

        syn::visit::visit_item_mod(self, _module);
        self.module_depth -= 1;
    }
}

// Pattern Visitor
struct PatternVisitor {
    file_path: std::path::PathBuf,
    issues: Vec<CodeIssue>,
    complex_pattern_count: usize,
    lang: String,
    last_position: (usize, usize),
}

impl PatternVisitor {
    fn new(file_path: std::path::PathBuf, lang: &str) -> Self {
        Self {
            file_path,
            issues: Vec::new(),
            complex_pattern_count: 0,
            lang: lang.to_string(),
            last_position: (1, 1),
        }
    }

    fn check_pattern_complexity(&mut self, pattern_type: &str) {
        self.complex_pattern_count += 1;

        if self.complex_pattern_count > 15 {
            let messages = if self.lang == "zh-CN" {
                [
                    format!("{pattern_type}模式匹配比我的感情生活还复杂"),
                    format!("这么多{pattern_type}模式,你是在写解谜游戏吗?"),
                    format!("{pattern_type}模式过多,建议简化逻辑"),
                    format!("复杂的{pattern_type}模式让代码可读性直线下降"),
                ]
            } else {
                let en_type = match pattern_type {
                    "元组" => "tuple",
                    "切片" => "slice",
                    _ => pattern_type,
                };
                [
                    format!("{en_type} pattern matching is more complex than my love life"),
                    format!("So many {en_type} patterns - are you writing a puzzle game?"),
                    format!("Too many {en_type} patterns - consider simplifying the logic"),
                    format!("Complex {en_type} patterns tanking your code readability"),
                ]
            };

            let (line, column) = self.last_position;
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column,
                rule_name: "pattern-matching-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Mild,
            });
        }
    }
}

impl<'ast> Visit<'ast> for PatternVisitor {
    fn visit_pat_tuple(&mut self, _tuple_pat: &'ast PatTuple) {
        self.last_position = get_position(_tuple_pat);
        self.check_pattern_complexity("元组");
        syn::visit::visit_pat_tuple(self, _tuple_pat);
    }

    fn visit_pat_slice(&mut self, _slice_pat: &'ast PatSlice) {
        self.last_position = get_position(_slice_pat);
        self.check_pattern_complexity("切片");
        syn::visit::visit_pat_slice(self, _slice_pat);
    }

    fn visit_expr_match(&mut self, match_expr: &'ast ExprMatch) {
        // Only flag if there are many match arms (threshold raised from 10 to 20)
        if match_expr.arms.len() > 20 {
            let messages = if self.lang == "zh-CN" {
                [
                    "Match 分支比我的人生选择还多",
                    "这么多 match 分支,你确定不是在写状态机?",
                    "Match 分支过多,建议重构",
                    "这个 match 比电视遥控器的按钮还多",
                ]
            } else {
                [
                    "More match arms than life choices I've made",
                    "So many match branches - are you building a state machine?",
                    "Too many match arms - consider refactoring",
                    "This match has more arms than a TV remote has buttons",
                ]
            };

            let (line, column) = get_position(match_expr);
            self.issues.push(CodeIssue {
                file_path: self.file_path.clone(),
                line,
                column,
                rule_name: "pattern-matching-abuse".to_string(),
                message: messages[self.issues.len() % messages.len()].to_string(),
                severity: Severity::Spicy,
            });
        }
        syn::visit::visit_expr_match(self, match_expr);
    }
}