Skip to main content

garbage_code_hunter/rules/
mod.rs

1use std::path::Path;
2use syn::File;
3
4use crate::analyzer::CodeIssue;
5use crate::context::{FileContext, ProjectConfig};
6
7pub mod advanced_rust;
8pub mod code_smells;
9pub mod complexity;
10pub mod comprehensive_rust;
11pub mod duplication;
12pub mod file_structure;
13pub mod garbage_naming;
14pub mod naming;
15pub mod rust_patterns;
16pub mod rust_specific;
17pub mod struct_patterns;
18pub mod student_code;
19
20pub trait Rule {
21    fn name(&self) -> &'static str;
22
23    /// Original check method (backward compatible)
24    fn check(
25        &self,
26        file_path: &Path,
27        syntax_tree: &File,
28        content: &str,
29        lang: &str,
30        is_test_file: bool,
31    ) -> Vec<CodeIssue> {
32        self.check_with_context(
33            file_path,
34            syntax_tree,
35            content,
36            lang,
37            is_test_file,
38            &FileContext::from_path(file_path),
39            &ProjectConfig::default(),
40        )
41    }
42
43    /// New method: check with context (recommended)
44    #[allow(clippy::too_many_arguments)]
45    fn check_with_context(
46        &self,
47        file_path: &Path,
48        syntax_tree: &File,
49        content: &str,
50        lang: &str,
51        is_test_file: bool,
52        _context: &FileContext,
53        _config: &ProjectConfig,
54    ) -> Vec<CodeIssue> {
55        self.check(file_path, syntax_tree, content, lang, is_test_file)
56    }
57}
58
59pub struct RuleEngine {
60    rules: Vec<Box<dyn Rule>>,
61    config: ProjectConfig,
62}
63
64impl Default for RuleEngine {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70impl RuleEngine {
71    pub fn new() -> Self {
72        Self::with_config(ProjectConfig::default())
73    }
74
75    pub fn with_config(config: ProjectConfig) -> Self {
76        let rules: Vec<Box<dyn Rule>> = vec![
77            // Add various detection rules
78            Box::new(naming::TerribleNamingRule),
79            Box::new(naming::SingleLetterVariableRule),
80            // Add garbage naming detection rules
81            Box::new(garbage_naming::MeaninglessNamingRule),
82            Box::new(garbage_naming::HungarianNotationRule),
83            Box::new(garbage_naming::AbbreviationAbuseRule),
84            // Add student code detection rules
85            Box::new(student_code::PrintlnDebuggingRule),
86            Box::new(student_code::PanicAbuseRule),
87            Box::new(student_code::TodoCommentRule),
88            // Add code smell detection rules
89            Box::new(code_smells::MagicNumberRule),
90            Box::new(code_smells::GodFunctionRule),
91            Box::new(code_smells::CommentedCodeRule),
92            Box::new(code_smells::DeadCodeRule),
93            // Add Rust-specific pattern detection rules
94            Box::new(rust_patterns::StringAbuseRule),
95            Box::new(rust_patterns::VecAbuseRule),
96            Box::new(complexity::DeepNestingRule),
97            Box::new(complexity::LongFunctionRule),
98            Box::new(duplication::CodeDuplicationRule),
99            Box::new(rust_specific::UnwrapAbuseRule),
100            Box::new(rust_specific::UnnecessaryCloneRule),
101            // Add advanced Rust-specific rules
102            Box::new(advanced_rust::ComplexClosureRule),
103            Box::new(advanced_rust::LifetimeAbuseRule),
104            Box::new(advanced_rust::TraitComplexityRule),
105            Box::new(advanced_rust::GenericAbuseRule),
106            // Add comprehensive Rust feature rules
107            Box::new(comprehensive_rust::ChannelAbuseRule),
108            Box::new(comprehensive_rust::AsyncAbuseRule),
109            Box::new(comprehensive_rust::DynTraitAbuseRule),
110            Box::new(comprehensive_rust::UnsafeAbuseRule),
111            Box::new(comprehensive_rust::FFIAbuseRule),
112            Box::new(comprehensive_rust::MacroAbuseRule),
113            Box::new(comprehensive_rust::ModuleComplexityRule),
114            Box::new(comprehensive_rust::PatternMatchingAbuseRule),
115            Box::new(struct_patterns::ReferenceAbuseRule),
116            Box::new(struct_patterns::BoxAbuseRule),
117            Box::new(struct_patterns::SliceAbuseRule),
118            // Add file structure rules
119            Box::new(file_structure::FileStructureRule),
120            Box::new(file_structure::ImportChaosRule),
121            Box::new(file_structure::ModuleNestingRule),
122        ];
123
124        Self { rules, config }
125    }
126
127    /// Use context-aware check method (recommended)
128    pub fn check_file_with_context(
129        &self,
130        file_path: &Path,
131        syntax_tree: &File,
132        content: &str,
133        lang: &str,
134        is_test_file: bool,
135    ) -> Vec<CodeIssue> {
136        let context = FileContext::from_path(file_path);
137        let mut issues = Vec::new();
138
139        for rule in &self.rules {
140            if context.should_skip_rule(rule.name()) {
141                continue;
142            }
143
144            let rule_issues = rule.check_with_context(
145                file_path,
146                syntax_tree,
147                content,
148                lang,
149                is_test_file,
150                &context,
151                &self.config,
152            );
153
154            issues.extend(rule_issues);
155        }
156
157        issues
158    }
159
160    /// Legacy check method (backward compatible)
161    pub fn check_file(
162        &self,
163        file_path: &Path,
164        syntax_tree: &File,
165        content: &str,
166        lang: &str,
167        is_test_file: bool,
168    ) -> Vec<CodeIssue> {
169        self.check_file_with_context(file_path, syntax_tree, content, lang, is_test_file)
170    }
171
172    pub fn rule_names(&self) -> Vec<&'static str> {
173        self.rules.iter().map(|r| r.name()).collect()
174    }
175}