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