luaur_analysis/methods/
lint_format_string_match_call.rs1use crate::functions::emit_warning::emit_warning;
2use crate::functions::is_string::is_string;
3use crate::records::lint_format_string::LintFormatString;
4use luaur_ast::records::ast_array::AstArray;
5use luaur_ast::records::ast_expr::AstExpr;
6use luaur_ast::records::ast_expr_call::AstExprCall;
7use luaur_ast::records::ast_expr_constant_string::AstExprConstantString;
8use luaur_ast::records::ast_expr_global::AstExprGlobal;
9use luaur_ast::records::ast_expr_group::AstExprGroup;
10use luaur_ast::records::ast_expr_index_name::AstExprIndexName;
11use luaur_ast::records::ast_node::AstNode;
12use luaur_ast::rtti;
13use luaur_config::enums::code::Code;
14
15impl LintFormatString {
16 pub fn match_call(&mut self, node: *mut AstExprCall) {
17 let node = unsafe { &*node };
18 let func = unsafe { rtti::ast_node_as::<AstExprIndexName>(node.func as *mut AstNode) };
19 if func.is_null() {
20 return;
21 }
22
23 if node.self_ {
24 let group = unsafe { rtti::ast_node_as::<AstExprGroup>((*func).expr as *mut AstNode) };
25 let self_expr: *mut AstExpr = if !group.is_null() {
26 unsafe { (*group).expr }
27 } else {
28 unsafe { (*func).expr }
29 };
30
31 if rtti::ast_node_is::<AstExprConstantString>(self_expr as *mut AstNode) {
32 self.match_string_call(unsafe { (*func).index }, self_expr, node.args);
33 } else if let Some(type_id) = unsafe { (*self.context).get_type(self_expr) } {
34 if is_string(type_id) {
35 self.match_string_call(unsafe { (*func).index }, self_expr, node.args);
36 }
37 }
38 return;
39 }
40
41 let lib = unsafe { rtti::ast_node_as::<AstExprGlobal>((*func).expr as *mut AstNode) };
42 if lib.is_null() {
43 return;
44 }
45
46 let lib_name = unsafe { (*lib).name };
47
48 if lib_name.operator_eq_c_char(c"string".as_ptr()) {
49 if node.args.size > 0 {
50 let rest = AstArray {
51 data: unsafe { node.args.data.add(1) },
52 size: node.args.size - 1,
53 };
54 let first_arg = unsafe { *node.args.data.add(0) };
55 self.match_string_call(unsafe { (*func).index }, first_arg, rest);
56 }
57 } else if lib_name.operator_eq_c_char(c"os".as_ptr()) {
58 if unsafe { (*func).index }.operator_eq_c_char(c"date".as_ptr()) && node.args.size > 0 {
59 let arg0 = unsafe { *node.args.data.add(0) };
60 let fmt =
61 unsafe { rtti::ast_node_as::<AstExprConstantString>(arg0 as *mut AstNode) };
62 if !fmt.is_null() {
63 let error = self.check_date_format(unsafe { (*fmt).value.data }, unsafe {
64 (*fmt).value.size
65 });
66 if !error.is_null() {
67 let error_str =
68 unsafe { core::ffi::CStr::from_ptr(error).to_string_lossy() };
69 emit_warning(
70 unsafe { &mut *self.context },
71 Code::Code_FormatString,
72 unsafe { (*fmt).base.base.location },
73 format_args!("Invalid date format: {}", error_str),
74 );
75 }
76 }
77 }
78 }
79 }
80}