1
1
use emmylua_parser:: {
2
- BinaryOperator , LuaAst , LuaAstNode , LuaBinaryExpr , LuaCallArgList , LuaCallExpr , LuaExpr ,
3
- LuaIndexKey , LuaLiteralToken , LuaNameExpr , LuaSyntaxId , LuaSyntaxKind ,
2
+ BinaryOperator , LuaAst , LuaAstNode , LuaBinaryExpr , LuaBlock , LuaCallArgList , LuaCallExpr ,
3
+ LuaExpr , LuaIndexKey , LuaLiteralToken , LuaNameExpr , LuaStat , LuaSyntaxId , LuaSyntaxKind ,
4
+ UnaryOperator ,
4
5
} ;
5
6
use rowan:: TextRange ;
6
7
@@ -20,8 +21,9 @@ pub fn analyze(analyzer: &mut FlowAnalyzer) -> Option<()> {
20
21
let mut flow_chains = LuaFlowChain :: new ( decl_id) ;
21
22
for range in ranges {
22
23
let syntax_id = LuaSyntaxId :: new ( LuaSyntaxKind :: NameExpr . into ( ) , range. clone ( ) ) ;
23
- let node = LuaNameExpr :: cast ( syntax_id. to_node_from_root ( root) ?) ?;
24
- infer_name_expr ( analyzer, & mut flow_chains, node) ;
24
+ if let Some ( node) = LuaNameExpr :: cast ( syntax_id. to_node_from_root ( root) ?) {
25
+ infer_name_expr ( analyzer, & mut flow_chains, node) ;
26
+ }
25
27
}
26
28
analyzer
27
29
. db
@@ -32,84 +34,63 @@ pub fn analyze(analyzer: &mut FlowAnalyzer) -> Option<()> {
32
34
Some ( ( ) )
33
35
}
34
36
35
- fn get_effect_range ( check_expr : LuaExpr ) -> Option < TextRange > {
36
- let parent = check_expr. get_parent :: < LuaAst > ( ) ?;
37
- match parent {
38
- LuaAst :: LuaIfStat ( if_stat) => {
39
- let range = if_stat. get_block ( ) ?. get_range ( ) ;
40
- Some ( range)
41
- }
42
- LuaAst :: LuaWhileStat ( while_stat) => {
43
- let range = while_stat. get_block ( ) ?. get_range ( ) ;
44
- Some ( range)
45
- }
46
- LuaAst :: LuaElseIfClauseStat ( else_if_clause_stat) => {
47
- let range = else_if_clause_stat. get_block ( ) ?. get_range ( ) ;
48
- Some ( range)
49
- }
50
- LuaAst :: LuaParenExpr ( paren_expr) => get_effect_range ( LuaExpr :: ParenExpr ( paren_expr) ) ,
51
- LuaAst :: LuaBinaryExpr ( binary_expr) => {
52
- let op = binary_expr. get_op_token ( ) ?;
53
- let basic_range = match op. get_op ( ) {
54
- BinaryOperator :: OpAnd => {
55
- let range = binary_expr. get_range ( ) ;
56
- let check_range = check_expr. get_range ( ) ;
57
- if check_range. start ( ) == range. start ( ) {
58
- let start = check_range. end ( ) ;
59
- let end = range. end ( ) ;
60
- if start < end {
61
- Some ( TextRange :: new ( start, end) )
62
- } else {
63
- None
64
- }
65
- } else {
66
- None
67
- }
68
- }
69
- _ => return None ,
70
- } ;
71
-
72
- let parent_effect_range = get_effect_range ( LuaExpr :: BinaryExpr ( binary_expr) ) ;
73
- match ( basic_range, parent_effect_range) {
74
- ( Some ( basic_range) , Some ( parent_effect_range) ) => {
75
- let start = basic_range. start ( ) . min ( parent_effect_range. start ( ) ) ;
76
- let end = basic_range. end ( ) . max ( parent_effect_range. end ( ) ) ;
77
- Some ( TextRange :: new ( start, end) )
78
- }
79
- ( Some ( basic_range) , None ) => Some ( basic_range) ,
80
- ( None , Some ( parent_effect_range) ) => Some ( parent_effect_range) ,
81
- _ => None ,
82
- }
83
- }
84
- _ => None ,
85
- }
86
- }
87
-
88
37
fn infer_name_expr (
89
38
analyzer : & FlowAnalyzer ,
90
39
flow_chains : & mut LuaFlowChain ,
91
40
name_expr : LuaNameExpr ,
92
41
) -> Option < ( ) > {
93
42
let parent = name_expr. get_parent :: < LuaAst > ( ) ?;
43
+ broadcast_up (
44
+ analyzer,
45
+ flow_chains,
46
+ parent,
47
+ LuaAst :: LuaNameExpr ( name_expr) ,
48
+ TypeAssertion :: Exist ,
49
+ ) ;
50
+ Some ( ( ) )
51
+ }
52
+
53
+ fn broadcast_up (
54
+ analyzer : & FlowAnalyzer ,
55
+ flow_chains : & mut LuaFlowChain ,
56
+ parent : LuaAst ,
57
+ origin : LuaAst ,
58
+ type_assert : TypeAssertion ,
59
+ ) -> Option < ( ) > {
94
60
match parent {
95
61
LuaAst :: LuaIfStat ( if_stat) => {
96
62
// this mean the name_expr is a condition and the name_expr is not nil and is not false
97
- let block = if_stat. get_block ( ) ?;
98
- flow_chains. add_type_assert ( TypeAssertion :: Exist , block. get_range ( ) ) ;
63
+ if let Some ( block) = if_stat. get_block ( ) {
64
+ flow_chains. add_type_assert ( type_assert. clone ( ) , block. get_range ( ) ) ;
65
+ }
66
+
67
+ if let Some ( ne_type_assert) = type_assert. get_negation ( ) {
68
+ if let Some ( else_stat) = if_stat. get_else_clause ( ) {
69
+ let range = else_stat. get_range ( ) ;
70
+ flow_chains. add_type_assert ( ne_type_assert, range) ;
71
+ } else if is_block_has_return ( if_stat. get_block ( ) ?) . unwrap_or ( false ) {
72
+ let parent_block = if_stat. get_parent :: < LuaBlock > ( ) ?;
73
+ let parent_range = parent_block. get_range ( ) ;
74
+ let if_range = if_stat. get_range ( ) ;
75
+ if if_range. end ( ) < parent_range. end ( ) {
76
+ let range = TextRange :: new ( if_range. end ( ) , parent_range. end ( ) ) ;
77
+ flow_chains. add_type_assert ( ne_type_assert, range) ;
78
+ }
79
+ }
80
+ }
99
81
}
100
82
LuaAst :: LuaWhileStat ( while_stat) => {
101
83
// this mean the name_expr is a condition and the name_expr is not nil and is not false
102
84
let block = while_stat. get_block ( ) ?;
103
- flow_chains. add_type_assert ( TypeAssertion :: Exist , block. get_range ( ) ) ;
85
+ flow_chains. add_type_assert ( type_assert , block. get_range ( ) ) ;
104
86
}
105
87
LuaAst :: LuaElseIfClauseStat ( else_if_clause_stat) => {
106
88
// this mean the name_expr is a condition and the name_expr is not nil and is not false
107
89
let block = else_if_clause_stat. get_block ( ) ?;
108
- flow_chains. add_type_assert ( TypeAssertion :: Exist , block. get_range ( ) ) ;
90
+ flow_chains. add_type_assert ( type_assert , block. get_range ( ) ) ;
109
91
}
110
92
LuaAst :: LuaIndexExpr ( index_expr) => {
111
93
let key = index_expr. get_index_key ( ) ?;
112
- let range = get_effect_range ( LuaExpr :: IndexExpr ( index_expr) ) ?;
113
94
let reference_key = match key {
114
95
LuaIndexKey :: Integer ( i) => {
115
96
if i. is_int ( ) {
@@ -125,24 +106,59 @@ fn infer_name_expr(
125
106
_ => return None ,
126
107
} ;
127
108
128
- flow_chains. add_type_assert ( TypeAssertion :: FieldExist ( reference_key. into ( ) ) , range) ;
109
+ let type_assert = TypeAssertion :: FieldExist ( reference_key. into ( ) ) ;
110
+ broadcast_up (
111
+ analyzer,
112
+ flow_chains,
113
+ index_expr. get_parent :: < LuaAst > ( ) ?,
114
+ LuaAst :: LuaIndexExpr ( index_expr) ,
115
+ type_assert,
116
+ ) ;
129
117
}
130
118
LuaAst :: LuaBinaryExpr ( binary_expr) => {
131
119
let op = binary_expr. get_op_token ( ) ?;
132
120
match op. get_op ( ) {
133
121
BinaryOperator :: OpAnd => {
134
- let range = get_effect_range ( LuaExpr :: NameExpr ( name_expr) ) ?;
135
- flow_chains. add_type_assert ( TypeAssertion :: Exist , range) ;
122
+ let ( left, right) = binary_expr. get_exprs ( ) ?;
123
+ if left. get_position ( ) == origin. get_position ( ) {
124
+ flow_chains. add_type_assert ( type_assert. clone ( ) , right. get_range ( ) ) ;
125
+ }
126
+
127
+ broadcast_up (
128
+ analyzer,
129
+ flow_chains,
130
+ binary_expr. get_parent :: < LuaAst > ( ) ?,
131
+ LuaAst :: LuaBinaryExpr ( binary_expr) ,
132
+ type_assert,
133
+ ) ;
136
134
}
137
135
_ => { }
138
136
}
139
137
}
140
138
LuaAst :: LuaCallArgList ( call_args_list) => {
141
- infer_call_arg_list ( analyzer, flow_chains, call_args_list) ?;
139
+ if type_assert == TypeAssertion :: Exist {
140
+ infer_call_arg_list ( analyzer, flow_chains, call_args_list) ?;
141
+ }
142
+ }
143
+ LuaAst :: LuaUnaryExpr ( unary_expr) => {
144
+ let op = unary_expr. get_op_token ( ) ?;
145
+ match op. get_op ( ) {
146
+ UnaryOperator :: OpNot => {
147
+ if let Some ( ne_type_assert) = type_assert. get_negation ( ) {
148
+ broadcast_up (
149
+ analyzer,
150
+ flow_chains,
151
+ unary_expr. get_parent :: < LuaAst > ( ) ?,
152
+ LuaAst :: LuaUnaryExpr ( unary_expr) ,
153
+ ne_type_assert,
154
+ ) ;
155
+ }
156
+ }
157
+ _ => { }
158
+ }
142
159
}
143
160
_ => { }
144
161
}
145
-
146
162
Some ( ( ) )
147
163
}
148
164
@@ -168,18 +184,18 @@ fn infer_call_arg_list(
168
184
}
169
185
170
186
fn infer_lua_type_assert (
171
- _ : & FlowAnalyzer ,
187
+ analyzer : & FlowAnalyzer ,
172
188
flow_chains : & mut LuaFlowChain ,
173
189
call_expr : LuaCallExpr ,
174
190
) -> Option < ( ) > {
175
- let parent = call_expr. get_parent :: < LuaBinaryExpr > ( ) ?;
176
- let op = parent . get_op_token ( ) ?;
191
+ let binary_expr = call_expr. get_parent :: < LuaBinaryExpr > ( ) ?;
192
+ let op = binary_expr . get_op_token ( ) ?;
177
193
match op. get_op ( ) {
178
194
BinaryOperator :: OpEq => { }
179
195
_ => return None ,
180
196
} ;
181
197
182
- let operands = parent . get_exprs ( ) ?;
198
+ let operands = binary_expr . get_exprs ( ) ?;
183
199
let literal_expr = if let LuaExpr :: LiteralExpr ( literal) = operands. 0 {
184
200
literal
185
201
} else if let LuaExpr :: LiteralExpr ( literal) = operands. 1 {
@@ -194,21 +210,42 @@ fn infer_lua_type_assert(
194
210
} ;
195
211
196
212
let type_assert = match type_literal. as_str ( ) {
197
- "number" => TypeAssertion :: IsNativeLuaType ( LuaType :: Number ) ,
198
- "string" => TypeAssertion :: IsNativeLuaType ( LuaType :: String ) ,
199
- "boolean" => TypeAssertion :: IsNativeLuaType ( LuaType :: Boolean ) ,
200
- "table" => TypeAssertion :: IsNativeLuaType ( LuaType :: Table ) ,
201
- "function" => TypeAssertion :: IsNativeLuaType ( LuaType :: Function ) ,
202
- "thread" => TypeAssertion :: IsNativeLuaType ( LuaType :: Thread ) ,
203
- "userdata" => TypeAssertion :: IsNativeLuaType ( LuaType :: Userdata ) ,
204
- "nil" => TypeAssertion :: IsNativeLuaType ( LuaType :: Nil ) ,
213
+ "number" => TypeAssertion :: Force ( LuaType :: Number ) ,
214
+ "string" => TypeAssertion :: Force ( LuaType :: String ) ,
215
+ "boolean" => TypeAssertion :: Force ( LuaType :: Boolean ) ,
216
+ "table" => TypeAssertion :: Force ( LuaType :: Table ) ,
217
+ "function" => TypeAssertion :: Force ( LuaType :: Function ) ,
218
+ "thread" => TypeAssertion :: Force ( LuaType :: Thread ) ,
219
+ "userdata" => TypeAssertion :: Force ( LuaType :: Userdata ) ,
220
+ "nil" => TypeAssertion :: Force ( LuaType :: Nil ) ,
205
221
_ => {
206
222
return None ;
207
223
}
208
224
} ;
209
225
210
- let range = get_effect_range ( LuaExpr :: BinaryExpr ( parent) ) ?;
211
- flow_chains. add_type_assert ( type_assert, range) ;
226
+ broadcast_up (
227
+ analyzer,
228
+ flow_chains,
229
+ binary_expr. get_parent :: < LuaAst > ( ) ?,
230
+ LuaAst :: LuaBinaryExpr ( binary_expr) ,
231
+ type_assert,
232
+ ) ;
212
233
213
234
Some ( ( ) )
214
235
}
236
+
237
+ fn is_block_has_return ( block : LuaBlock ) -> Option < bool > {
238
+ for stat in block. get_stats ( ) {
239
+ match stat {
240
+ LuaStat :: ReturnStat ( _) => return Some ( true ) ,
241
+ LuaStat :: DoStat ( do_stat) => {
242
+ if is_block_has_return ( do_stat. get_block ( ) ?) . unwrap_or ( false ) {
243
+ return Some ( true ) ;
244
+ }
245
+ }
246
+ _ => { }
247
+ }
248
+ }
249
+
250
+ Some ( false )
251
+ }
0 commit comments