mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
fix(oxc_semantic): Handle short-circuiting operators in CFG (#2252)
Closes #2239
This commit is contained in:
parent
27681951e1
commit
f4674f33b2
13 changed files with 253 additions and 43 deletions
|
|
@ -666,6 +666,73 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
self.leave_node(kind);
|
self.leave_node(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_logical_expression(&mut self, expr: &LogicalExpression<'a>) {
|
||||||
|
// logical expressions are short-circuiting, and therefore
|
||||||
|
// also represent control flow.
|
||||||
|
// For example, in:
|
||||||
|
// foo && bar();
|
||||||
|
// the bar() call will only be executed if foo is truthy.
|
||||||
|
let kind = AstKind::LogicalExpression(self.alloc(expr));
|
||||||
|
self.enter_node(kind);
|
||||||
|
|
||||||
|
self.visit_expression(&expr.left);
|
||||||
|
|
||||||
|
/* cfg */
|
||||||
|
let left_expr_end_ix = self.cfg.current_node_ix;
|
||||||
|
let right_expr_start_ix = self.cfg.new_basic_block();
|
||||||
|
/* cfg */
|
||||||
|
|
||||||
|
self.visit_expression(&expr.right);
|
||||||
|
|
||||||
|
/* cfg */
|
||||||
|
let right_expr_end_ix = self.cfg.current_node_ix;
|
||||||
|
let after_logical_expr_ix = self.cfg.new_basic_block();
|
||||||
|
|
||||||
|
self.cfg.add_edge(left_expr_end_ix, right_expr_start_ix, EdgeType::Normal);
|
||||||
|
self.cfg.add_edge(left_expr_end_ix, after_logical_expr_ix, EdgeType::Normal);
|
||||||
|
self.cfg.add_edge(right_expr_end_ix, after_logical_expr_ix, EdgeType::Normal);
|
||||||
|
/* cfg */
|
||||||
|
|
||||||
|
self.leave_node(kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_assignment_expression(&mut self, expr: &AssignmentExpression<'a>) {
|
||||||
|
// assignment expressions can include an operator, which
|
||||||
|
// can be used to determine the control flow of the expression.
|
||||||
|
// For example, in:
|
||||||
|
// foo &&= super();
|
||||||
|
// the super() call will only be executed if foo is truthy.
|
||||||
|
|
||||||
|
let kind = AstKind::AssignmentExpression(self.alloc(expr));
|
||||||
|
self.enter_node(kind);
|
||||||
|
self.visit_assignment_target(&expr.left);
|
||||||
|
|
||||||
|
/* cfg */
|
||||||
|
let cfg_ixs = if expr.operator.is_logical() {
|
||||||
|
let target_end_ix = self.cfg.current_node_ix;
|
||||||
|
let expr_start_ix = self.cfg.new_basic_block();
|
||||||
|
Some((target_end_ix, expr_start_ix))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
/* cfg */
|
||||||
|
|
||||||
|
self.visit_expression(&expr.right);
|
||||||
|
|
||||||
|
/* cfg */
|
||||||
|
if let Some((target_end_ix, expr_start_ix)) = cfg_ixs {
|
||||||
|
let expr_end_ix = self.cfg.current_node_ix;
|
||||||
|
let after_assignment_ix = self.cfg.new_basic_block();
|
||||||
|
|
||||||
|
self.cfg.add_edge(target_end_ix, expr_start_ix, EdgeType::Normal);
|
||||||
|
self.cfg.add_edge(target_end_ix, after_assignment_ix, EdgeType::Normal);
|
||||||
|
self.cfg.add_edge(expr_end_ix, after_assignment_ix, EdgeType::Normal);
|
||||||
|
}
|
||||||
|
/* cfg */
|
||||||
|
|
||||||
|
self.leave_node(kind);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_for_statement(&mut self, stmt: &ForStatement<'a>) {
|
fn visit_for_statement(&mut self, stmt: &ForStatement<'a>) {
|
||||||
let kind = AstKind::ForStatement(self.alloc(stmt));
|
let kind = AstKind::ForStatement(self.alloc(stmt));
|
||||||
let is_lexical_declaration =
|
let is_lexical_declaration =
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,20 @@ input_file: crates/oxc_semantic/tests/cfg_fixtures/assignment_operators.js
|
||||||
---
|
---
|
||||||
digraph {
|
digraph {
|
||||||
0 [ label = ""]
|
0 [ label = ""]
|
||||||
|
1 [ label = ""]
|
||||||
|
2 [ label = ""]
|
||||||
|
3 [ label = ""]
|
||||||
|
4 [ label = ""]
|
||||||
|
5 [ label = ""]
|
||||||
|
6 [ label = ""]
|
||||||
|
0 -> 1 [ ]
|
||||||
|
0 -> 2 [ ]
|
||||||
|
1 -> 2 [ ]
|
||||||
|
2 -> 3 [ ]
|
||||||
|
2 -> 4 [ ]
|
||||||
|
3 -> 4 [ ]
|
||||||
|
4 -> 5 [ ]
|
||||||
|
4 -> 6 [ ]
|
||||||
|
5 -> 6 [ ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,27 @@ input_file: crates/oxc_semantic/tests/cfg_fixtures/assignment_operators.js
|
||||||
bb0: {
|
bb0: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb3: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb6: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@ digraph {
|
||||||
20 [ label = ""]
|
20 [ label = ""]
|
||||||
21 [ label = ""]
|
21 [ label = ""]
|
||||||
22 [ label = ""]
|
22 [ label = ""]
|
||||||
|
23 [ label = ""]
|
||||||
|
24 [ label = ""]
|
||||||
|
25 [ label = ""]
|
||||||
|
26 [ label = ""]
|
||||||
0 -> 1 [ ]
|
0 -> 1 [ ]
|
||||||
0 -> 2 [ ]
|
0 -> 2 [ ]
|
||||||
2 -> 3 [ ]
|
2 -> 3 [ ]
|
||||||
|
|
@ -45,9 +49,15 @@ digraph {
|
||||||
14 -> 16 [ ]
|
14 -> 16 [ ]
|
||||||
16 -> 17 [ ]
|
16 -> 17 [ ]
|
||||||
16 -> 18 [ ]
|
16 -> 18 [ ]
|
||||||
|
17 -> 18 [ ]
|
||||||
18 -> 19 [ ]
|
18 -> 19 [ ]
|
||||||
18 -> 20 [ ]
|
18 -> 20 [ ]
|
||||||
20 -> 21 [ ]
|
20 -> 21 [ ]
|
||||||
20 -> 22 [ ]
|
20 -> 22 [ ]
|
||||||
|
21 -> 22 [ ]
|
||||||
|
22 -> 23 [ ]
|
||||||
|
22 -> 24 [ ]
|
||||||
|
24 -> 25 [ ]
|
||||||
|
24 -> 26 [ ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,3 +94,19 @@ bb21: {
|
||||||
bb22: {
|
bb22: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb23: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb24: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb25: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb26: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,26 +6,31 @@ input_file: crates/oxc_semantic/tests/cfg_fixtures/if_else.js
|
||||||
digraph {
|
digraph {
|
||||||
0 [ label = ""]
|
0 [ label = ""]
|
||||||
1 [ label = ""]
|
1 [ label = ""]
|
||||||
2 [ label = "$return = <value>"]
|
2 [ label = ""]
|
||||||
3 [ label = ""]
|
3 [ label = ""]
|
||||||
4 [ label = "Unreachable()"]
|
4 [ label = "$return = <value>"]
|
||||||
5 [ label = "$return = <value>"]
|
5 [ label = ""]
|
||||||
6 [ label = ""]
|
6 [ label = "Unreachable()"]
|
||||||
7 [ label = "Unreachable()"]
|
7 [ label = "$return = <value>"]
|
||||||
8 [ label = ""]
|
8 [ label = ""]
|
||||||
9 [ label = "Unreachable()\n$return = <value>"]
|
9 [ label = "Unreachable()"]
|
||||||
10 [ label = ""]
|
10 [ label = ""]
|
||||||
11 [ label = "Unreachable()"]
|
11 [ label = "Unreachable()\n$return = <value>"]
|
||||||
12 [ label = ""]
|
12 [ label = ""]
|
||||||
|
13 [ label = "Unreachable()"]
|
||||||
|
14 [ label = ""]
|
||||||
0 -> 1 [ ]
|
0 -> 1 [ ]
|
||||||
3 -> 4 [ ]
|
|
||||||
6 -> 7 [ ]
|
|
||||||
8 -> 9 [ ]
|
|
||||||
4 -> 8 [ ]
|
|
||||||
1 -> 2 [ ]
|
1 -> 2 [ ]
|
||||||
1 -> 5 [ ]
|
1 -> 3 [ ]
|
||||||
7 -> 8 [ ]
|
2 -> 3 [ ]
|
||||||
|
5 -> 6 [ ]
|
||||||
|
8 -> 9 [ ]
|
||||||
10 -> 11 [ ]
|
10 -> 11 [ ]
|
||||||
0 -> 12 [ ]
|
6 -> 10 [ ]
|
||||||
|
3 -> 4 [ ]
|
||||||
|
3 -> 7 [ ]
|
||||||
|
9 -> 10 [ ]
|
||||||
|
12 -> 13 [ ]
|
||||||
|
0 -> 14 [ ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ bb1: {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
$return = <value>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
|
|
@ -20,28 +20,27 @@ bb3: {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
Unreachable()
|
|
||||||
}
|
|
||||||
|
|
||||||
bb5: {
|
|
||||||
$return = <value>
|
$return = <value>
|
||||||
}
|
}
|
||||||
|
|
||||||
bb6: {
|
bb5: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb7: {
|
bb6: {
|
||||||
Unreachable()
|
Unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb7: {
|
||||||
|
$return = <value>
|
||||||
|
}
|
||||||
|
|
||||||
bb8: {
|
bb8: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb9: {
|
bb9: {
|
||||||
Unreachable()
|
Unreachable()
|
||||||
$return = <value>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb10: {
|
bb10: {
|
||||||
|
|
@ -50,8 +49,17 @@ bb10: {
|
||||||
|
|
||||||
bb11: {
|
bb11: {
|
||||||
Unreachable()
|
Unreachable()
|
||||||
|
$return = <value>
|
||||||
}
|
}
|
||||||
|
|
||||||
bb12: {
|
bb12: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb13: {
|
||||||
|
Unreachable()
|
||||||
|
}
|
||||||
|
|
||||||
|
bb14: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,10 @@ input_file: crates/oxc_semantic/tests/cfg_fixtures/infix_operators.js
|
||||||
---
|
---
|
||||||
digraph {
|
digraph {
|
||||||
0 [ label = ""]
|
0 [ label = ""]
|
||||||
|
1 [ label = ""]
|
||||||
|
2 [ label = ""]
|
||||||
|
0 -> 1 [ ]
|
||||||
|
0 -> 2 [ ]
|
||||||
|
1 -> 2 [ ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,11 @@ input_file: crates/oxc_semantic/tests/cfg_fixtures/infix_operators.js
|
||||||
bb0: {
|
bb0: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,29 @@ digraph {
|
||||||
4 [ label = ""]
|
4 [ label = ""]
|
||||||
5 [ label = ""]
|
5 [ label = ""]
|
||||||
6 [ label = ""]
|
6 [ label = ""]
|
||||||
1 -> 2 [ ]
|
7 [ label = ""]
|
||||||
|
8 [ label = ""]
|
||||||
|
9 [ label = ""]
|
||||||
|
10 [ label = ""]
|
||||||
|
11 [ label = ""]
|
||||||
|
12 [ label = ""]
|
||||||
0 -> 1 [ ]
|
0 -> 1 [ ]
|
||||||
0 -> 2 [ ]
|
0 -> 2 [ ]
|
||||||
|
1 -> 2 [ ]
|
||||||
3 -> 4 [ ]
|
3 -> 4 [ ]
|
||||||
2 -> 3 [ ]
|
2 -> 3 [ ]
|
||||||
2 -> 4 [ ]
|
2 -> 4 [ ]
|
||||||
5 -> 6 [ ]
|
|
||||||
4 -> 5 [ ]
|
4 -> 5 [ ]
|
||||||
4 -> 6 [ ]
|
4 -> 6 [ ]
|
||||||
|
5 -> 6 [ ]
|
||||||
|
7 -> 8 [ ]
|
||||||
|
6 -> 7 [ ]
|
||||||
|
6 -> 8 [ ]
|
||||||
|
8 -> 9 [ ]
|
||||||
|
8 -> 10 [ ]
|
||||||
|
9 -> 10 [ ]
|
||||||
|
11 -> 12 [ ]
|
||||||
|
10 -> 11 [ ]
|
||||||
|
10 -> 12 [ ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,3 +30,27 @@ bb5: {
|
||||||
bb6: {
|
bb6: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb7: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb8: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb9: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb10: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb11: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bb12: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,21 +7,26 @@ digraph {
|
||||||
0 [ label = ""]
|
0 [ label = ""]
|
||||||
1 [ label = ""]
|
1 [ label = ""]
|
||||||
2 [ label = ""]
|
2 [ label = ""]
|
||||||
3 [ label = "$return = <value>"]
|
3 [ label = ""]
|
||||||
4 [ label = ""]
|
4 [ label = ""]
|
||||||
5 [ label = "Unreachable()"]
|
5 [ label = "$return = <value>"]
|
||||||
6 [ label = "$return = <value>"]
|
6 [ label = ""]
|
||||||
7 [ label = ""]
|
7 [ label = "Unreachable()"]
|
||||||
8 [ label = "Unreachable()"]
|
8 [ label = "$return = <value>"]
|
||||||
9 [ label = ""]
|
9 [ label = ""]
|
||||||
|
10 [ label = "Unreachable()"]
|
||||||
|
11 [ label = ""]
|
||||||
0 -> 1 [ ]
|
0 -> 1 [ ]
|
||||||
4 -> 5 [ ]
|
|
||||||
1 -> 2 [ ]
|
|
||||||
2 -> 3 [ ]
|
2 -> 3 [ ]
|
||||||
3 -> 6 [ ]
|
2 -> 4 [ ]
|
||||||
3 -> 2 [ ]
|
3 -> 4 [ ]
|
||||||
2 -> 6 [ ]
|
6 -> 7 [ ]
|
||||||
7 -> 8 [ ]
|
1 -> 2 [ ]
|
||||||
0 -> 9 [ ]
|
2 -> 5 [ ]
|
||||||
|
5 -> 8 [ ]
|
||||||
|
5 -> 2 [ ]
|
||||||
|
2 -> 8 [ ]
|
||||||
|
9 -> 10 [ ]
|
||||||
|
0 -> 11 [ ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ bb2: {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
$return = <value>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
|
|
@ -24,21 +24,29 @@ bb4: {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb5: {
|
bb5: {
|
||||||
Unreachable()
|
|
||||||
}
|
|
||||||
|
|
||||||
bb6: {
|
|
||||||
$return = <value>
|
$return = <value>
|
||||||
}
|
}
|
||||||
|
|
||||||
bb7: {
|
bb6: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb8: {
|
bb7: {
|
||||||
Unreachable()
|
Unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb8: {
|
||||||
|
$return = <value>
|
||||||
|
}
|
||||||
|
|
||||||
bb9: {
|
bb9: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb10: {
|
||||||
|
Unreachable()
|
||||||
|
}
|
||||||
|
|
||||||
|
bb11: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue