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);
|
||||
}
|
||||
|
||||
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>) {
|
||||
let kind = AstKind::ForStatement(self.alloc(stmt));
|
||||
let is_lexical_declaration =
|
||||
|
|
|
|||
|
|
@ -5,5 +5,20 @@ input_file: crates/oxc_semantic/tests/cfg_fixtures/assignment_operators.js
|
|||
---
|
||||
digraph {
|
||||
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: {
|
||||
|
||||
}
|
||||
|
||||
bb1: {
|
||||
|
||||
}
|
||||
|
||||
bb2: {
|
||||
|
||||
}
|
||||
|
||||
bb3: {
|
||||
|
||||
}
|
||||
|
||||
bb4: {
|
||||
|
||||
}
|
||||
|
||||
bb5: {
|
||||
|
||||
}
|
||||
|
||||
bb6: {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ digraph {
|
|||
20 [ label = ""]
|
||||
21 [ label = ""]
|
||||
22 [ label = ""]
|
||||
23 [ label = ""]
|
||||
24 [ label = ""]
|
||||
25 [ label = ""]
|
||||
26 [ label = ""]
|
||||
0 -> 1 [ ]
|
||||
0 -> 2 [ ]
|
||||
2 -> 3 [ ]
|
||||
|
|
@ -45,9 +49,15 @@ digraph {
|
|||
14 -> 16 [ ]
|
||||
16 -> 17 [ ]
|
||||
16 -> 18 [ ]
|
||||
17 -> 18 [ ]
|
||||
18 -> 19 [ ]
|
||||
18 -> 20 [ ]
|
||||
20 -> 21 [ ]
|
||||
20 -> 22 [ ]
|
||||
21 -> 22 [ ]
|
||||
22 -> 23 [ ]
|
||||
22 -> 24 [ ]
|
||||
24 -> 25 [ ]
|
||||
24 -> 26 [ ]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,3 +94,19 @@ bb21: {
|
|||
bb22: {
|
||||
|
||||
}
|
||||
|
||||
bb23: {
|
||||
|
||||
}
|
||||
|
||||
bb24: {
|
||||
|
||||
}
|
||||
|
||||
bb25: {
|
||||
|
||||
}
|
||||
|
||||
bb26: {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,26 +6,31 @@ input_file: crates/oxc_semantic/tests/cfg_fixtures/if_else.js
|
|||
digraph {
|
||||
0 [ label = ""]
|
||||
1 [ label = ""]
|
||||
2 [ label = "$return = <value>"]
|
||||
2 [ label = ""]
|
||||
3 [ label = ""]
|
||||
4 [ label = "Unreachable()"]
|
||||
5 [ label = "$return = <value>"]
|
||||
6 [ label = ""]
|
||||
7 [ label = "Unreachable()"]
|
||||
4 [ label = "$return = <value>"]
|
||||
5 [ label = ""]
|
||||
6 [ label = "Unreachable()"]
|
||||
7 [ label = "$return = <value>"]
|
||||
8 [ label = ""]
|
||||
9 [ label = "Unreachable()\n$return = <value>"]
|
||||
9 [ label = "Unreachable()"]
|
||||
10 [ label = ""]
|
||||
11 [ label = "Unreachable()"]
|
||||
11 [ label = "Unreachable()\n$return = <value>"]
|
||||
12 [ label = ""]
|
||||
13 [ label = "Unreachable()"]
|
||||
14 [ label = ""]
|
||||
0 -> 1 [ ]
|
||||
3 -> 4 [ ]
|
||||
6 -> 7 [ ]
|
||||
8 -> 9 [ ]
|
||||
4 -> 8 [ ]
|
||||
1 -> 2 [ ]
|
||||
1 -> 5 [ ]
|
||||
7 -> 8 [ ]
|
||||
1 -> 3 [ ]
|
||||
2 -> 3 [ ]
|
||||
5 -> 6 [ ]
|
||||
8 -> 9 [ ]
|
||||
10 -> 11 [ ]
|
||||
0 -> 12 [ ]
|
||||
6 -> 10 [ ]
|
||||
3 -> 4 [ ]
|
||||
3 -> 7 [ ]
|
||||
9 -> 10 [ ]
|
||||
12 -> 13 [ ]
|
||||
0 -> 14 [ ]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ bb1: {
|
|||
}
|
||||
|
||||
bb2: {
|
||||
$return = <value>
|
||||
|
||||
}
|
||||
|
||||
bb3: {
|
||||
|
|
@ -20,28 +20,27 @@ bb3: {
|
|||
}
|
||||
|
||||
bb4: {
|
||||
Unreachable()
|
||||
}
|
||||
|
||||
bb5: {
|
||||
$return = <value>
|
||||
}
|
||||
|
||||
bb6: {
|
||||
bb5: {
|
||||
|
||||
}
|
||||
|
||||
bb7: {
|
||||
bb6: {
|
||||
Unreachable()
|
||||
}
|
||||
|
||||
bb7: {
|
||||
$return = <value>
|
||||
}
|
||||
|
||||
bb8: {
|
||||
|
||||
}
|
||||
|
||||
bb9: {
|
||||
Unreachable()
|
||||
$return = <value>
|
||||
}
|
||||
|
||||
bb10: {
|
||||
|
|
@ -50,8 +49,17 @@ bb10: {
|
|||
|
||||
bb11: {
|
||||
Unreachable()
|
||||
$return = <value>
|
||||
}
|
||||
|
||||
bb12: {
|
||||
|
||||
}
|
||||
|
||||
bb13: {
|
||||
Unreachable()
|
||||
}
|
||||
|
||||
bb14: {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,5 +5,10 @@ input_file: crates/oxc_semantic/tests/cfg_fixtures/infix_operators.js
|
|||
---
|
||||
digraph {
|
||||
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: {
|
||||
|
||||
}
|
||||
|
||||
bb1: {
|
||||
|
||||
}
|
||||
|
||||
bb2: {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,14 +11,29 @@ digraph {
|
|||
4 [ label = ""]
|
||||
5 [ label = ""]
|
||||
6 [ label = ""]
|
||||
1 -> 2 [ ]
|
||||
7 [ label = ""]
|
||||
8 [ label = ""]
|
||||
9 [ label = ""]
|
||||
10 [ label = ""]
|
||||
11 [ label = ""]
|
||||
12 [ label = ""]
|
||||
0 -> 1 [ ]
|
||||
0 -> 2 [ ]
|
||||
1 -> 2 [ ]
|
||||
3 -> 4 [ ]
|
||||
2 -> 3 [ ]
|
||||
2 -> 4 [ ]
|
||||
5 -> 6 [ ]
|
||||
4 -> 5 [ ]
|
||||
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: {
|
||||
|
||||
}
|
||||
|
||||
bb7: {
|
||||
|
||||
}
|
||||
|
||||
bb8: {
|
||||
|
||||
}
|
||||
|
||||
bb9: {
|
||||
|
||||
}
|
||||
|
||||
bb10: {
|
||||
|
||||
}
|
||||
|
||||
bb11: {
|
||||
|
||||
}
|
||||
|
||||
bb12: {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,21 +7,26 @@ digraph {
|
|||
0 [ label = ""]
|
||||
1 [ label = ""]
|
||||
2 [ label = ""]
|
||||
3 [ label = "$return = <value>"]
|
||||
3 [ label = ""]
|
||||
4 [ label = ""]
|
||||
5 [ label = "Unreachable()"]
|
||||
6 [ label = "$return = <value>"]
|
||||
7 [ label = ""]
|
||||
8 [ label = "Unreachable()"]
|
||||
5 [ label = "$return = <value>"]
|
||||
6 [ label = ""]
|
||||
7 [ label = "Unreachable()"]
|
||||
8 [ label = "$return = <value>"]
|
||||
9 [ label = ""]
|
||||
10 [ label = "Unreachable()"]
|
||||
11 [ label = ""]
|
||||
0 -> 1 [ ]
|
||||
4 -> 5 [ ]
|
||||
1 -> 2 [ ]
|
||||
2 -> 3 [ ]
|
||||
3 -> 6 [ ]
|
||||
3 -> 2 [ ]
|
||||
2 -> 6 [ ]
|
||||
7 -> 8 [ ]
|
||||
0 -> 9 [ ]
|
||||
2 -> 4 [ ]
|
||||
3 -> 4 [ ]
|
||||
6 -> 7 [ ]
|
||||
1 -> 2 [ ]
|
||||
2 -> 5 [ ]
|
||||
5 -> 8 [ ]
|
||||
5 -> 2 [ ]
|
||||
2 -> 8 [ ]
|
||||
9 -> 10 [ ]
|
||||
0 -> 11 [ ]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ bb2: {
|
|||
}
|
||||
|
||||
bb3: {
|
||||
$return = <value>
|
||||
|
||||
}
|
||||
|
||||
bb4: {
|
||||
|
|
@ -24,21 +24,29 @@ bb4: {
|
|||
}
|
||||
|
||||
bb5: {
|
||||
Unreachable()
|
||||
}
|
||||
|
||||
bb6: {
|
||||
$return = <value>
|
||||
}
|
||||
|
||||
bb7: {
|
||||
bb6: {
|
||||
|
||||
}
|
||||
|
||||
bb8: {
|
||||
bb7: {
|
||||
Unreachable()
|
||||
}
|
||||
|
||||
bb8: {
|
||||
$return = <value>
|
||||
}
|
||||
|
||||
bb9: {
|
||||
|
||||
}
|
||||
|
||||
bb10: {
|
||||
Unreachable()
|
||||
}
|
||||
|
||||
bb11: {
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue