garbage_code_hunter/rules/
rust_specific.rs

1use std::path::Path;
2use syn::{visit::Visit, ExprMethodCall, File};
3
4use crate::analyzer::{CodeIssue, RoastLevel, Severity};
5use crate::rules::Rule;
6
7pub struct UnwrapAbuseRule;
8
9impl Rule for UnwrapAbuseRule {
10    fn name(&self) -> &'static str {
11        "unwrap-abuse"
12    }
13
14    fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
15        let mut visitor = UnwrapVisitor::new(file_path.to_path_buf());
16        visitor.visit_file(syntax_tree);
17        visitor.issues
18    }
19}
20
21pub struct UnnecessaryCloneRule;
22
23impl Rule for UnnecessaryCloneRule {
24    fn name(&self) -> &'static str {
25        "unnecessary-clone"
26    }
27
28    fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
29        let mut visitor = CloneVisitor::new(file_path.to_path_buf());
30        visitor.visit_file(syntax_tree);
31        visitor.issues
32    }
33}
34
35struct UnwrapVisitor {
36    file_path: std::path::PathBuf,
37    issues: Vec<CodeIssue>,
38    unwrap_count: usize,
39}
40
41impl UnwrapVisitor {
42    fn new(file_path: std::path::PathBuf) -> Self {
43        Self {
44            file_path,
45            issues: Vec::new(),
46            unwrap_count: 0,
47        }
48    }
49}
50
51impl<'ast> Visit<'ast> for UnwrapVisitor {
52    fn visit_expr_method_call(&mut self, method_call: &'ast ExprMethodCall) {
53        if method_call.method.to_string() == "unwrap" {
54            self.unwrap_count += 1;
55
56            let messages = vec![
57                "又一个 unwrap()!你是想让程序在生产环境里爆炸吗?",
58                "unwrap() 大师!错误处理是什么?能吃吗?",
59                "看到这个 unwrap(),我仿佛听到了程序崩溃的声音",
60                "unwrap() 使用者,恭喜你获得了'程序炸弹制造专家'称号",
61                "这个 unwrap() 就像定时炸弹,不知道什么时候会爆",
62                "又见 unwrap()!建议使用 match 或 if let,除非你喜欢 panic",
63            ];
64
65            let severity = if self.unwrap_count > 5 {
66                Severity::Nuclear
67            } else if self.unwrap_count > 2 {
68                Severity::Spicy
69            } else {
70                Severity::Mild
71            };
72
73            let roast_level = if self.unwrap_count > 5 {
74                RoastLevel::Savage
75            } else {
76                RoastLevel::Sarcastic
77            };
78
79            self.issues.push(CodeIssue {
80                file_path: self.file_path.clone(),
81                line: 1, // 简化处理
82                column: 1,
83                rule_name: "unwrap-abuse".to_string(),
84                message: messages[self.issues.len() % messages.len()].to_string(),
85                severity,
86                roast_level,
87            });
88        }
89
90        syn::visit::visit_expr_method_call(self, method_call);
91    }
92}
93
94struct CloneVisitor {
95    file_path: std::path::PathBuf,
96    issues: Vec<CodeIssue>,
97    clone_count: usize,
98}
99
100impl CloneVisitor {
101    fn new(file_path: std::path::PathBuf) -> Self {
102        Self {
103            file_path,
104            issues: Vec::new(),
105            clone_count: 0,
106        }
107    }
108}
109
110impl<'ast> Visit<'ast> for CloneVisitor {
111    fn visit_expr_method_call(&mut self, method_call: &'ast ExprMethodCall) {
112        if method_call.method.to_string() == "clone" {
113            self.clone_count += 1;
114
115            // Simple heuristic detection: if there are multiple clones on the same line or nearby, they might be unnecessary
116            if self.clone_count > 3 {
117                let messages = vec![
118                    "clone() 狂魔!你是想把内存用完吗?",
119                    "这么多 clone(),你确定不是在写 Java?",
120                    "clone() 使用过度!Rust 的借用检查器在哭泣",
121                    "又见 clone()!也许你需要重新学习一下 Rust 的所有权系统",
122                    "这些 clone() 让我想起了复印机店的老板",
123                ];
124
125                self.issues.push(CodeIssue {
126                    file_path: self.file_path.clone(),
127                    line: 1, // 简化处理
128                    column: 1,
129                    rule_name: "unnecessary-clone".to_string(),
130                    message: messages[self.issues.len() % messages.len()].to_string(),
131                    severity: Severity::Spicy,
132                    roast_level: RoastLevel::Sarcastic,
133                });
134            }
135        }
136
137        syn::visit::visit_expr_method_call(self, method_call);
138    }
139}