use crate::ast::{AstNode, AstToken, Condition, Expr};
use crate::linter::diagnostic::{Applicability, Diagnostic, Fix};
use crate::linter::rules::{Example, Rule, RuleContext};
use crate::syntax::{SyntaxElement, SyntaxKind};
pub struct AssignmentInCondition;
impl Rule for AssignmentInCondition {
fn id(&self) -> &'static str {
"assignment-in-condition"
}
fn description(&self) -> &'static str {
"Flag a bare `=` assignment used as the test of an `if`/`elseif`/`while`. \
It is valid Julia but almost always a typo for `==`, so it is reported \
with a safe fix that rewrites `=` to `==`."
}
fn examples(&self) -> &'static [Example] {
&[Example {
caption: "`=` where `==` was meant:",
source: "if x = 5\n println(x)\nend\n",
}]
}
fn interests(&self) -> &'static [SyntaxKind] {
&[SyntaxKind::CONDITION]
}
fn check(&self, el: &SyntaxElement, _ctx: &RuleContext<'_>, sink: &mut Vec<Diagnostic>) {
let Some(condition) = el.as_node().cloned().and_then(Condition::cast) else {
return;
};
let Some(Expr::AssignmentExpr(assign)) = condition.expr() else {
return;
};
let Some(op) = assign
.op()
.filter(|op| op.syntax().kind() == SyntaxKind::EQ)
else {
return;
};
let range = op.syntax().text_range();
let mut diag = Diagnostic::new(
self.id(),
assign.syntax().text_range(),
"assignment used as a condition; did you mean `==`?",
);
diag.fixes.push(Fix {
description: "Replace `=` with `==`".to_string(),
content: "==".to_string(),
start: range.start().into(),
end: range.end().into(),
applicability: Applicability::Safe,
});
sink.push(diag);
}
}