Skip to content

Commit

Permalink
feat(semantic/cfg): add Condition instruction.
Browse files Browse the repository at this point in the history
  • Loading branch information
rzvxa committed Jun 6, 2024
1 parent b282f27 commit 9fa95b0
Show file tree
Hide file tree
Showing 26 changed files with 84 additions and 37 deletions.
1 change: 1 addition & 0 deletions crates/oxc_linter/src/rules/eslint/getter_return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ impl GetterReturn {
| InstructionKind::Break(_)
| InstructionKind::Continue(_)
| InstructionKind::Iteration(_)
| InstructionKind::Condition
| InstructionKind::Statement => {}
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/oxc_linter/src/rules/react/require_render_return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ fn contains_return_statement<'a>(node: &AstNode<'a>, ctx: &LintContext<'a>) -> b
| InstructionKind::Break(_)
| InstructionKind::Continue(_)
| InstructionKind::Iteration(_)
| InstructionKind::Condition
| InstructionKind::Statement => {}
}
}
Expand Down
19 changes: 17 additions & 2 deletions crates/oxc_semantic/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,10 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
let start_of_condition_graph_ix = self.cfg.new_basic_block_normal();
/* cfg */

self.record_ast_nodes();
self.visit_expression(&stmt.test);
let test_node = self.retrieve_recorded_ast_nodes().into_iter().next();
self.cfg.append_condition(test_node);

/* cfg */
let end_of_condition_graph_ix = self.cfg.current_node_ix;
Expand Down Expand Up @@ -675,7 +678,10 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
let kind = AstKind::ConditionalExpression(self.alloc(expr));
self.enter_node(kind);

self.record_ast_nodes();
self.visit_expression(&expr.test);
let test_node = self.retrieve_recorded_ast_nodes().into_iter().next();
self.cfg.append_condition(test_node);

/* cfg */
let before_conditional_expr_graph_ix = self.cfg.current_node_ix;
Expand Down Expand Up @@ -706,7 +712,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
self.cfg.add_edge(
before_conditional_expr_graph_ix,
before_consequent_expr_graph_ix,
EdgeType::Normal,
EdgeType::Jump,
);

self.cfg.add_edge(
Expand Down Expand Up @@ -735,7 +741,10 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
let test_graph_ix = self.cfg.new_basic_block_normal();
/* cfg */
if let Some(test) = &stmt.test {
self.record_ast_nodes();
self.visit_expression(test);
let test_node = self.retrieve_recorded_ast_nodes().into_iter().next();
self.cfg.append_condition(test_node);
}

/* cfg */
Expand Down Expand Up @@ -932,7 +941,10 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
let kind = AstKind::IfStatement(self.alloc(stmt));
self.enter_node(kind);

self.record_ast_nodes();
self.visit_expression(&stmt.test);
let test_node = self.retrieve_recorded_ast_nodes().into_iter().next();
self.cfg.append_condition(test_node);

/* cfg */
let before_if_stmt_graph_ix = self.cfg.current_node_ix;
Expand Down Expand Up @@ -965,7 +977,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
self.cfg.add_edge(
before_if_stmt_graph_ix,
before_consequent_stmt_graph_ix,
EdgeType::Normal,
EdgeType::Jump,
);

if let Some((start_of_alternate_stmt_graph_ix, after_alternate_stmt_graph_ix)) =
Expand Down Expand Up @@ -1278,7 +1290,10 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
let condition_graph_ix = self.cfg.new_basic_block_normal();
/* cfg */

self.record_ast_nodes();
self.visit_expression(&stmt.test);
let test_node = self.retrieve_recorded_ast_nodes().into_iter().next();
self.cfg.append_condition(test_node);

/* cfg - body basic block */
let body_graph_ix = self.cfg.new_basic_block_normal();
Expand Down
4 changes: 4 additions & 0 deletions crates/oxc_semantic/src/control_flow/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ impl<'a> ControlFlowGraphBuilder<'a> {
);
}

pub fn append_condition(&mut self, node: Option<AstNodeId>) {
self.push_instruction(InstructionKind::Condition, node);
}

pub fn append_iteration(&mut self, node: Option<AstNodeId>, kind: IterationInstructionKind) {
self.push_instruction(InstructionKind::Iteration(kind), node);
}
Expand Down
22 changes: 20 additions & 2 deletions crates/oxc_semantic/src/control_flow/dot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ impl<'a, 'b> DebugDotContext<'a, 'b> {
fn debug_ast_kind(self, id: AstNodeId) -> String {
self.0.kind(id).debug_name().into_owned()
}

fn try_eval_literal(self, id: AstNodeId) -> Option<String> {
match self.0.kind(id) {
AstKind::NumericLiteral(lit) => Some(lit.value.to_string()),
AstKind::BooleanLiteral(lit) => Some(lit.value.to_string()),
AstKind::StringLiteral(lit) => Some(lit.value.to_string()),
AstKind::BigintLiteral(lit) => Some(lit.raw.to_string()),
AstKind::NullLiteral(_) => Some("null".to_string()),
_ => None,
}
}
}

