use crate::directive::RuleScope;
use crate::linter::diagnostic::{Diagnostic, ViolationData};
use crate::linter::rules::{Example, Rule, RuleContext};
use crate::linter::suppression::{Directive, Verb};
pub struct BlanketSuppression;
const EXAMPLES: &[Example] = &[
Example {
caption: "Disabling every rule for the file, including rules that do not exist yet:",
source: "# arity-lint skip-file: generated by a script\nx <- 1\n",
},
Example {
caption: "A directive with no rule ID suppresses nothing at all:",
source: "# arity-lint skip\nx <- 1\n",
},
];
impl Rule for BlanketSuppression {
fn id(&self) -> &'static str {
"blanket-suppression"
}
fn description(&self) -> &'static str {
"Flags an `# arity-lint` directive that names no rule where it could \
have. `# arity-lint skip-file: <reason>` disables every rule for the file, and \
`# arity-lint off: <reason>` does so until the matching `on` — including every \
rule arity ships in the future, so the code quietly stops being checked as the \
rule set grows. A directive with nothing after the verb is the opposite \
failure: it names nothing, so it suppresses nothing. Both are fixed by naming \
the rule. Not flagged: the rule-scoped `# arity-lint skip-file <rule>`, broad \
in range but narrow in effect, and `# arity skip: <reason>`, broad in rules but \
bounded to one statement. Report-only — choosing the rules for the author would \
guess at intent in either direction."
}
fn examples(&self) -> &'static [Example] {
EXAMPLES
}
fn check_file(&self, ctx: &RuleContext<'_>, sink: &mut Vec<Diagnostic>) {
for directive in ctx.suppressions.directives() {
if !directive.has_rule_slot() {
continue;
}
match directive.scope {
RuleScope::Rule(_) => continue,
RuleScope::All if directive.verb == Verb::Skip => continue,
_ => sink.push(report(directive)),
}
}
}
}
fn report(directive: &Directive) -> Diagnostic {
let (body, suggestion) = match (&directive.scope, directive.verb) {
(RuleScope::All, Verb::Off) => (
"this directive disables every lint rule until `# arity-lint on`",
"scope it with `# arity-lint off <rule>: <reason>`",
),
(RuleScope::All, _) => (
"this directive disables every lint rule for the whole file",
"scope it with `# arity-lint skip-file <rule>: <reason>`",
),
_ => (
"this directive names no rule, so it suppresses nothing",
"name the rule: `# arity-lint skip <rule>: <reason>`",
),
};
Diagnostic {
rule: "blanket-suppression",
severity: Default::default(),
path: Default::default(),
range: directive.comment,
message: ViolationData::new("blanket-suppression", body).with_suggestion(suggestion),
fix: None,
}
}