luaur_analysis/functions/
get_fallthrough.rs1use luaur_ast::records::ast_expr_call::AstExprCall;
2use luaur_ast::records::ast_expr_constant_bool::AstExprConstantBool;
3use luaur_ast::records::ast_stat::AstStat;
4use luaur_ast::records::ast_stat_block::AstStatBlock;
5use luaur_ast::records::ast_stat_expr::AstStatExpr;
6use luaur_ast::records::ast_stat_if::AstStatIf;
7use luaur_ast::records::ast_stat_repeat::AstStatRepeat;
8use luaur_ast::records::ast_stat_return::AstStatReturn;
9use luaur_ast::records::ast_stat_while::AstStatWhile;
10use luaur_ast::rtti::ast_node_as;
11use luaur_ast::rtti::ast_node_is;
12
13use crate::functions::does_call_error::does_call_error;
14use crate::functions::has_break::has_break;
15
16pub fn get_fallthrough(node: *const AstStat) -> *const AstStat {
17 if node.is_null() {
18 return core::ptr::null();
19 }
20
21 unsafe {
22 if !ast_node_as::<AstStatBlock>(
23 node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
24 )
25 .is_null()
26 {
27 let stat = ast_node_as::<AstStatBlock>(
28 node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
29 );
30 if stat.is_null() {
31 return core::ptr::null();
32 }
33
34 if (*stat).body.size == 0 {
35 return stat as *const AstStat;
36 }
37
38 let size = (*stat).body.size;
39 for i in 0..(size.saturating_sub(1)) {
40 let s = *(*stat).body.data.add(i);
41 if get_fallthrough(s).is_null() {
42 return core::ptr::null();
43 }
44 }
45
46 let last = *(*stat).body.data.add(size - 1);
47 return get_fallthrough(last);
48 }
49
50 if !ast_node_as::<AstStatIf>(node as *const _ as *mut luaur_ast::records::ast_node::AstNode)
51 .is_null()
52 {
53 let stat = ast_node_as::<AstStatIf>(
54 node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
55 );
56 if stat.is_null() {
57 return core::ptr::null();
58 }
59
60 let thenf = get_fallthrough((*stat).thenbody as *const AstStat);
61 if !thenf.is_null() {
62 return thenf;
63 }
64
65 if !(*stat).elsebody.is_null() {
66 let elsef = get_fallthrough((*stat).elsebody);
67 if !elsef.is_null() {
68 return elsef;
69 }
70 return core::ptr::null();
71 } else {
72 return node;
73 }
74 }
75
76 if ast_node_is::<AstStatReturn>(unsafe {
77 &*(node as *const luaur_ast::records::ast_node::AstNode)
78 }) {
79 return core::ptr::null();
80 }
81
82 if !ast_node_as::<AstStatExpr>(
83 node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
84 )
85 .is_null()
86 {
87 let stat = ast_node_as::<AstStatExpr>(
88 node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
89 );
90 if stat.is_null() {
91 return core::ptr::null();
92 }
93
94 if !(*stat).expr.is_null() {
95 let call = ast_node_as::<AstExprCall>(
96 (*stat).expr as *mut luaur_ast::records::ast_node::AstNode,
97 );
98 if !call.is_null() {
99 if does_call_error(&*call) {
100 return core::ptr::null();
101 }
102 }
103 }
104
105 return node;
106 }
107
108 if !ast_node_as::<AstStatWhile>(
109 node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
110 )
111 .is_null()
112 {
113 let stat = ast_node_as::<AstStatWhile>(
114 node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
115 );
116 if stat.is_null() {
117 return core::ptr::null();
118 }
119
120 if !(*stat).condition.is_null() {
121 let expr = ast_node_as::<AstExprConstantBool>(
122 (*stat).condition as *mut luaur_ast::records::ast_node::AstNode,
123 );
124 if !expr.is_null() {
125 if (*expr).value && !has_break((*stat).body as *mut AstStat) {
126 return core::ptr::null();
127 }
128 }
129 }
130
131 return node;
132 }
133
134 if !ast_node_as::<AstStatRepeat>(
135 node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
136 )
137 .is_null()
138 {
139 let stat = ast_node_as::<AstStatRepeat>(
140 node as *const _ as *mut luaur_ast::records::ast_node::AstNode,
141 );
142 if stat.is_null() {
143 return core::ptr::null();
144 }
145
146 if !(*stat).condition.is_null() {
147 let expr = ast_node_as::<AstExprConstantBool>(
148 (*stat).condition as *mut luaur_ast::records::ast_node::AstNode,
149 );
150 if !expr.is_null() {
151 if !(*expr).value && !has_break((*stat).body as *mut AstStat) {
152 return core::ptr::null();
153 }
154 }
155 }
156
157 if get_fallthrough((*stat).body as *const AstStat).is_null() {
158 return core::ptr::null();
159 }
160
161 return node;
162 }
163
164 node
165 }
166}