Skip to content

Commit 03817bb

Browse files
authored
Merge pull request #523 from EmmyLuaLs/refactor-flow
refactor flow algorithm
2 parents 3552cb3 + d706173 commit 03817bb

File tree

82 files changed

+3238
-2733
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+3238
-2733
lines changed

crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_ref_tags.rs

Lines changed: 24 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
use emmylua_parser::{
2-
BinaryOperator, LuaAst, LuaAstNode, LuaAstToken, LuaBlock, LuaDocDescriptionOwner, LuaDocTagAs,
3-
LuaDocTagCast, LuaDocTagModule, LuaDocTagOther, LuaDocTagOverload, LuaDocTagParam,
4-
LuaDocTagReturn, LuaDocTagReturnCast, LuaDocTagSee, LuaDocTagType, LuaExpr, LuaLocalName,
5-
LuaTokenKind, LuaVarExpr,
2+
LuaAst, LuaAstNode, LuaAstToken, LuaBlock, LuaDocDescriptionOwner, LuaDocTagAs, LuaDocTagCast,
3+
LuaDocTagModule, LuaDocTagOther, LuaDocTagOverload, LuaDocTagParam, LuaDocTagReturn,
4+
LuaDocTagReturnCast, LuaDocTagSee, LuaDocTagType, LuaExpr, LuaLocalName, LuaTokenKind,
5+
LuaVarExpr,
66
};
77

88
use crate::{
9-
compilation::analyzer::{
10-
bind_type::bind_type, flow::CastAction, unresolve::UnResolveModuleRef,
11-
},
9+
compilation::analyzer::{bind_type::bind_type, unresolve::UnResolveModuleRef},
1210
db_index::{
1311
LuaDeclId, LuaDocParamInfo, LuaDocReturnInfo, LuaMemberId, LuaOperator, LuaSemanticDeclId,
1412
LuaSignatureId, LuaType,
1513
},
16-
InFiled, InferFailReason, LuaOperatorMetaMethod, LuaTypeCache, OperatorFunction,
17-
SignatureReturnStatus, TypeAssertion, TypeOps,
14+
InFiled, InferFailReason, LuaOperatorMetaMethod, LuaTypeCache, LuaTypeOwner, OperatorFunction,
15+
SignatureReturnStatus, TypeOps,
1816
};
1917

