luaur_analysis/methods/
lint_for_range_visit.rs1use crate::functions::emit_warning::emit_warning;
2use crate::records::lint_for_range::LintForRange;
3use luaur_ast::records::ast_expr_constant_number::AstExprConstantNumber;
4use luaur_ast::records::ast_expr_unary::{AstExprUnary, AstExprUnaryOp};
5use luaur_ast::records::ast_node::AstNode;
6use luaur_ast::records::ast_stat_for::AstStatFor;
7use luaur_ast::records::location::Location;
8use luaur_ast::rtti::ast_node_as;
9use luaur_config::enums::code::Code;
10
11impl LintForRange {
12 pub fn visit_ast_stat_for_linter(&mut self, node: *mut AstStatFor) -> bool {
13 unsafe {
14 if (*node).step.is_null() {
15 let fc = ast_node_as::<AstExprConstantNumber>((*node).from as *mut AstNode);
16 let fu = ast_node_as::<AstExprUnary>((*node).from as *mut AstNode);
17 let tc = ast_node_as::<AstExprConstantNumber>((*node).to as *mut AstNode);
18 let tu = ast_node_as::<AstExprUnary>((*node).to as *mut AstNode);
19
20 let range_location = Location::new(
21 (*(*node).from).base.location.begin,
22 (*(*node).to).base.location.end,
23 );
24
25 if !fu.is_null()
26 && (*fu).op == AstExprUnaryOp::Len
27 && !tc.is_null()
28 && (*tc).value == 1.0
29 {
30 emit_warning(
31 &mut *self.context,
32 Code::Code_ForRange,
33 range_location,
34 format_args!("For loop should iterate backwards; did you forget to specify -1 as step?"),
35 );
36 } else if !fc.is_null() && !tc.is_null() && (*fc).value > (*tc).value {
37 emit_warning(
38 &mut *self.context,
39 Code::Code_ForRange,
40 range_location,
41 format_args!("For loop should iterate backwards; did you forget to specify -1 as step?"),
42 );
43 } else if !fc.is_null()
44 && !tc.is_null()
45 && self.get_loop_end((*fc).value, (*tc).value) != (*tc).value
46 {
47 emit_warning(
48 &mut *self.context,
49 Code::Code_ForRange,
50 range_location,
51 format_args!(
52 "For loop ends at {} instead of {}; did you forget to specify step?",
53 self.get_loop_end((*fc).value, (*tc).value),
54 (*tc).value
55 ),
56 );
57 } else if !fc.is_null()
58 && !tu.is_null()
59 && (*fc).value == 0.0
60 && (*tu).op == AstExprUnaryOp::Len
61 {
62 emit_warning(
63 &mut *self.context,
64 Code::Code_ForRange,
65 range_location,
66 format_args!("For loop starts at 0, but arrays start at 1"),
67 );
68 } else if !fu.is_null()
69 && (*fu).op == AstExprUnaryOp::Len
70 && !tc.is_null()
71 && (*tc).value == 0.0
72 {
73 emit_warning(
74 &mut *self.context,
75 Code::Code_ForRange,
76 range_location,
77 format_args!("For loop should iterate backwards; did you forget to specify -1 as step? Also consider changing 0 to 1 since arrays start at 1"),
78 );
79 }
80 }
81 }
82
83 true
84 }
85}