use super::{base_caps, concepts_of, finding_from_concept};
use crate::domain::concepts::ConceptKind;
use crate::domain::model::LanguageModel;
use crate::domain::rule::{Rule, RuleMeta};
use crate::domain::types::{Confidence, Finding, Severity};
use std::sync::OnceLock;
#[derive(Default)]
pub struct UnsafeTerminationRule;
impl Rule for UnsafeTerminationRule {
fn meta(&self) -> &RuleMeta {
static META: OnceLock<RuleMeta> = OnceLock::new();
META.get_or_init(|| RuleMeta {
id: "unsafe-termination".into(),
name: "Unsafe termination".into(),
description: "Process or task may abort on recoverable errors (unwrap/expect/panic)."
.into(),
default_severity: Severity::High,
required_capabilities: base_caps(),
autofix_safe: false,
})
}
fn evaluate(&self, model: &LanguageModel) -> Vec<Finding> {
concepts_of(model, ConceptKind::Termination)
.map(|(lang, c)| {
let confidence = if c.tag == "unwrap" || c.tag == "expect" || c.tag == "panic" {
Confidence::High
} else {
Confidence::Medium
};
finding_from_concept(
&self.meta().id,
lang,
c,
Severity::High,
confidence,
format!("Unsafe termination via `{}`.", c.tag),
"A recoverable error aborts the process or task, taking down the service.",
"Return Result/Option, use map_err, or handle with explicit recovery.",
)
})
.collect()
}
}