Skip to main content

garbage_code_hunter/
educational.rs

1/// Educational advice system that provides detailed explanations and improvement suggestions
2use std::collections::HashMap;
3
4#[derive(Debug, Clone)]
5pub struct EducationalAdvice {
6    pub why_bad: String,
7    pub how_to_fix: String,
8    pub best_practice_tip: Option<String>,
9}
10
11pub struct EducationalAdvisor {
12    advice_db: HashMap<String, EducationalAdvice>,
13    lang: String,
14}
15
16impl EducationalAdvisor {
17    pub fn new(lang: &str) -> Self {
18        let mut advisor = Self {
19            advice_db: HashMap::new(),
20            lang: lang.to_string(),
21        };
22        advisor.initialize_advice_database();
23        advisor
24    }
25
26    pub fn get_advice(&self, rule_name: &str) -> Option<&EducationalAdvice> {
27        self.advice_db.get(rule_name)
28    }
29
30    fn initialize_advice_database(&mut self) {
31        // Naming convention advice
32        self.add_advice("terrible-naming", self.create_terrible_naming_advice());
33        self.add_advice(
34            "meaningless-naming",
35            self.create_meaningless_naming_advice(),
36        );
37        self.add_advice(
38            "hungarian-notation",
39            self.create_hungarian_notation_advice(),
40        );
41        self.add_advice(
42            "abbreviation-abuse",
43            self.create_abbreviation_abuse_advice(),
44        );
45
46        // Complexity advice
47        self.add_advice("deep-nesting", self.create_deep_nesting_advice());
48        self.add_advice("god-function", self.create_god_function_advice());
49        self.add_advice("long-function", self.create_long_function_advice());
50
51        // Code smells advice
52        self.add_advice("magic-number", self.create_magic_number_advice());
53        self.add_advice("commented-code", self.create_commented_code_advice());
54        self.add_advice("dead-code", self.create_dead_code_advice());
55
56        // Rust-specific advice
57        self.add_advice("unwrap-abuse", self.create_unwrap_abuse_advice());
58        self.add_advice("string-abuse", self.create_string_abuse_advice());
59        self.add_advice("unnecessary-clone", self.create_unnecessary_clone_advice());
60        self.add_advice("iterator-abuse", self.create_iterator_abuse_advice());
61
62        // Student code advice
63        self.add_advice("println-debugging", self.create_println_debugging_advice());
64        self.add_advice("panic-abuse", self.create_panic_abuse_advice());
65        self.add_advice("todo-comment", self.create_todo_comment_advice());
66
67        // File structure advice
68        self.add_advice("file-too-long", self.create_file_too_long_advice());
69        self.add_advice("unordered-imports", self.create_unordered_imports_advice());
70        self.add_advice(
71            "deep-module-nesting",
72            self.create_deep_module_nesting_advice(),
73        );
74    }
75
76    fn add_advice(&mut self, rule_name: &str, advice: EducationalAdvice) {
77        self.advice_db.insert(rule_name.to_string(), advice);
78    }
79
80    fn create_terrible_naming_advice(&self) -> EducationalAdvice {
81        if self.lang == "zh-CN" {
82            EducationalAdvice {
83                why_bad: "糟糕的变量命名会严重影响代码可读性,让其他开发者(包括未来的你)难以理解代码意图。".to_string(),
84                how_to_fix: "使用描述性的、有意义的变量名,清楚地表达变量的用途和含义。".to_string(),
85                best_practice_tip: Some("变量名应该是自文档化的,读代码的人应该能从名字就理解变量的用途。".to_string()),
86            }
87        } else {
88            EducationalAdvice {
89                why_bad: "Poor variable naming severely impacts code readability, making it difficult for other developers (including future you) to understand the code's intent.".to_string(),
90                how_to_fix: "Use descriptive, meaningful variable names that clearly express the variable's purpose and meaning.".to_string(),
91                best_practice_tip: Some("Variable names should be self-documenting - readers should understand the purpose from the name alone.".to_string()),
92            }
93        }
94    }
95
96    fn create_meaningless_naming_advice(&self) -> EducationalAdvice {
97        if self.lang == "zh-CN" {
98            EducationalAdvice {
99                why_bad: "使用 foo、bar、data、temp 等占位符命名会让代码失去表达力,增加维护成本。"
100                    .to_string(),
101                how_to_fix: "根据变量的实际用途选择具体的、有意义的名称。".to_string(),
102                best_practice_tip: Some(
103                    "避免使用通用词汇,选择能准确描述数据性质的词汇。".to_string(),
104                ),
105            }
106        } else {
107            EducationalAdvice {
108                why_bad: "Using placeholder names like foo, bar, data, temp makes code lose expressiveness and increases maintenance cost.".to_string(),
109                how_to_fix: "Choose specific, meaningful names based on the variable's actual purpose.".to_string(),
110                best_practice_tip: Some("Avoid generic words, choose words that accurately describe the nature of the data.".to_string()),
111            }
112        }
113    }
114
115    fn create_hungarian_notation_advice(&self) -> EducationalAdvice {
116        if self.lang == "zh-CN" {
117            EducationalAdvice {
118                why_bad:
119                    "匈牙利命名法在现代编程语言中已经过时,Rust 的类型系统已经提供了类型安全保障。"
120                        .to_string(),
121                how_to_fix: "使用描述性名称而不是类型前缀,让 Rust 的类型系统处理类型检查。"
122                    .to_string(),
123                best_practice_tip: Some(
124                    "Rust 的强类型系统使得类型前缀变得多余,专注于语义而非类型。".to_string(),
125                ),
126            }
127        } else {
128            EducationalAdvice {
129                why_bad: "Hungarian notation is outdated in modern programming languages, Rust's type system already provides type safety guarantees.".to_string(),
130                how_to_fix: "Use descriptive names instead of type prefixes, let Rust's type system handle type checking.".to_string(),
131                best_practice_tip: Some("Rust's strong type system makes type prefixes redundant, focus on semantics rather than types.".to_string()),
132            }
133        }
134    }
135
136    fn create_abbreviation_abuse_advice(&self) -> EducationalAdvice {
137        if self.lang == "zh-CN" {
138            EducationalAdvice {
139                why_bad: "过度缩写会让代码变得难以理解,特别是对新团队成员或几个月后的自己。"
140                    .to_string(),
141                how_to_fix: "使用完整的、清晰的单词,现代编辑器的自动补全让长名称不再是问题。"
142                    .to_string(),
143                best_practice_tip: Some(
144                    "清晰胜过简洁,代码被阅读的次数远超过被编写的次数。".to_string(),
145                ),
146            }
147        } else {
148            EducationalAdvice {
149                why_bad: "Excessive abbreviations make code hard to understand, especially for new team members or yourself months later.".to_string(),
150                how_to_fix: "Use complete, clear words. Modern editors' auto-completion makes long names no longer a problem.".to_string(),
151                best_practice_tip: Some("Clarity over brevity - code is read far more often than it's written.".to_string()),
152            }
153        }
154    }
155
156    fn create_deep_nesting_advice(&self) -> EducationalAdvice {
157        if self.lang == "zh-CN" {
158            EducationalAdvice {
159                why_bad: "深层嵌套增加了代码的认知复杂度,使得逻辑难以跟踪和调试。".to_string(),
160                how_to_fix: "使用早期返回、提取函数、或者 Rust 的 ? 操作符来减少嵌套层级。"
161                    .to_string(),
162                best_practice_tip: Some(
163                    "保持嵌套层级在 3 层以内,使用卫语句和早期返回。".to_string(),
164                ),
165            }
166        } else {
167            EducationalAdvice {
168                why_bad: "Deep nesting increases cognitive complexity, making logic hard to follow and debug.".to_string(),
169                how_to_fix: "Use early returns, extract functions, or Rust's ? operator to reduce nesting levels.".to_string(),
170                best_practice_tip: Some("Keep nesting levels within 3, use guard clauses and early returns.".to_string()),
171            }
172        }
173    }
174
175    fn create_unwrap_abuse_advice(&self) -> EducationalAdvice {
176        if self.lang == "zh-CN" {
177            EducationalAdvice {
178                why_bad:
179                    "过度使用 unwrap() 会导致程序在遇到错误时直接崩溃,无法优雅地处理异常情况。"
180                        .to_string(),
181                how_to_fix: "使用 match、if let、或者 ? 操作符来正确处理 Option 和 Result 类型。"
182                    .to_string(),
183                best_practice_tip: Some(
184                    "只在你确定不会失败的情况下使用 unwrap(),并添加注释说明原因。".to_string(),
185                ),
186            }
187        } else {
188            EducationalAdvice {
189                why_bad: "Excessive use of unwrap() causes programs to crash directly when encountering errors, unable to handle exceptions gracefully.".to_string(),
190                how_to_fix: "Use match, if let, or the ? operator to properly handle Option and Result types.".to_string(),
191                best_practice_tip: Some("Only use unwrap() when you're certain it won't fail, and add comments explaining why.".to_string()),
192            }
193        }
194    }
195
196    fn create_string_abuse_advice(&self) -> EducationalAdvice {
197        if self.lang == "zh-CN" {
198            EducationalAdvice {
199                why_bad:
200                    "不必要的 String 分配会增加内存使用和性能开销,特别是在只需要读取的场景中。"
201                        .to_string(),
202                how_to_fix: "在只需要读取字符串的地方使用 &str,只在需要拥有所有权时使用 String。"
203                    .to_string(),
204                best_practice_tip: Some(
205                    "优先使用 &str 作为函数参数,这样可以接受 String 和 &str 两种类型。"
206                        .to_string(),
207                ),
208            }
209        } else {
210            EducationalAdvice {
211                why_bad: "Unnecessary String allocations increase memory usage and performance overhead, especially in read-only scenarios.".to_string(),
212                how_to_fix: "Use &str where you only need to read strings, use String only when you need ownership.".to_string(),
213                best_practice_tip: Some("Prefer &str as function parameters, this way you can accept both String and &str types.".to_string()),
214            }
215        }
216    }
217
218    fn create_println_debugging_advice(&self) -> EducationalAdvice {
219        if self.lang == "zh-CN" {
220            EducationalAdvice {
221                why_bad: "遗留的 println! 调试语句会污染输出,在生产环境中可能泄露敏感信息。"
222                    .to_string(),
223                how_to_fix: "使用 log 库进行日志记录,或者使用 dbg! 宏进行临时调试(记得删除)。"
224                    .to_string(),
225                best_practice_tip: Some(
226                    "使用条件编译 #[cfg(debug_assertions)] 来确保调试代码不会进入生产环境。"
227                        .to_string(),
228                ),
229            }
230        } else {
231            EducationalAdvice {
232                why_bad: "Leftover println! debug statements pollute output and may leak sensitive information in production.".to_string(),
233                how_to_fix: "Use the log crate for logging, or use the dbg! macro for temporary debugging (remember to remove).".to_string(),
234                best_practice_tip: Some("Use conditional compilation #[cfg(debug_assertions)] to ensure debug code doesn't reach production.".to_string()),
235            }
236        }
237    }
238
239    fn create_file_too_long_advice(&self) -> EducationalAdvice {
240        if self.lang == "zh-CN" {
241            EducationalAdvice {
242                why_bad: "过长的文件难以导航和维护,违反了单一职责原则,增加了代码复杂度。"
243                    .to_string(),
244                how_to_fix: "将大文件拆分成多个小模块,每个模块负责特定的功能领域。".to_string(),
245                best_practice_tip: Some(
246                    "保持文件在 500-1000 行以内,超出时考虑按功能拆分。".to_string(),
247                ),
248            }
249        } else {
250            EducationalAdvice {
251                why_bad: "Overly long files are hard to navigate and maintain, violate the single responsibility principle, and increase code complexity.".to_string(),
252                how_to_fix: "Split large files into multiple small modules, each responsible for specific functional areas.".to_string(),
253                best_practice_tip: Some("Keep files within 500-1000 lines, consider splitting by functionality when exceeded.".to_string()),
254            }
255        }
256    }
257
258    // Add more advice creation methods for other rules...
259    fn create_god_function_advice(&self) -> EducationalAdvice {
260        if self.lang == "zh-CN" {
261            EducationalAdvice {
262                why_bad: "做太多事情的函数违反了单一职责原则,难以测试和维护。".to_string(),
263                how_to_fix: "将大函数拆分成更小的、专注的函数,每个函数只做一件事。".to_string(),
264                best_practice_tip: Some("保持函数在 20-30 行以内,专注于单一任务。".to_string()),
265            }
266        } else {
267            EducationalAdvice {
268                why_bad: "Functions that do too much violate the single responsibility principle and are hard to test and maintain.".to_string(),
269                how_to_fix: "Break down large functions into smaller, focused functions that each do one thing well.".to_string(),
270                best_practice_tip: Some("Keep functions under 20-30 lines and focused on a single task.".to_string()),
271            }
272        }
273    }
274
275    fn create_long_function_advice(&self) -> EducationalAdvice {
276        if self.lang == "zh-CN" {
277            EducationalAdvice {
278                why_bad: "长函数更难理解、测试和维护。".to_string(),
279                how_to_fix: "将逻辑块提取到具有描述性名称的独立函数中。".to_string(),
280                best_practice_tip: Some(
281                    "如果你无法在屏幕上看到整个函数,那它可能太长了。".to_string(),
282                ),
283            }
284        } else {
285            EducationalAdvice {
286                why_bad: "Long functions are harder to understand, test, and maintain.".to_string(),
287                how_to_fix:
288                    "Extract logical blocks into separate functions with descriptive names."
289                        .to_string(),
290                best_practice_tip: Some(
291                    "If you can't see the entire function on your screen, it's probably too long."
292                        .to_string(),
293                ),
294            }
295        }
296    }
297
298    fn create_magic_number_advice(&self) -> EducationalAdvice {
299        if self.lang == "zh-CN" {
300            EducationalAdvice {
301                why_bad: "魔法数字让代码难以理解和维护。".to_string(),
302                how_to_fix: "用能解释其用途的命名常量替换魔法数字。".to_string(),
303                best_practice_tip: Some("对具有语义含义的值使用 const 声明。".to_string()),
304            }
305        } else {
306            EducationalAdvice {
307                why_bad: "Magic numbers make code hard to understand and maintain.".to_string(),
308                how_to_fix:
309                    "Replace magic numbers with named constants that explain their purpose."
310                        .to_string(),
311                best_practice_tip: Some(
312                    "Use const declarations for values that have semantic meaning.".to_string(),
313                ),
314            }
315        }
316    }
317
318    fn create_commented_code_advice(&self) -> EducationalAdvice {
319        if self.lang == "zh-CN" {
320            EducationalAdvice {
321                why_bad: "注释掉的代码会污染代码库,让人困惑哪些是真正在使用的代码。".to_string(),
322                how_to_fix: "删除注释掉的代码 - 版本控制系统会保留历史记录。".to_string(),
323                best_practice_tip: Some(
324                    "相信你的版本控制系统 - 删除死代码而不是注释掉它。".to_string(),
325                ),
326            }
327        } else {
328            EducationalAdvice {
329                why_bad: "Commented-out code clutters the codebase and creates confusion about what's actually used.".to_string(),
330                how_to_fix: "Remove commented code - version control systems preserve history.".to_string(),
331                best_practice_tip: Some("Trust your version control system - delete dead code instead of commenting it out.".to_string()),
332            }
333        }
334    }
335
336    fn create_dead_code_advice(&self) -> EducationalAdvice {
337        if self.lang == "zh-CN" {
338            EducationalAdvice {
339                why_bad: "死代码增加了维护负担,会让开发者困惑。".to_string(),
340                how_to_fix: "定期删除未使用的函数、变量和导入。".to_string(),
341                best_practice_tip: Some("使用 cargo clippy 自动检测死代码。".to_string()),
342            }
343        } else {
344            EducationalAdvice {
345                why_bad: "Dead code increases maintenance burden and can confuse developers."
346                    .to_string(),
347                how_to_fix: "Remove unused functions, variables, and imports regularly."
348                    .to_string(),
349                best_practice_tip: Some(
350                    "Use cargo clippy to detect dead code automatically.".to_string(),
351                ),
352            }
353        }
354    }
355
356    fn create_unnecessary_clone_advice(&self) -> EducationalAdvice {
357        if self.lang == "zh-CN" {
358            EducationalAdvice {
359                why_bad: "不必要的 clone 会浪费内存和 CPU 周期。".to_string(),
360                how_to_fix: "尽可能使用引用,只在需要所有权时才 clone。".to_string(),
361                best_practice_tip: Some("理解 Rust 的借用规则以减少不必要的分配。".to_string()),
362            }
363        } else {
364            EducationalAdvice {
365                why_bad: "Unnecessary clones waste memory and CPU cycles.".to_string(),
366                how_to_fix: "Use references when possible, clone only when you need ownership."
367                    .to_string(),
368                best_practice_tip: Some(
369                    "Understand Rust's borrowing rules to minimize unnecessary allocations."
370                        .to_string(),
371                ),
372            }
373        }
374    }
375
376    fn create_iterator_abuse_advice(&self) -> EducationalAdvice {
377        if self.lang == "zh-CN" {
378            EducationalAdvice {
379                why_bad: "手动循环通常比迭代器链更低效且表达力差。".to_string(),
380                how_to_fix: "在适当的情况下使用 map、filter、fold 等迭代器方法代替手动循环。"
381                    .to_string(),
382                best_practice_tip: Some(
383                    "迭代器链由于惰性求值和编译器优化,通常更高效。".to_string(),
384                ),
385            }
386        } else {
387            EducationalAdvice {
388                why_bad: "Manual loops are often less efficient and expressive than iterator chains.".to_string(),
389                how_to_fix: "Use iterator methods like map, filter, fold instead of manual loops when appropriate.".to_string(),
390                best_practice_tip: Some("Iterator chains are often more efficient due to lazy evaluation and compiler optimizations.".to_string()),
391            }
392        }
393    }
394
395    fn create_panic_abuse_advice(&self) -> EducationalAdvice {
396        if self.lang == "zh-CN" {
397            EducationalAdvice {
398                why_bad: "过度使用 panic 会让程序在生产环境中不可靠且难以调试。".to_string(),
399                how_to_fix: "对可恢复的错误使用 Result 类型,仅在真正无法恢复的情况下使用 panic。"
400                    .to_string(),
401                best_practice_tip: Some(
402                    "Panic 应该用于编程错误,而不是预期的错误条件。".to_string(),
403                ),
404            }
405        } else {
406            EducationalAdvice {
407                why_bad: "Excessive panics make programs unreliable and hard to debug in production.".to_string(),
408                how_to_fix: "Use Result types for recoverable errors, reserve panics for truly unrecoverable situations.".to_string(),
409                best_practice_tip: Some("Panics should be used for programming errors, not for expected error conditions.".to_string()),
410            }
411        }
412    }
413
414    fn create_todo_comment_advice(&self) -> EducationalAdvice {
415        if self.lang == "zh-CN" {
416            EducationalAdvice {
417                why_bad: "过多的 TODO 注释表示代码不完整或规划不当。".to_string(),
418                how_to_fix: "要么实现这些 TODO,要么为未来的工作创建适当的问题跟踪。".to_string(),
419                best_practice_tip: Some(
420                    "谨慎使用 TODO,并始终附带具体的解决方案计划。".to_string(),
421                ),
422            }
423        } else {
424            EducationalAdvice {
425                why_bad: "Too many TODO comments indicate incomplete or poorly planned code."
426                    .to_string(),
427                how_to_fix:
428                    "Either implement the TODOs or create proper issue tracking for future work."
429                        .to_string(),
430                best_practice_tip: Some(
431                    "Use TODO sparingly and always with a specific plan for resolution."
432                        .to_string(),
433                ),
434            }
435        }
436    }
437
438    fn create_unordered_imports_advice(&self) -> EducationalAdvice {
439        EducationalAdvice {
440            why_bad: "Unordered imports make it hard to find and manage dependencies.".to_string(),
441            how_to_fix: "Use rustfmt to automatically sort imports, or sort them manually by: std, external crates, local modules.".to_string(),
442            best_practice_tip: Some("Configure your editor to run rustfmt on save to maintain consistent formatting.".to_string()),
443        }
444    }
445
446    fn create_deep_module_nesting_advice(&self) -> EducationalAdvice {
447        EducationalAdvice {
448            why_bad: "Deep module nesting makes code navigation difficult and indicates poor architecture.".to_string(),
449            how_to_fix: "Flatten module structure, use re-exports to maintain clean public APIs.".to_string(),
450            best_practice_tip: Some("Keep module nesting to 2-3 levels maximum, use re-exports for convenience.".to_string()),
451        }
452    }
453}