use crate::linter::LintResult;
pub const MIGRATIONS: &[(&str, &str)] = &[
("SC1009", "BRS0001"),
("SC2036", "BRS0002"),
("SC2066", "BRS0003"),
("SC2069", "BRS0004"),
("SC2077", "BRS0005"),
("SC2081", "BRS0006"),
("SC2087", "BRS0007"),
("SC2095", "BRS0008"),
("SC2096", "BRS0009"),
("SC2104", "BRS0010"),
("SC2114", "BRS0011"),
("SC2117", "BRS0012"),
("SC2141", "BRS0013"),
("SC2165", "BRS0014"),
("SC2183", "BRS0015"),
("SC2223", "BRS0016"),
("SC2224", "BRS0017"),
("SC2227", "BRS0018"),
("SC2231", "BRS0019"),
("SC2233", "BRS0020"),
("SC2266", "BRS0021"),
("SC2268", "BRS0022"),
("SC2269", "BRS0023"),
("SC2282", "BRS0024"),
("SC2286", "BRS0025"),
("SC2311", "BRS0026"),
("SC2061", "BRS0027"),
("SC2235", "BRS0028"),
("SC2248", "BRS0029"),
("SC2267", "BRS0030"),
("SC2283", "BRS0031"),
("SC2287", "BRS0032"),
("SC2289", "BRS0033"),
("SC2291", "BRS0034"),
("SC2292", "BRS0035"),
("SC2294", "BRS0036"),
];
pub const RETIRED: &[(&str, &str)] = &[(
"SC2032",
"unfalsifiable: fires on correct code by construction (0/9253 true positives measured)",
)];
pub const PARITY: &[&str] = &[
"SC1003", "SC2001", "SC2021", "SC2024", "SC2043", "SC2050", "SC2054", "SC2094", "SC2103",
"SC2119", "SC2120", "SC2124", "SC2209", "SC1007", "SC1014", "SC1020", "SC1028", "SC1078",
"SC1079", "SC1083", "SC1087", "SC1090", "SC1091", "SC2002", "SC2003", "SC2004", "SC2005",
"SC2006", "SC2007", "SC2015", "SC2016", "SC2018", "SC2019", "SC2025", "SC2028", "SC2029",
"SC2030", "SC2031", "SC2034", "SC2035", "SC2037", "SC2038", "SC2044", "SC2046", "SC2048",
"SC2053", "SC2059", "SC2060", "SC2062", "SC2063", "SC2068", "SC2076", "SC2086", "SC2088",
"SC2089", "SC2090", "SC2091", "SC2097", "SC2098", "SC2102", "SC2105", "SC2112", "SC2113",
"SC2115", "SC2116", "SC2122", "SC2125", "SC2126", "SC2128", "SC2129", "SC2140", "SC2143",
"SC2145", "SC2148", "SC2153", "SC2154", "SC2155", "SC2156", "SC2157", "SC2162", "SC2164",
"SC2166", "SC2168", "SC2178", "SC2181", "SC2182", "SC2188", "SC2198", "SC2204", "SC2206",
"SC2207", "SC2230", "SC2236", "SC2244", "SC2249", "SC2295", "SC2310",
"SC1035", "SC2111", ];
pub fn canonical(code: &str) -> &str {
for (legacy, new) in MIGRATIONS {
if *legacy == code {
return new;
}
}
code
}
pub fn legacy_alias(code: &str) -> Option<&'static str> {
MIGRATIONS
.iter()
.find(|(_, new)| *new == code)
.map(|(legacy, _)| *legacy)
}
pub fn is_retired(code: &str) -> bool {
RETIRED.iter().any(|(c, _)| *c == code)
}
pub fn is_parity(code: &str) -> bool {
PARITY.contains(&code)
}
pub fn apply(result: &mut LintResult) {
for diag in &mut result.diagnostics {
let canon = canonical(&diag.code);
if canon != diag.code {
diag.code = canon.to_string();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::linter::{Diagnostic, Severity, Span};
#[test]
fn canonical_maps_measured_collisions_out_of_the_sc_namespace() {
assert_eq!(canonical("SC2311"), "BRS0026");
assert_eq!(canonical("SC2032"), "SC2032"); assert_eq!(canonical("SC2086"), "SC2086"); }
#[test]
fn canonical_is_idempotent() {
for (_, new) in MIGRATIONS {
assert_eq!(canonical(canonical(new)), *new);
}
}
#[test]
fn legacy_alias_round_trips_every_migration() {
for (legacy, new) in MIGRATIONS {
assert_eq!(legacy_alias(new), Some(*legacy));
}
assert_eq!(legacy_alias("SC2086"), None);
}
#[test]
fn apply_preserves_diagnostic_count_and_spans() {
let mut result = LintResult::new();
for code in ["SC2311", "SEC011", "SC2086", "SC2266"] {
result.add(Diagnostic::new(
code,
Severity::Error,
"m",
Span::new(1, 1, 1, 2),
));
}
let before = result.diagnostics.len();
apply(&mut result);
assert_eq!(result.diagnostics.len(), before);
let codes: Vec<&str> = result.diagnostics.iter().map(|d| d.code.as_str()).collect();
assert_eq!(codes, vec!["BRS0026", "SEC011", "SC2086", "BRS0021"]);
}
#[test]
fn retired_entries_carry_a_reason() {
for (code, why) in RETIRED {
assert!(!why.is_empty(), "{code} was retired without a reason");
}
}
}