2018
use super::{
@@ -193,61 +191,19 @@ pub fn analyze_return_cast(analyzer: &mut DocAnalyzer, tag: LuaDocTagReturnCast)
193191
let name_token = tag.get_name_token()?;
194192
let name = name_token.get_name_text();
195193
let cast_op_type = tag.get_op_type()?;
196-
let action = match cast_op_type.get_op() {
197-
Some(op) => {
198-
if op.get_op() == BinaryOperator::OpAdd {
199-
CastAction::Add
200-
} else {
201-
CastAction::Remove
202-
}
203-
}
204-
None => CastAction::Force,
194+
if let Some(node_type) = cast_op_type.get_type() {
195+
let typ = infer_type(analyzer, node_type.clone());
196+
let infiled_syntax_id = InFiled::new(analyzer.file_id, node_type.get_syntax_id());
197+
let type_owner = LuaTypeOwner::SyntaxId(infiled_syntax_id);
198+
bind_type(analyzer.db, type_owner, LuaTypeCache::DocType(typ));
205199
};
206200

207-
if cast_op_type.is_nullable() {
208-
match action {
209-
CastAction::Add => {
210-
analyzer.db.get_flow_index_mut().add_call_cast(
211-
signature_id,
212-
name,
213-
TypeAssertion::Add(LuaType::Nil),
214-
);
215-
}
216-
CastAction::Remove => {
217-
analyzer.db.get_flow_index_mut().add_call_cast(
218-
signature_id,
219-
name,
220-
TypeAssertion::Remove(LuaType::Nil),
221-
);
222-
}
223-
_ => {}
224-
}
225-
} else if let Some(doc_type) = cast_op_type.get_type() {
226-
let typ = infer_type(analyzer, doc_type.clone());
227-
match action {
228-
CastAction::Add => {
229-
analyzer.db.get_flow_index_mut().add_call_cast(
230-
signature_id,
231-
name,
232-
TypeAssertion::Add(typ),
233-
);
234-
}
235-
CastAction::Remove => {
236-
analyzer.db.get_flow_index_mut().add_call_cast(
237-
signature_id,
238-
name,
239-
TypeAssertion::Remove(typ),
240-
);
241-
}
242-
CastAction::Force => {
243-
analyzer.db.get_flow_index_mut().add_call_cast(
244-
signature_id,
245-
name,
246-
TypeAssertion::Force(typ),
247-
);
248-
}
249-
}
250-
}
201+
analyzer.db.get_flow_index_mut().add_signature_cast(
202+
analyzer.file_id,
203+
signature_id,
204+
name.to_string(),
205+
cast_op_type.to_ptr(),
206+
);
251207
}
252208

253209
Some(())
@@ -354,13 +310,12 @@ pub fn analyze_cast(analyzer: &mut DocAnalyzer, tag: LuaDocTagCast) -> Option<()
354310
for op in tag.get_op_types() {
355311
if let Some(doc_type) = op.get_type() {
356312
let typ = infer_type(analyzer, doc_type.clone());
357-
analyzer.context.cast_flow.insert(
358-
InFiled {
359-
file_id: analyzer.file_id,
360-
value: doc_type.get_syntax_id(),
361-
},
362-
typ,
363-
);
313+
let type_owner =
314+
LuaTypeOwner::SyntaxId(InFiled::new(analyzer.file_id, doc_type.get_syntax_id()));
315+
analyzer
316+
.db
317+
.get_type_index_mut()
318+
.bind_type(type_owner, LuaTypeCache::DocType(typ));
364319
}
365320
}
366321
Some(())
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use emmylua_parser::{LuaAstNode, LuaComment, LuaDocTag};
2+
3+
use crate::{compilation::analyzer::flow::binder::FlowBinder, FlowId, FlowNodeKind};
4+
5+
pub fn bind_comment(binder: &mut FlowBinder, lua_comment: LuaComment, current: FlowId) -> FlowId {
6+
let cast_tags = lua_comment.get_doc_tags().filter_map(|it| match it {
7+
LuaDocTag::Cast(cast) => Some(cast),
8+
_ => None,
9+
});
10+
11+
let mut parent = current;
12+
for cast in cast_tags {
13+
let expr = cast.get_key_expr();
14+
if expr.is_some() {
15+
let flow_id = binder.create_node(FlowNodeKind::TagCast(cast.to_ptr()));
16+
binder.add_antecedent(flow_id, parent);
17+
parent = flow_id;
18+
} else {
19+
// inline cast
20+
let Some(owner) = lua_comment.get_owner() else {
21+
continue;
22+
};
23+
24+
let flow_id = binder.create_node(FlowNodeKind::TagCast(cast.to_ptr()));
25+
let bind_flow_id = binder.get_bind_flow(owner.get_syntax_id());
26+
if let Some(bind_flow) = bind_flow_id {
27+
binder.add_antecedent(flow_id, bind_flow);
28+
binder.bind_syntax_node(owner.get_syntax_id(), flow_id);
29+
} else {
30+
binder.add_antecedent(flow_id, parent);
31+
binder.bind_syntax_node(owner.get_syntax_id(), flow_id);
32+
}
33+
}
34+
}
35+
36+
parent
37+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use emmylua_parser::{BinaryOperator, LuaAst, LuaBinaryExpr, LuaExpr};
2+
3+
use crate::{
4+
compilation::analyzer::flow::{
5+
bind_analyze::{bind_each_child, exprs::bind_condition_expr, finish_flow_label},
6+
binder::FlowBinder,
7+
},
8+
FlowId,
9+
};
10+
11+
pub fn bind_binary_expr(
12+
binder: &mut FlowBinder,
13+
binary_expr: LuaBinaryExpr,
14+
current: FlowId,
15+
) -> Option<()> {
16+
let op_token = binary_expr.get_op_token()?;
17+
18+
match op_token.get_op() {
19+
BinaryOperator::OpAnd => bind_and_expr(binder, binary_expr, current),
20+
BinaryOperator::OpOr => bind_or_expr(binder, binary_expr, current),
21+
_ => {
22+
bind_each_child(binder, LuaAst::LuaBinaryExpr(binary_expr.clone()), current);
23+
Some(())
24+
}
25+
}
26+
}
27+
28+
fn bind_and_expr(
29+
binder: &mut FlowBinder,
30+
binary_expr: LuaBinaryExpr,
31+
current: FlowId,
32+
) -> Option<()> {
33+
let (left, right) = binary_expr.get_exprs()?;
34+
35+
let pre_right = binder.create_branch_label();
36+
bind_condition_expr(binder, left, current, pre_right, binder.false_target);
37+
let current = finish_flow_label(binder, pre_right, current);
38+
bind_condition_expr(
39+
binder,
40+
right,
41+
current,
42+
binder.true_target,
43+
binder.false_target,
44+
);
45+
46+
Some(())
47+
}
48+
49+
fn bind_or_expr(
50+
binder: &mut FlowBinder,
51+
binary_expr: LuaBinaryExpr,
52+
current: FlowId,
53+
) -> Option<()> {
54+
let (left, right) = binary_expr.get_exprs()?;
55+
let pre_right = binder.create_branch_label();
56+
bind_condition_expr(binder, left, current, binder.true_target, pre_right);
57+
let current = finish_flow_label(binder, pre_right, current);
58+
bind_condition_expr(
59+
binder,
60+
right,
61+
current,
62+
binder.true_target,
63+
binder.false_target,
64+
);
65+
Some(())
66+
}
67+
68+
pub fn is_binary_logical(expr: &LuaExpr) -> bool {
69+
match expr {
70+
LuaExpr::BinaryExpr(binary_expr) => {
71+
let Some(op_token) = binary_expr.get_op_token() else {
72+
return false;
73+
};
74+
75+
return match op_token.get_op() {
76+
BinaryOperator::OpAnd | BinaryOperator::OpOr => true,
77+
_ => false,
78+
};
79+
}
80+
LuaExpr::ParenExpr(paren_expr) => {
81+
if let Some(inner_expr) = paren_expr.get_expr() {
82+
return is_binary_logical(&inner_expr);
83+
}
84+
}
85+
_ => {}
86+
}
87+
false
88+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
mod bind_binary_expr;
2+
3+
use emmylua_parser::{
4+
LuaAst, LuaAstNode, LuaCallExpr, LuaClosureExpr, LuaExpr, LuaIndexExpr, LuaNameExpr,
5+
LuaTableExpr, LuaUnaryExpr,
6+
};
7+
8+
use crate::{
9+
compilation::analyzer::flow::{
10+
bind_analyze::{bind_each_child, exprs::bind_binary_expr::is_binary_logical},
11+
binder::FlowBinder,
12+
},
13+
FlowId, FlowNodeKind,
14+
};
15+
pub use bind_binary_expr::bind_binary_expr;
16+
17+
pub fn bind_condition_expr(
18+
binder: &mut FlowBinder,
19+
condition_expr: LuaExpr,
20+
current: FlowId,
21+
true_target: FlowId,
22+
false_target: FlowId,
23+
) {
24+
let old_true_target = binder.true_target;
25+
let old_false_target = binder.false_target;
26+
27+
binder.true_target = true_target;
28+
binder.false_target = false_target;
29+
bind_expr(binder, condition_expr.clone(), current);
30+
binder.true_target = old_true_target;
31+
binder.false_target = old_false_target;
32+
33+
if !is_binary_logical(&condition_expr) {
34+
let true_condition =
35+
binder.create_node(FlowNodeKind::TrueCondition(condition_expr.to_ptr()));
36+
binder.add_antecedent(true_condition, current);
37+
binder.add_antecedent(true_target, true_condition);
38+
39+
let false_condition =
40+
binder.create_node(FlowNodeKind::FalseCondition(condition_expr.to_ptr()));
41+
binder.add_antecedent(false_condition, current);
42+
binder.add_antecedent(false_target, false_condition);
43+
}
44+
}
45+
46+
pub fn bind_expr(binder: &mut FlowBinder, expr: LuaExpr, current: FlowId) -> FlowId {
47+
match expr {
48+
LuaExpr::NameExpr(name_expr) => bind_name_expr(binder, name_expr, current),
49+
LuaExpr::CallExpr(call_expr) => bind_call_expr(binder, call_expr, current),
50+
LuaExpr::TableExpr(table_expr) => bind_table_expr(binder, table_expr, current),
51+
LuaExpr::LiteralExpr(_) => Some(()), // Literal expressions do not need binding
52+
LuaExpr::ClosureExpr(closure_expr) => bind_closure_expr(binder, closure_expr, current),
53+
LuaExpr::ParenExpr(paren_expr) => bind_paren_expr(binder, paren_expr, current),
54+
LuaExpr::IndexExpr(index_expr) => bind_index_expr(binder, index_expr, current),
55+
LuaExpr::BinaryExpr(binary_expr) => bind_binary_expr(binder, binary_expr, current),
56+
LuaExpr::UnaryExpr(unary_expr) => bind_unary_expr(binder, unary_expr, current),
57+
};
58+
59+
current
60+
}
61+
62+
pub fn bind_name_expr(
63+
binder: &mut FlowBinder,
64+
name_expr: LuaNameExpr,
65+
current: FlowId,
66+
) -> Option<()> {
67+
binder.bind_syntax_node(name_expr.get_syntax_id(), current);
68+
Some(())
69+
}
70+
71+
pub fn bind_table_expr(
72+
binder: &mut FlowBinder,
73+
table_expr: LuaTableExpr,
74+
current: FlowId,
75+
) -> Option<()> {
76+
bind_each_child(binder, LuaAst::LuaTableExpr(table_expr), current);
77+
Some(())
78+
}
79+
80+
pub fn bind_closure_expr(
81+
binder: &mut FlowBinder,
82+
closure_expr: LuaClosureExpr,
83+
current: FlowId,
84+
) -> Option<()> {
85+
bind_each_child(binder, LuaAst::LuaClosureExpr(closure_expr), current);
86+
Some(())
87+
}
88+
89+
pub fn bind_index_expr(
90+
binder: &mut FlowBinder,
91+
index_expr: LuaIndexExpr,
92+
current: FlowId,
93+
) -> Option<()> {
94+
binder.bind_syntax_node(index_expr.get_syntax_id(), current);
95+
bind_each_child(binder, LuaAst::LuaIndexExpr(index_expr.clone()), current);
96+
Some(())
97+
}
98+
99+
pub fn bind_paren_expr(
100+
binder: &mut FlowBinder,
101+
paren_expr: emmylua_parser::LuaParenExpr,
102+
current: FlowId,
103+
) -> Option<()> {
104+
let Some(inner_expr) = paren_expr.get_expr() else {
105+
return None;
106+
};
107+
108+
bind_expr(binder, inner_expr, current);
109+
Some(())
110+
}
111+
112+
pub fn bind_unary_expr(
113+
binder: &mut FlowBinder,
114+
unary_expr: LuaUnaryExpr,
115+
current: FlowId,
116+
) -> Option<()> {
117+
let Some(inner_expr) = unary_expr.get_expr() else {
118+
return None;
119+
};
120+
bind_expr(binder, inner_expr, current);
121+
Some(())
122+
}
123+
124+
pub fn bind_call_expr(
125+
binder: &mut FlowBinder,
126+
call_expr: LuaCallExpr,
127+
current: FlowId,
128+
) -> Option<()> {
129+
bind_each_child(binder, LuaAst::LuaCallExpr(call_expr.clone()), current);
130+
Some(())
131+
}

0 commit comments

Comments
 (0)