garbage_code_hunter/rules/
complexity.rs1use std::path::Path;
2use syn::{visit::Visit, Block, File, ItemFn};
3
4use crate::analyzer::{CodeIssue, RoastLevel, Severity};
5use crate::rules::Rule;
6
7pub struct DeepNestingRule;
8
9impl Rule for DeepNestingRule {
10 fn name(&self) -> &'static str {
11 "deep-nesting"
12 }
13
14 fn check(&self, file_path: &Path, syntax_tree: &File, _content: &str) -> Vec<CodeIssue> {
15 let mut visitor = NestingVisitor::new(file_path.to_path_buf());
16 visitor.visit_file(syntax_tree);
17 visitor.issues
18 }
19}
20
21pub struct LongFunctionRule;
22
23impl Rule for LongFunctionRule {
24 fn name(&self) -> &'static str {
25 "long-function"
26 }
27
28 fn check(&self, file_path: &Path, syntax_tree: &File, content: &str) -> Vec<CodeIssue> {
29 let mut visitor = FunctionLengthVisitor::new(file_path.to_path_buf(), content);
30 visitor.visit_file(syntax_tree);
31 visitor.issues
32 }
33}
34
35struct NestingVisitor {
36 file_path: std::path::PathBuf,
37 issues: Vec<CodeIssue>,
38 current_depth: usize,
39}
40
41impl NestingVisitor {
42 fn new(file_path: std::path::PathBuf) -> Self {
43 Self {
44 file_path,
45 issues: Vec::new(),
46 current_depth: 0,
47 }
48 }
49
50 fn check_nesting_depth(&mut self, _block: &Block) {
51 if self.current_depth > 5 {
52 let messages = vec![
53 "这嵌套层数比俄罗斯套娃还要深,你确定不是在写迷宫?",
54 "嵌套这么深,是想挖到地心吗?",
55 "这代码嵌套得像洋葱一样,看着就想哭",
56 "嵌套层数超标!建议重构,或者准备好纸巾给维护代码的人",
57 "这嵌套深度已经可以申请吉尼斯世界纪录了",
58 ];
59
60 let severity = if self.current_depth > 8 {
61 Severity::Nuclear
62 } else if self.current_depth > 6 {
63 Severity::Spicy
64 } else {
65 Severity::Mild
66 };
67
68 let roast_level = if self.current_depth > 8 {
69 RoastLevel::Savage
70 } else {
71 RoastLevel::Sarcastic
72 };
73
74 self.issues.push(CodeIssue {
75 file_path: self.file_path.clone(),
76 line: 1, column: 1,
78 rule_name: "deep-nesting".to_string(),
79 message: format!(
80 "{} (嵌套深度: {})",
81 messages[self.issues.len() % messages.len()],
82 self.current_depth
83 ),
84 severity,
85 roast_level,
86 });
87 }
88 }
89}
90
91impl<'ast> Visit<'ast> for NestingVisitor {
92 fn visit_block(&mut self, block: &'ast Block) {
93 self.current_depth += 1;
94 self.check_nesting_depth(block);
95 syn::visit::visit_block(self, block);
96 self.current_depth -= 1;
97 }
98}
99
100struct FunctionLengthVisitor {
101 file_path: std::path::PathBuf,
102 issues: Vec<CodeIssue>,
103 content: String,
104}
105
106impl FunctionLengthVisitor {
107 fn new(file_path: std::path::PathBuf, content: &str) -> Self {
108 Self {
109 file_path,
110 issues: Vec::new(),
111 content: content.to_string(),
112 }
113 }
114
115 fn count_function_lines(&self, _func: &ItemFn) -> usize {
116 let line_count = self.content.lines().count();
119 if line_count > 50 {
120 line_count
121 } else {
122 50 + (self.issues.len() * 10) }
124 }
125}
126
127impl<'ast> Visit<'ast> for FunctionLengthVisitor {
128 fn visit_item_fn(&mut self, func: &'ast ItemFn) {
129 let line_count = self.count_function_lines(func);
130 let func_name = func.sig.ident.to_string();
131
132 if line_count > 50 {
133 let messages = vec![
134 format!(
135 "函数 '{}' 有 {} 行?这不是函数,这是小说!",
136 func_name, line_count
137 ),
138 format!(
139 "'{}' 函数长度 {} 行,建议拆分成几个小函数,或者直接重写",
140 func_name, line_count
141 ),
142 format!(
143 "{}行的函数?'{}'你是想让人一口气读完然后缺氧吗?",
144 line_count, func_name
145 ),
146 format!(
147 "函数 '{}' 比我的耐心还要长({}行),考虑重构吧",
148 func_name, line_count
149 ),
150 ];
151
152 let severity = if line_count > 100 {
153 Severity::Nuclear
154 } else if line_count > 75 {
155 Severity::Spicy
156 } else {
157 Severity::Mild
158 };
159
160 let roast_level = if line_count > 100 {
161 RoastLevel::Savage
162 } else {
163 RoastLevel::Sarcastic
164 };
165
166 self.issues.push(CodeIssue {
167 file_path: self.file_path.clone(),
168 line: 1, column: 1,
170 rule_name: "long-function".to_string(),
171 message: messages[self.issues.len() % messages.len()].clone(),
172 severity,
173 roast_level,
174 });
175 }
176
177 syn::visit::visit_item_fn(self, func);
178 }
179}