use crate::{DiagnosticCode, LocalAttribute, LuaDeclExtra, LuaDeclId, SemanticModel};
use super::{Checker, DiagnosticContext};
pub struct LocalConstReassignChecker;
impl Checker for LocalConstReassignChecker {
const CODES: &[DiagnosticCode] = &[
DiagnosticCode::LocalConstReassign,
DiagnosticCode::IterVariableReassign,
];
fn check(context: &mut DiagnosticContext, semantic_model: &SemanticModel) {
let file_id = semantic_model.get_file_id();
let Some(decl_tree) = semantic_model
.get_db()
.get_decl_index()
.get_decl_tree(&file_id)
else {
return;
};
for (decl_id, decl) in decl_tree.get_decls() {
if let LuaDeclExtra::Local {
attrib: Some(attrib @ (LocalAttribute::Const | LocalAttribute::IterConst)),
..
} = &decl.extra
{
check_local_const_reassign(context, semantic_model, decl_id, attrib);
}
}
}
}
fn check_local_const_reassign(
context: &mut DiagnosticContext,
semantic_model: &SemanticModel,
decl_id: &LuaDeclId,
attrib: &LocalAttribute,
) -> Option<()> {
let file_id = semantic_model.get_file_id();
let refs_index = semantic_model.get_db().get_reference_index();
let local_refs = refs_index.get_local_reference(&file_id)?;
let decl_refs = local_refs.get_decl_references(decl_id)?;
for decl_ref in &decl_refs.cells {
if decl_ref.is_write {
match attrib {
LocalAttribute::Const => {
context.add_diagnostic(
DiagnosticCode::LocalConstReassign,
decl_ref.range,
t!("Cannot reassign to a constant variable").to_string(),
None,
);
}
LocalAttribute::IterConst => {
context.add_diagnostic(
DiagnosticCode::IterVariableReassign,
decl_ref.range,
t!("Should not reassign to iter variable").to_string(),
None,
);
}
_ => {}
}
}
}
Some(())
}