Skip to main content

luaur_analysis/methods/
lint_table_operations_check_indexer.rs

1use crate::enums::table_state::TableState;
2use crate::functions::emit_warning::emit_warning;
3use crate::functions::follow_type::follow_type_id;
4use crate::functions::get_type_alt_j::get_type_id;
5use crate::functions::is_string::is_string;
6use crate::records::lint_table_operations::LintTableOperations;
7use crate::records::table_type::TableType;
8use luaur_ast::records::ast_expr::AstExpr;
9use luaur_config::enums::code::Code;
10
11impl LintTableOperations {
12    pub fn check_indexer(&mut self, node: *mut AstExpr, expr: *mut AstExpr, op: &str) {
13        let ty = unsafe { (*self.context).get_type(expr) };
14        if ty.is_none() {
15            return;
16        }
17
18        let ty = ty.unwrap();
19        let followed = unsafe { follow_type_id(ty) };
20        let tty = unsafe { get_type_id::<TableType>(followed) };
21
22        if tty.is_null() {
23            return;
24        }
25
26        let tty_ref = unsafe { &*tty };
27
28        if tty_ref.indexer.is_none()
29            && !tty_ref.props.is_empty()
30            && tty_ref.state != TableState::Generic
31        {
32            let msg = format!(
33                "Using '{}' on a table without an array part is likely a bug",
34                op
35            );
36            // Pass `format_args!` straight into the call: a `fmt::Arguments`
37            // borrows its operands, so storing it in a `let` and using it in a
38            // later statement is the shape that dangles if an operand is ever a
39            // temporary (the E0716 fixed in luaur-vm's pusherror.rs, issue #3).
40            emit_warning(
41                unsafe { &mut *self.context },
42                Code::Code_TableOperations,
43                unsafe { (*node).base.location },
44                format_args!("{}", msg),
45            );
46        } else if tty_ref.indexer.is_some()
47            && is_string(tty_ref.indexer.as_ref().unwrap().index_type)
48        {
49            let msg = format!("Using '{}' on a table with string keys is likely a bug", op);
50            // Pass `format_args!` straight into the call: a `fmt::Arguments`
51            // borrows its operands, so storing it in a `let` and using it in a
52            // later statement is the shape that dangles if an operand is ever a
53            // temporary (the E0716 fixed in luaur-vm's pusherror.rs, issue #3).
54            emit_warning(
55                unsafe { &mut *self.context },
56                Code::Code_TableOperations,
57                unsafe { (*node).base.location },
58                format_args!("{}", msg),
59            );
60        }
61    }
62}