garbage_code_hunter/rules/
rust_specific.rs1use 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, 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 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, 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}