Skip to content

Commit e0e3044

Browse files
committed
refactor flow analyze
1 parent 6941750 commit e0e3044

File tree

2 files changed

+140
-85
lines changed

2 files changed

+140
-85
lines changed
Lines changed: 118 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
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,
45
};
56
use rowan::TextRange;
67

@@ -20,8 +21,9 @@ pub fn analyze(analyzer: &mut FlowAnalyzer) -> Option<()> {
2021
let mut flow_chains = LuaFlowChain::new(decl_id);
2122
for range in ranges {
2223
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+
}
2527
}
2628
analyzer
2729
.db
@@ -32,84 +34,63 @@ pub fn analyze(analyzer: &mut FlowAnalyzer) -> Option<()> {
3234
Some(())
3335
}
3436

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-
8837
fn infer_name_expr(
8938
analyzer: &FlowAnalyzer,
9039
flow_chains: &mut LuaFlowChain,
9140
name_expr: LuaNameExpr,
9241
) -> Option<()> {
9342
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<()> {
9460
match parent {
9561
LuaAst::LuaIfStat(if_stat) => {
9662
// 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+
}
9981
}
10082
LuaAst::LuaWhileStat(while_stat) => {
10183
// this mean the name_expr is a condition and the name_expr is not nil and is not false
10284
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());
10486
}
10587
LuaAst::LuaElseIfClauseStat(else_if_clause_stat) => {
10688
// this mean the name_expr is a condition and the name_expr is not nil and is not false
10789
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());
10991
}
11092
LuaAst::LuaIndexExpr(index_expr) => {
11193
let key = index_expr.get_index_key()?;
112-
let range = get_effect_range(LuaExpr::IndexExpr(index_expr))?;
11394
let reference_key = match key {
11495
LuaIndexKey::Integer(i) => {
11596
if i.is_int() {
@@ -125,24 +106,59 @@ fn infer_name_expr(
125106
_ => return None,
126107
};
127108

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+
);
129117
}
130118
LuaAst::LuaBinaryExpr(binary_expr) => {
131119
let op = binary_expr.get_op_token()?;
132120
match op.get_op() {
133121
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+
);
136134
}
137135
_ => {}
138136
}
139137
}
140138
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+
}
142159
}
143160
_ => {}
144161
}
145-
146162
Some(())
147163
}
148164

@@ -168,18 +184,18 @@ fn infer_call_arg_list(
168184
}
169185

170186
fn infer_lua_type_assert(
171-
_: &FlowAnalyzer,
187+
analyzer: &FlowAnalyzer,
172188
flow_chains: &mut LuaFlowChain,
173189
call_expr: LuaCallExpr,
174190
) -> 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()?;
177193
match op.get_op() {
178194
BinaryOperator::OpEq => {}
179195
_ => return None,
180196
};
181197

182-
let operands = parent.get_exprs()?;
198+
let operands = binary_expr.get_exprs()?;
183199
let literal_expr = if let LuaExpr::LiteralExpr(literal) = operands.0 {
184200
literal
185201
} else if let LuaExpr::LiteralExpr(literal) = operands.1 {
@@ -194,21 +210,42 @@ fn infer_lua_type_assert(
194210
};
195211

196212
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),
205221
_ => {
206222
return None;
207223
}
208224
};
209225

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+
);
212233

213234
Some(())
214235
}
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+
}

crates/code_analysis/src/db_index/type/type_assert.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,35 @@ use super::{LuaExistFieldType, LuaType, LuaUnionType};
77
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
88
pub enum TypeAssertion {
99
Exist,
10-
IsNativeLuaType(LuaType),
10+
NotExist,
11+
Force(LuaType),
1112
FieldExist(Arc<LuaMemberKey>),
1213
Add(LuaType),
1314
Remove(LuaType),
14-
Force(LuaType),
1515
}
1616

1717
#[allow(unused)]
1818
impl TypeAssertion {
1919
pub fn tighten_type(&self, source: LuaType) -> LuaType {
2020
match self {
2121
TypeAssertion::Exist => remove_nil_and_not_false(source),
22-
TypeAssertion::IsNativeLuaType(t) => force_type(source, t.clone()),
22+
TypeAssertion::NotExist => force_nil_or_false(source),
23+
TypeAssertion::Force(t) => force_type(source, t.clone()),
2324
TypeAssertion::FieldExist(key) => {
2425
LuaType::ExistField(LuaExistFieldType::new((**key).clone(), source).into())
2526
}
2627
TypeAssertion::Add(lua_type) => add_type(source, lua_type.clone()),
2728
TypeAssertion::Remove(lua_type) => remove_type(source, lua_type.clone()),
28-
TypeAssertion::Force(lua_type) => force_type(source, lua_type.clone()),
29+
_ => source,
30+
}
31+
}
32+
33+
pub fn get_negation(&self) -> Option<TypeAssertion> {
34+
match self {
35+
TypeAssertion::Exist => Some(TypeAssertion::NotExist),
36+
TypeAssertion::NotExist => Some(TypeAssertion::Exist),
37+
TypeAssertion::Force(t) => Some(TypeAssertion::Remove(t.clone())),
38+
_ => None,
2939
}
3040
}
3141
}
@@ -52,6 +62,14 @@ fn remove_nil_and_not_false(t: LuaType) -> LuaType {
5262
}
5363
}
5464

65+
fn force_nil_or_false(t: LuaType) -> LuaType {
66+
if t.is_boolean() {
67+
return LuaType::BooleanConst(false);
68+
}
69+
70+
return LuaType::Nil;
71+
}
72+
5573
fn force_type(source: LuaType, target: LuaType) -> LuaType {
5674
match &source {
5775
LuaType::Union(union) => {

0 commit comments

Comments
 (0)