normalize_native_rules/
dead_parameter.rs1use normalize_languages::parsers::grammar_loader;
15use normalize_languages::support_for_path;
16use normalize_output::diagnostics::{DiagnosticsReport, Issue, Severity};
17use normalize_scope::ScopeEngine;
18use std::path::Path;
19
20use crate::cache::{FileRule, run_file_rule};
21use normalize_rules_config::WalkConfig;
22
23#[derive(serde::Serialize, serde::Deserialize)]
25pub struct DeadParameterFinding {
26 rel_path: String,
27 name: String,
29 line: usize,
31}
32
33pub struct DeadParameterRule;
35
36impl FileRule for DeadParameterRule {
37 type Finding = DeadParameterFinding;
38
39 fn engine_name(&self) -> &str {
40 "dead-parameter"
41 }
42
43 fn config_hash(&self) -> String {
44 "1".into()
46 }
47
48 fn check_file(&self, path: &Path, root: &Path) -> Vec<Self::Finding> {
49 let support = match support_for_path(path) {
50 Some(s) => s,
51 None => return Vec::new(),
52 };
53 let content = match std::fs::read_to_string(path) {
54 Ok(c) => c,
55 Err(_) => return Vec::new(),
56 };
57
58 let loader = grammar_loader();
59 let engine = ScopeEngine::new(&loader);
60 let lang = support.grammar_name();
61
62 if !engine.has_locals(lang) {
64 return Vec::new();
65 }
66
67 let unused = engine.find_unused_parameters(lang, &content);
68 if unused.is_empty() {
69 return Vec::new();
70 }
71
72 let rel_path = path
73 .strip_prefix(root)
74 .unwrap_or(path)
75 .to_string_lossy()
76 .to_string();
77
78 unused
79 .into_iter()
80 .map(|def| DeadParameterFinding {
81 rel_path: rel_path.clone(),
82 name: def.name,
83 line: def.location.line,
84 })
85 .collect()
86 }
87
88 fn to_diagnostics(
89 &self,
90 findings: Vec<(std::path::PathBuf, Vec<Self::Finding>)>,
91 _root: &Path,
92 files_checked: usize,
93 ) -> DiagnosticsReport {
94 let issues: Vec<Issue> = findings
95 .into_iter()
96 .flat_map(|(_path, file_findings)| file_findings)
97 .map(|f| Issue {
98 file: f.rel_path,
99 line: Some(f.line),
100 column: None,
101 end_line: None,
102 end_column: None,
103 rule_id: "dead-parameter".into(),
104 message: format!("parameter `{}` is never used", f.name),
105 severity: Severity::Warning,
106 source: "dead-parameter".into(),
107 related: vec![],
108 suggestion: Some(
109 "prefix with `_` to mark it intentionally unused, or remove it if possible"
110 .into(),
111 ),
112 })
113 .collect();
114
115 DiagnosticsReport {
116 issues,
117 files_checked,
118 sources_run: vec!["dead-parameter".into()],
119 tool_errors: vec![],
120 daemon_cached: false,
121 }
122 }
123}
124
125pub fn build_dead_parameter_report(
130 root: &Path,
131 explicit_files: Option<&[std::path::PathBuf]>,
132 walk_config: &WalkConfig,
133) -> DiagnosticsReport {
134 let rule = DeadParameterRule;
135 run_file_rule(&rule, root, explicit_files, walk_config)
136}