impl<'a, 'b> From<&'b AstNodes<'a>> for DebugDotContext<'a, 'b> {
Expand Down Expand Up @@ -76,12 +87,13 @@ impl DisplayDot for Instruction {
InstructionKind::Statement => "statement",
InstructionKind::Unreachable => "unreachable",
InstructionKind::Throw => "throw",
InstructionKind::Condition => "condition",
InstructionKind::Iteration(IterationInstructionKind::Of) => "iteration <of>",
InstructionKind::Iteration(IterationInstructionKind::In) => "iteration <in>",
InstructionKind::Break(LabeledInstruction::Labeled) => "break <label>",
InstructionKind::Break(LabeledInstruction::Unlabeled) => "break",
InstructionKind::Continue(LabeledInstruction::Labeled) => "continue <label>",
InstructionKind::Continue(LabeledInstruction::Unlabeled) => "continue",
InstructionKind::Iteration(IterationInstructionKind::Of) => "iteration <of>",
InstructionKind::Iteration(IterationInstructionKind::In) => "iteration <in>",
InstructionKind::Return(ReturnInstructionKind::ImplicitUndefined) => {
"return <implicit undefined>"
}
Expand Down Expand Up @@ -136,6 +148,12 @@ impl DebugDot for Instruction {
}
InstructionKind::Unreachable => "unreachable".to_string(),
InstructionKind::Throw => "throw".to_string(),
InstructionKind::Condition => self.node_id.map_or("None".to_string(), |id| {
format!(
"Condition({})",
ctx.try_eval_literal(id).unwrap_or_else(|| ctx.debug_ast_kind(id))
)
}),
InstructionKind::Iteration(ref kind) => {
format!(
"Iteration({} {} {})",
Expand Down
9 changes: 6 additions & 3 deletions crates/oxc_semantic/src/control_flow/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
mod builder;
mod dot;

use itertools::Itertools;
use oxc_ast::AstKind;
use oxc_span::CompactStr;
use oxc_syntax::operator::{
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
};
use petgraph::{
stable_graph::NodeIndex,
visit::{depth_first_search, Control, DfsEvent},
Graph,
visit::{depth_first_search, Control, DfsEvent, EdgeRef},
Direction, Graph,
};

use crate::AstNodeId;
use crate::{AstNodeId, AstNodes};

pub use builder::{ControlFlowGraphBuilder, CtxCursor, CtxFlags};
pub use dot::{DebugDot, DebugDotContext, DisplayDot};
Expand Down Expand Up @@ -148,6 +150,7 @@ pub enum InstructionKind {
Break(LabeledInstruction),
Continue(LabeledInstruction),
Throw,
Condition,
Iteration(IterationInstructionKind),
}
#[derive(Debug, Clone)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ digraph {
0 [ label = "" ]
1 [ label = "VariableDeclaration" ]
2 [ label = "" ]
3 [ label = "ExpressionStatement" ]
3 [ label = "ExpressionStatement\nCondition(CallExpression)" ]
4 [ label = "" ]
5 [ label = "" ]
6 [ label = "" ]
Expand All @@ -18,7 +18,7 @@ digraph {
5 -> 2 [ label = "Error(Implicit)" ]
6 -> 2 [ label = "Error(Implicit)" ]
4 -> 6 [ label = "Normal" ]
3 -> 4 [ label = "Normal" ]
3 -> 4 [ label = "Jump" ]
3 -> 5 [ label = "Normal" ]
5 -> 6 [ label = "Normal" ]
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ bb2: {

bb3: {
statement
condition
}

bb4: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ input_file: crates/oxc_semantic/tests/integration/cfg_fixtures/conditional_expre
---
digraph {
0 [ label = "" ]
1 [ label = "VariableDeclaration" ]
1 [ label = "VariableDeclaration\nCondition(CallExpression)" ]
2 [ label = "" ]
3 [ label = "" ]
4 [ label = "VariableDeclaration" ]
Expand All @@ -14,7 +14,7 @@ digraph {
3 -> 0 [ label = "Error(Implicit)" ]
4 -> 0 [ label = "Error(Implicit)" ]
2 -> 4 [ label = "Normal" ]
1 -> 2 [ label = "Normal" ]
1 -> 2 [ label = "Jump" ]
1 -> 3 [ label = "Normal" ]
3 -> 4 [ label = "Normal" ]
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ bb0: {

bb1: {
statement
condition
}

bb2: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ digraph {
6 [ label = "DoWhileStatement" ]
7 [ label = "BlockStatement\nbreak" ]
8 [ label = "unreachable" ]
9 [ label = "" ]
9 [ label = "Condition(true)" ]
10 [ label = "" ]
11 [ label = "" ]
12 [ label = "" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ bb8: {
}

bb9: {

condition
}

bb10: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ digraph {
1 [ label = "" ]
2 [ label = "" ]
3 [ label = "ForStatement\nVariableDeclaration" ]
4 [ label = "" ]
4 [ label = "Condition(test)" ]
5 [ label = "" ]
6 [ label = "ExpressionStatement" ]
7 [ label = "ExpressionStatement" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ bb3: {
}

bb4: {

condition
}

bb5: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ digraph {
2 [ label = "" ]
3 [ label = "IfStatement" ]
4 [ label = "" ]
5 [ label = "" ]
5 [ label = "Condition(LogicalExpression)" ]
6 [ label = "BlockStatement\nreturn <value>" ]
7 [ label = "unreachable" ]
8 [ label = "BlockStatement\nreturn <value>" ]
Expand All @@ -33,7 +33,7 @@ digraph {
8 -> 9 [ label = "Unreachable" , style = "dotted" ]
10 -> 2 [ label = "Error(Implicit)" ]
7 -> 10 [ label = "Normal" ]
5 -> 6 [ label = "Normal" ]
5 -> 6 [ label = "Jump" ]
5 -> 8 [ label = "Normal" ]
9 -> 10 [ label = "Normal" ]
11 -> 2 [ label = "Error(Implicit)" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ bb4: {
}

bb5: {

condition
}

bb6: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ digraph {
3 [ label = "ForInStatement\nVariableDeclaration" ]
4 [ label = "" ]
5 [ label = "Iteration(IdentifierReference(array) in expr)" ]
6 [ label = "BlockStatement\nIfStatement" ]
6 [ label = "BlockStatement\nIfStatement\nCondition(if cond)" ]
7 [ label = "BlockStatement\nExpressionStatement\nbreak" ]
8 [ label = "unreachable" ]
9 [ label = "IfStatement" ]
9 [ label = "IfStatement\nCondition(else cond)" ]
10 [ label = "BlockStatement\nExpressionStatement\ncontinue" ]
11 [ label = "unreachable" ]
12 [ label = "" ]
Expand All @@ -35,11 +35,11 @@ digraph {
10 -> 11 [ label = "Unreachable" , style = "dotted" ]
12 -> 2 [ label = "Error(Implicit)" ]
11 -> 12 [ label = "Normal" ]
9 -> 10 [ label = "Normal" ]
9 -> 10 [ label = "Jump" ]
9 -> 12 [ label = "Normal" ]
13 -> 2 [ label = "Error(Implicit)" ]
8 -> 13 [ label = "Normal" ]
6 -> 7 [ label = "Normal" ]
6 -> 7 [ label = "Jump" ]
6 -> 9 [ label = "Normal" ]
12 -> 13 [ label = "Normal" ]
14 -> 2 [ label = "Error(Implicit)" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ bb5: {
bb6: {
statement
statement
condition
}

bb7: {
Expand All @@ -45,6 +46,7 @@ bb8: {

bb9: {
statement
condition
}

bb10: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ digraph {
1 [ label = "TryStatement" ]
2 [ label = "" ]
3 [ label = "BlockStatement" ]
4 [ label = "LabeledStatement\nBlockStatement\nIfStatement" ]
4 [ label = "LabeledStatement\nBlockStatement\nIfStatement\nCondition(IdentifierReference(condition))" ]
5 [ label = "BlockStatement\nbreak <LABEL>" ]
6 [ label = "unreachable" ]
7 [ label = "" ]
Expand All @@ -23,7 +23,7 @@ digraph {
5 -> 6 [ label = "Unreachable" , style = "dotted" ]
7 -> 0 [ label = "Error(Implicit)" ]
6 -> 7 [ label = "Normal" ]
4 -> 5 [ label = "Normal" ]
4 -> 5 [ label = "Jump" ]
4 -> 7 [ label = "Normal" ]
8 -> 0 [ label = "Error(Implicit)" ]
7 -> 8 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ bb4: {
statement
statement
statement
condition
}

bb5: {
Expand Down
Loading

0 comments on commit 9fa95b0

Please sign in to comment.