diff --git a/crates/oxc_linter/src/rules/eslint/getter_return.rs b/crates/oxc_linter/src/rules/eslint/getter_return.rs index 10582862c66683..037bddf2006d2f 100644 --- a/crates/oxc_linter/src/rules/eslint/getter_return.rs +++ b/crates/oxc_linter/src/rules/eslint/getter_return.rs @@ -276,6 +276,7 @@ impl GetterReturn { | InstructionKind::Break(_) | InstructionKind::Continue(_) | InstructionKind::Iteration(_) + | InstructionKind::Condition | InstructionKind::Statement => {} } } diff --git a/crates/oxc_linter/src/rules/react/require_render_return.rs b/crates/oxc_linter/src/rules/react/require_render_return.rs index 49d67a1b17b330..fc75760e2bd56b 100644 --- a/crates/oxc_linter/src/rules/react/require_render_return.rs +++ b/crates/oxc_linter/src/rules/react/require_render_return.rs @@ -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 => {} } } diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 05c6f3b7aa7ac7..ab1cc7af322838 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -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; @@ -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; @@ -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( @@ -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 */ @@ -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; @@ -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)) = @@ -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(); diff --git a/crates/oxc_semantic/src/control_flow/builder/mod.rs b/crates/oxc_semantic/src/control_flow/builder/mod.rs index 35404c17521e23..5c6b23fd6a2135 100644 --- a/crates/oxc_semantic/src/control_flow/builder/mod.rs +++ b/crates/oxc_semantic/src/control_flow/builder/mod.rs @@ -145,6 +145,10 @@ impl<'a> ControlFlowGraphBuilder<'a> { ); } + pub fn append_condition(&mut self, node: Option) { + self.push_instruction(InstructionKind::Condition, node); + } + pub fn append_iteration(&mut self, node: Option, kind: IterationInstructionKind) { self.push_instruction(InstructionKind::Iteration(kind), node); } diff --git a/crates/oxc_semantic/src/control_flow/dot.rs b/crates/oxc_semantic/src/control_flow/dot.rs index f3497380e0f0f0..a7d7176fb95340 100644 --- a/crates/oxc_semantic/src/control_flow/dot.rs +++ b/crates/oxc_semantic/src/control_flow/dot.rs @@ -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 { + 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> { @@ -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 ", + InstructionKind::Iteration(IterationInstructionKind::In) => "iteration ", InstructionKind::Break(LabeledInstruction::Labeled) => "break