use emmylua_parser::{LuaAstNode, LuaCallExpr};
use crate::{DiagnosticCode, LuaType, SemanticModel, check_export_visibility};
use super::{Checker, DiagnosticContext};
pub struct RequireModuleVisibilityChecker;
impl Checker for RequireModuleVisibilityChecker {
const CODES: &[DiagnosticCode] = &[
DiagnosticCode::RequireModuleNotVisible,
DiagnosticCode::UnresolvedRequire,
];
fn check(context: &mut DiagnosticContext, semantic_model: &SemanticModel) {
let root = semantic_model.get_root().clone();
for call_expr in root.descendants::<LuaCallExpr>() {
if call_expr.is_require() {
check_require_call_expr(context, semantic_model, call_expr);
}
}
}
}
fn check_require_call_expr(
context: &mut DiagnosticContext,
semantic_model: &SemanticModel,
call_expr: LuaCallExpr,
) -> Option<()> {
let args_list = call_expr.get_args_list()?;
let arg_expr = args_list.get_args().next()?;
let ty = semantic_model
.infer_expr(arg_expr.clone())
.unwrap_or(LuaType::Any);
let module_path = match ty {
LuaType::StringConst(s) => s.as_ref().to_string(),
_ => return Some(()),
};
let Some(module_info) = semantic_model
.get_db()
.get_module_index()
.find_module(&module_path)
else {
context.add_diagnostic(
DiagnosticCode::UnresolvedRequire,
arg_expr.get_range(),
t!("Cannot resolve module `%{module}`.", module = module_path).to_string(),
None,
);
return Some(());
};
if !check_export_visibility(semantic_model, module_info).unwrap_or(false) {
context.add_diagnostic(
DiagnosticCode::RequireModuleNotVisible,
arg_expr.get_range(),
t!(
"Module '%{module}' is not visible. It has @export restrictions.",
module = module_info.full_module_name
)
.to_string(),
None,
);
}
Some(())
}