garbage_code_hunter/rules/
complexity.rs

1use 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, // TODO: Get actual line number
77                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        // Simplified handling: return an estimated value based on content length
117        // Real projects could calculate actual line counts through more complex methods
118        let line_count = self.content.lines().count();
119        if line_count > 50 {
120            line_count
121        } else {
122            50 + (self.issues.len() * 10) // Simulate functions of different lengths
123        }
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, // Simplified handling
169                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}