mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
refactor(cfg): use IndexVec for storing basic blocks (#6323)
Use an `IndexVec` when storing basic blocks. This makes the link between nodes in `.graph` and elements of `.basic_blocks` more clear. I had to rename `BasicBlockId` to `BlockNodeId` to avoid a name collision. I wasn't sure what else to name the `Idx` type for the basic blocks vec.
This commit is contained in:
parent
71ad5d3e3f
commit
40932f79b1
11 changed files with 115 additions and 81 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1519,6 +1519,8 @@ version = "0.30.5"
|
|||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"itertools",
|
||||
"nonmax",
|
||||
"oxc_index",
|
||||
"oxc_syntax",
|
||||
"petgraph",
|
||||
"rustc-hash",
|
||||
|
|
|
|||
|
|
@ -21,9 +21,11 @@ test = false
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
oxc_index = { workspace = true }
|
||||
oxc_syntax = { workspace = true }
|
||||
|
||||
bitflags = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
nonmax = { workspace = true }
|
||||
petgraph = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
use oxc_syntax::node::NodeId;
|
||||
use petgraph::stable_graph::NodeIndex;
|
||||
|
||||
pub type BasicBlockId = NodeIndex;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BasicBlock {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use super::ControlFlowGraphBuilder;
|
||||
use crate::{BasicBlockId, EdgeType};
|
||||
use crate::{BlockNodeId, EdgeType};
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
|
@ -15,9 +15,9 @@ bitflags::bitflags! {
|
|||
pub(super) struct Ctx<'a> {
|
||||
flags: CtxFlags,
|
||||
label: Option<&'a str>,
|
||||
entries: Vec<(CtxFlags, BasicBlockId)>,
|
||||
break_jmp: Option<BasicBlockId>,
|
||||
continue_jmp: Option<BasicBlockId>,
|
||||
entries: Vec<(CtxFlags, BlockNodeId)>,
|
||||
break_jmp: Option<BlockNodeId>,
|
||||
continue_jmp: Option<BlockNodeId>,
|
||||
}
|
||||
|
||||
impl<'a> Ctx<'a> {
|
||||
|
|
@ -29,11 +29,11 @@ impl<'a> Ctx<'a> {
|
|||
self.label.as_ref().is_some_and(|it| *it == label)
|
||||
}
|
||||
|
||||
fn r#break(&mut self, entry: BasicBlockId) {
|
||||
fn r#break(&mut self, entry: BlockNodeId) {
|
||||
self.entries.push((CtxFlags::BREAK, entry));
|
||||
}
|
||||
|
||||
fn r#continue(&mut self, entry: BasicBlockId) {
|
||||
fn r#continue(&mut self, entry: BlockNodeId) {
|
||||
self.entries.push((CtxFlags::CONTINUE, entry));
|
||||
}
|
||||
}
|
||||
|
|
@ -41,19 +41,19 @@ impl<'a> Ctx<'a> {
|
|||
pub trait CtxCursor {
|
||||
#![allow(clippy::return_self_not_must_use)]
|
||||
/// Marks the break jump position in the current context.
|
||||
fn mark_break(self, jmp_pos: BasicBlockId) -> Self;
|
||||
fn mark_break(self, jmp_pos: BlockNodeId) -> Self;
|
||||
/// Marks the continue jump position in the current context.
|
||||
fn mark_continue(self, jmp_pos: BasicBlockId) -> Self;
|
||||
fn mark_continue(self, jmp_pos: BlockNodeId) -> Self;
|
||||
/// Creates a break entry in the current context.
|
||||
fn r#break(self, bb: BasicBlockId) -> Self;
|
||||
fn r#break(self, bb: BlockNodeId) -> Self;
|
||||
/// Creates a continue entry in the current context.
|
||||
fn r#continue(self, bb: BasicBlockId) -> Self;
|
||||
fn r#continue(self, bb: BlockNodeId) -> Self;
|
||||
}
|
||||
|
||||
pub struct QueryCtx<'a, 'c>(&'c mut ControlFlowGraphBuilder<'a>, /* label */ Option<&'a str>);
|
||||
|
||||
impl<'a, 'c> CtxCursor for QueryCtx<'a, 'c> {
|
||||
fn mark_break(self, jmp_pos: BasicBlockId) -> Self {
|
||||
fn mark_break(self, jmp_pos: BlockNodeId) -> Self {
|
||||
self.0.in_break_context(self.1, |ctx| {
|
||||
debug_assert!(ctx.break_jmp.is_none());
|
||||
ctx.break_jmp = Some(jmp_pos);
|
||||
|
|
@ -61,7 +61,7 @@ impl<'a, 'c> CtxCursor for QueryCtx<'a, 'c> {
|
|||
self
|
||||
}
|
||||
|
||||
fn mark_continue(self, jmp_pos: BasicBlockId) -> Self {
|
||||
fn mark_continue(self, jmp_pos: BlockNodeId) -> Self {
|
||||
self.0.in_continue_context(self.1, |ctx| {
|
||||
debug_assert!(ctx.continue_jmp.is_none());
|
||||
ctx.continue_jmp = Some(jmp_pos);
|
||||
|
|
@ -69,14 +69,14 @@ impl<'a, 'c> CtxCursor for QueryCtx<'a, 'c> {
|
|||
self
|
||||
}
|
||||
|
||||
fn r#break(self, bb: BasicBlockId) -> Self {
|
||||
fn r#break(self, bb: BlockNodeId) -> Self {
|
||||
self.0.in_break_context(self.1, |ctx| {
|
||||
ctx.r#break(bb);
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
fn r#continue(self, bb: BasicBlockId) -> Self {
|
||||
fn r#continue(self, bb: BlockNodeId) -> Self {
|
||||
self.0.in_continue_context(self.1, |ctx| {
|
||||
ctx.r#continue(bb);
|
||||
});
|
||||
|
|
@ -192,24 +192,24 @@ impl<'a, 'c> RefCtxCursor<'a, 'c> {
|
|||
}
|
||||
|
||||
impl<'a, 'c> CtxCursor for RefCtxCursor<'a, 'c> {
|
||||
fn mark_break(self, jmp_pos: BasicBlockId) -> Self {
|
||||
fn mark_break(self, jmp_pos: BlockNodeId) -> Self {
|
||||
debug_assert!(self.0.break_jmp.is_none());
|
||||
self.0.break_jmp = Some(jmp_pos);
|
||||
self
|
||||
}
|
||||
|
||||
fn mark_continue(self, jmp_pos: BasicBlockId) -> Self {
|
||||
fn mark_continue(self, jmp_pos: BlockNodeId) -> Self {
|
||||
debug_assert!(self.0.continue_jmp.is_none());
|
||||
self.0.continue_jmp = Some(jmp_pos);
|
||||
self
|
||||
}
|
||||
|
||||
fn r#break(self, bb: BasicBlockId) -> Self {
|
||||
fn r#break(self, bb: BlockNodeId) -> Self {
|
||||
self.0.r#break(bb);
|
||||
self
|
||||
}
|
||||
|
||||
fn r#continue(self, bb: BasicBlockId) -> Self {
|
||||
fn r#continue(self, bb: BlockNodeId) -> Self {
|
||||
self.0.r#continue(bb);
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,28 +2,29 @@ mod context;
|
|||
|
||||
use context::Ctx;
|
||||
pub use context::{CtxCursor, CtxFlags};
|
||||
use oxc_index::IndexVec;
|
||||
use oxc_syntax::node::NodeId;
|
||||
use petgraph::Direction;
|
||||
|
||||
use super::{
|
||||
BasicBlock, BasicBlockId, ControlFlowGraph, EdgeType, ErrorEdgeKind, Graph, Instruction,
|
||||
BasicBlock, BlockNodeId, ControlFlowGraph, EdgeType, ErrorEdgeKind, Graph, Instruction,
|
||||
InstructionKind, IterationInstructionKind, LabeledInstruction,
|
||||
};
|
||||
use crate::ReturnInstructionKind;
|
||||
use crate::{BasicBlockId, ReturnInstructionKind};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ErrorHarness(ErrorEdgeKind, BasicBlockId);
|
||||
struct ErrorHarness(ErrorEdgeKind, BlockNodeId);
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ControlFlowGraphBuilder<'a> {
|
||||
pub graph: Graph,
|
||||
pub basic_blocks: Vec<BasicBlock>,
|
||||
pub current_node_ix: BasicBlockId,
|
||||
pub basic_blocks: IndexVec<BasicBlockId, BasicBlock>,
|
||||
pub current_node_ix: BlockNodeId,
|
||||
ctx_stack: Vec<Ctx<'a>>,
|
||||
/// Contains the error unwinding path represented as a stack of `ErrorHarness`es
|
||||
error_path: Vec<ErrorHarness>,
|
||||
/// Stack of finalizers, the top most element is always the appropriate one for current node.
|
||||
finalizers: Vec<Option<BasicBlockId>>,
|
||||
finalizers: Vec<Option<BlockNodeId>>,
|
||||
}
|
||||
|
||||
impl<'a> ControlFlowGraphBuilder<'a> {
|
||||
|
|
@ -36,7 +37,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
}
|
||||
|
||||
/// # Panics
|
||||
pub fn basic_block(&self, basic_block: BasicBlockId) -> &BasicBlock {
|
||||
pub fn basic_block(&self, basic_block: BlockNodeId) -> &BasicBlock {
|
||||
let idx = *self
|
||||
.graph
|
||||
.node_weight(basic_block)
|
||||
|
|
@ -47,7 +48,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
}
|
||||
|
||||
/// # Panics
|
||||
pub fn basic_block_mut(&mut self, basic_block: BasicBlockId) -> &mut BasicBlock {
|
||||
pub fn basic_block_mut(&mut self, basic_block: BlockNodeId) -> &mut BasicBlock {
|
||||
let idx = *self
|
||||
.graph
|
||||
.node_weight(basic_block)
|
||||
|
|
@ -57,15 +58,14 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
.expect("expected `self.current_node_ix` to be a valid node index in self.graph")
|
||||
}
|
||||
|
||||
pub(self) fn new_basic_block(&mut self) -> BasicBlockId {
|
||||
pub(self) fn new_basic_block(&mut self) -> BlockNodeId {
|
||||
// current length would be the index of block we are adding on the next line.
|
||||
let basic_block_ix = self.basic_blocks.len();
|
||||
self.basic_blocks.push(BasicBlock::new());
|
||||
let basic_block_ix = self.basic_blocks.push(BasicBlock::new());
|
||||
self.graph.add_node(basic_block_ix)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn new_basic_block_function(&mut self) -> BasicBlockId {
|
||||
pub fn new_basic_block_function(&mut self) -> BlockNodeId {
|
||||
// we might want to differentiate between function blocks and normal blocks down the road.
|
||||
self.new_basic_block_normal()
|
||||
}
|
||||
|
|
@ -73,7 +73,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
/// # Panics
|
||||
/// if there is no error harness to attach to.
|
||||
#[must_use]
|
||||
pub fn new_basic_block_normal(&mut self) -> BasicBlockId {
|
||||
pub fn new_basic_block_normal(&mut self) -> BlockNodeId {
|
||||
let graph_ix = self.new_basic_block();
|
||||
self.current_node_ix = graph_ix;
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
graph_ix
|
||||
}
|
||||
|
||||
pub fn add_edge(&mut self, a: BasicBlockId, b: BasicBlockId, weight: EdgeType) {
|
||||
pub fn add_edge(&mut self, a: BlockNodeId, b: BlockNodeId, weight: EdgeType) {
|
||||
if matches!(weight, EdgeType::NewFunction) {
|
||||
self.basic_block_mut(b).mark_as_reachable();
|
||||
} else if matches!(weight, EdgeType::Unreachable) || self.basic_block(a).is_unreachable() {
|
||||
|
|
@ -117,7 +117,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
|
||||
/// Creates and push a new `BasicBlockId` onto `self.error_path` stack.
|
||||
/// Returns the `BasicBlockId` of the created error harness block.
|
||||
pub fn attach_error_harness(&mut self, kind: ErrorEdgeKind) -> BasicBlockId {
|
||||
pub fn attach_error_harness(&mut self, kind: ErrorEdgeKind) -> BlockNodeId {
|
||||
let graph_ix = self.new_basic_block();
|
||||
self.error_path.push(ErrorHarness(kind, graph_ix));
|
||||
graph_ix
|
||||
|
|
@ -126,7 +126,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
/// # Panics
|
||||
/// if there is no error harness pushed onto the stack,
|
||||
/// Or last harness doesn't match the expected `BasicBlockId`.
|
||||
pub fn release_error_harness(&mut self, expect: BasicBlockId) {
|
||||
pub fn release_error_harness(&mut self, expect: BlockNodeId) {
|
||||
let harness = self
|
||||
.error_path
|
||||
.pop()
|
||||
|
|
@ -139,7 +139,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
|
||||
/// Creates and push a new `BasicBlockId` onto `self.finalizers` stack.
|
||||
/// Returns the `BasicBlockId` of the created finalizer block.
|
||||
pub fn attach_finalizer(&mut self) -> BasicBlockId {
|
||||
pub fn attach_finalizer(&mut self) -> BlockNodeId {
|
||||
let graph_ix = self.new_basic_block();
|
||||
self.finalizers.push(Some(graph_ix));
|
||||
graph_ix
|
||||
|
|
@ -156,7 +156,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
|
||||
/// # Panics
|
||||
/// if last finalizer doesn't match the expected `BasicBlockId`.
|
||||
pub fn release_finalizer(&mut self, expect: BasicBlockId) {
|
||||
pub fn release_finalizer(&mut self, expect: BlockNodeId) {
|
||||
// return early if there is no finalizer.
|
||||
let Some(finalizer) = self.finalizers.pop() else { return };
|
||||
assert_eq!(
|
||||
|
|
@ -166,7 +166,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
);
|
||||
}
|
||||
|
||||
pub fn append_condition_to(&mut self, block: BasicBlockId, node: Option<NodeId>) {
|
||||
pub fn append_condition_to(&mut self, block: BlockNodeId, node: Option<NodeId>) {
|
||||
self.push_instruction_to(block, InstructionKind::Condition, node);
|
||||
}
|
||||
|
||||
|
|
@ -228,7 +228,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
#[inline]
|
||||
pub(self) fn push_instruction_to(
|
||||
&mut self,
|
||||
block: BasicBlockId,
|
||||
block: BlockNodeId,
|
||||
kind: InstructionKind,
|
||||
node_id: Option<NodeId>,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ mod builder;
|
|||
pub mod dot;
|
||||
pub mod visit;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use itertools::Itertools;
|
||||
use nonmax::NonMaxU32;
|
||||
use oxc_index::{Idx, IndexVec};
|
||||
use petgraph::{
|
||||
visit::{Control, DfsEvent, EdgeRef},
|
||||
Direction,
|
||||
|
|
@ -23,7 +27,37 @@ pub use builder::{ControlFlowGraphBuilder, CtxCursor, CtxFlags};
|
|||
pub use dot::DisplayDot;
|
||||
use visit::set_depth_first_search;
|
||||
|
||||
pub type Graph = petgraph::graph::DiGraph<usize, EdgeType>;
|
||||
pub type BlockNodeId = petgraph::stable_graph::NodeIndex;
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct BasicBlockId(NonMaxU32);
|
||||
|
||||
impl Idx for BasicBlockId {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn from_usize(idx: usize) -> Self {
|
||||
assert!(idx < u32::MAX as usize);
|
||||
// SAFETY: We just checked `idx` is valid for `NonMaxU32`
|
||||
Self(unsafe { NonMaxU32::new_unchecked(idx as u32) })
|
||||
}
|
||||
|
||||
fn index(self) -> usize {
|
||||
self.0.get() as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<u32> for BasicBlockId {
|
||||
#[inline]
|
||||
fn eq(&self, other: &u32) -> bool {
|
||||
self.0.get() == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BasicBlockId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Graph = petgraph::graph::DiGraph<BasicBlockId, EdgeType>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EdgeType {
|
||||
|
|
@ -65,7 +99,7 @@ pub enum EvalConstConditionResult {
|
|||
#[derive(Debug)]
|
||||
pub struct ControlFlowGraph {
|
||||
pub graph: Graph,
|
||||
pub basic_blocks: Vec<BasicBlock>,
|
||||
pub basic_blocks: IndexVec<BasicBlockId, BasicBlock>,
|
||||
}
|
||||
|
||||
impl ControlFlowGraph {
|
||||
|
|
@ -74,25 +108,25 @@ impl ControlFlowGraph {
|
|||
}
|
||||
|
||||
/// # Panics
|
||||
pub fn basic_block(&self, id: BasicBlockId) -> &BasicBlock {
|
||||
pub fn basic_block(&self, id: BlockNodeId) -> &BasicBlock {
|
||||
let ix = *self.graph.node_weight(id).expect("expected a valid node id in self.graph");
|
||||
self.basic_blocks.get(ix).expect("expected a valid node id in self.basic_blocks")
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
pub fn basic_block_mut(&mut self, id: BasicBlockId) -> &mut BasicBlock {
|
||||
pub fn basic_block_mut(&mut self, id: BlockNodeId) -> &mut BasicBlock {
|
||||
let ix = *self.graph.node_weight(id).expect("expected a valid node id in self.graph");
|
||||
self.basic_blocks.get_mut(ix).expect("expected a valid node id in self.basic_blocks")
|
||||
}
|
||||
|
||||
pub fn is_reachable(&self, from: BasicBlockId, to: BasicBlockId) -> bool {
|
||||
pub fn is_reachable(&self, from: BlockNodeId, to: BlockNodeId) -> bool {
|
||||
self.is_reachable_filtered(from, to, |_| Control::Continue)
|
||||
}
|
||||
|
||||
pub fn is_reachable_filtered<F: Fn(BasicBlockId) -> Control<bool>>(
|
||||
pub fn is_reachable_filtered<F: Fn(BlockNodeId) -> Control<bool>>(
|
||||
&self,
|
||||
from: BasicBlockId,
|
||||
to: BasicBlockId,
|
||||
from: BlockNodeId,
|
||||
to: BlockNodeId,
|
||||
filter: F,
|
||||
) -> bool {
|
||||
if from == to {
|
||||
|
|
@ -127,13 +161,13 @@ impl ControlFlowGraph {
|
|||
/// Otherwise returns `Some(loop_start, loop_end)`.
|
||||
pub fn is_infinite_loop_start<F>(
|
||||
&self,
|
||||
node: BasicBlockId,
|
||||
node: BlockNodeId,
|
||||
try_eval_const_condition: F,
|
||||
) -> Option<(BasicBlockId, BasicBlockId)>
|
||||
) -> Option<(BlockNodeId, BlockNodeId)>
|
||||
where
|
||||
F: Fn(&Instruction) -> EvalConstConditionResult,
|
||||
{
|
||||
fn get_jump_target(graph: &Graph, node: BasicBlockId) -> Option<BasicBlockId> {
|
||||
fn get_jump_target(graph: &Graph, node: BlockNodeId) -> Option<BlockNodeId> {
|
||||
graph
|
||||
.edges_directed(node, Direction::Outgoing)
|
||||
.find_or_first(|e| matches!(e.weight(), EdgeType::Jump))
|
||||
|
|
@ -186,7 +220,7 @@ impl ControlFlowGraph {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_cyclic(&self, node: BasicBlockId) -> bool {
|
||||
pub fn is_cyclic(&self, node: BlockNodeId) -> bool {
|
||||
set_depth_first_search(&self.graph, Some(node), |event| match event {
|
||||
DfsEvent::BackEdge(_, id) if id == node => Err(()),
|
||||
_ => Ok(()),
|
||||
|
|
|
|||
|
|
@ -6,18 +6,18 @@ use petgraph::{
|
|||
};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::BasicBlockId;
|
||||
use crate::BlockNodeId;
|
||||
|
||||
/// # Panics
|
||||
pub fn neighbors_filtered_by_edge_weight<State: Default + Clone, NodeWeight, EdgeWeight, F, G>(
|
||||
graph: &Graph<NodeWeight, EdgeWeight>,
|
||||
node: BasicBlockId,
|
||||
node: BlockNodeId,
|
||||
edge_filter: &F,
|
||||
visitor: &mut G,
|
||||
) -> Vec<State>
|
||||
where
|
||||
F: Fn(&EdgeWeight) -> Option<State>,
|
||||
G: FnMut(&BasicBlockId, State) -> (State, bool),
|
||||
G: FnMut(&BlockNodeId, State) -> (State, bool),
|
||||
{
|
||||
let mut q = vec![];
|
||||
let mut final_states = vec![];
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use oxc_cfg::{
|
|||
visit::{neighbors_filtered_by_edge_weight, EdgeRef},
|
||||
Direction,
|
||||
},
|
||||
BasicBlockId, EdgeType, ErrorEdgeKind, InstructionKind,
|
||||
BlockNodeId, EdgeType, ErrorEdgeKind, InstructionKind,
|
||||
};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
|
|
@ -274,7 +274,7 @@ impl Rule for NoFallthrough {
|
|||
return;
|
||||
};
|
||||
|
||||
let fallthroughs: FxHashSet<BasicBlockId> = neighbors_filtered_by_edge_weight(
|
||||
let fallthroughs: FxHashSet<BlockNodeId> = neighbors_filtered_by_edge_weight(
|
||||
graph,
|
||||
switch_id,
|
||||
&|e| match e {
|
||||
|
|
@ -283,7 +283,7 @@ impl Rule for NoFallthrough {
|
|||
}
|
||||
_ => Some(None),
|
||||
},
|
||||
&mut |node, last_cond: Option<BasicBlockId>| {
|
||||
&mut |node, last_cond: Option<BlockNodeId>| {
|
||||
let node = *node;
|
||||
|
||||
if node == switch_id {
|
||||
|
|
@ -448,10 +448,10 @@ fn get_switch_semantic_cases(
|
|||
node: &AstNode,
|
||||
switch: &SwitchStatement,
|
||||
) -> (
|
||||
Vec<BasicBlockId>,
|
||||
FxHashMap<BasicBlockId, /* is_empty */ bool>,
|
||||
/* default */ Option<BasicBlockId>,
|
||||
/* exit */ Option<BasicBlockId>,
|
||||
Vec<BlockNodeId>,
|
||||
FxHashMap<BlockNodeId, /* is_empty */ bool>,
|
||||
/* default */ Option<BlockNodeId>,
|
||||
/* exit */ Option<BlockNodeId>,
|
||||
) {
|
||||
let cfg = ctx.cfg();
|
||||
let graph = cfg.graph();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use oxc_ast::{
|
|||
};
|
||||
use oxc_cfg::{
|
||||
graph::visit::{neighbors_filtered_by_edge_weight, EdgeRef},
|
||||
BasicBlockId, ControlFlowGraph, EdgeType, ErrorEdgeKind,
|
||||
BlockNodeId, ControlFlowGraph, EdgeType, ErrorEdgeKind,
|
||||
};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
|
|
@ -50,7 +50,7 @@ enum DefinitelyCallsThisBeforeSuper {
|
|||
#[default]
|
||||
No,
|
||||
Yes,
|
||||
Maybe(BasicBlockId),
|
||||
Maybe(BlockNodeId),
|
||||
}
|
||||
|
||||
impl Rule for NoThisBeforeSuper {
|
||||
|
|
@ -60,9 +60,9 @@ impl Rule for NoThisBeforeSuper {
|
|||
|
||||
// first pass -> find super calls and local violations
|
||||
let mut wanted_nodes = Vec::new();
|
||||
let mut basic_blocks_with_super_called = FxHashSet::<BasicBlockId>::default();
|
||||
let mut basic_blocks_with_super_called = FxHashSet::<BlockNodeId>::default();
|
||||
let mut basic_blocks_with_local_violations =
|
||||
FxHashMap::<BasicBlockId, Vec<NodeId>>::default();
|
||||
FxHashMap::<BlockNodeId, Vec<NodeId>>::default();
|
||||
for node in semantic.nodes() {
|
||||
match node.kind() {
|
||||
AstKind::Function(_) | AstKind::ArrowFunctionExpression(_) => {
|
||||
|
|
@ -151,9 +151,9 @@ impl NoThisBeforeSuper {
|
|||
|
||||
fn analyze(
|
||||
cfg: &ControlFlowGraph,
|
||||
id: BasicBlockId,
|
||||
basic_blocks_with_super_called: &FxHashSet<BasicBlockId>,
|
||||
basic_blocks_with_local_violations: &FxHashMap<BasicBlockId, Vec<NodeId>>,
|
||||
id: BlockNodeId,
|
||||
basic_blocks_with_super_called: &FxHashSet<BlockNodeId>,
|
||||
basic_blocks_with_local_violations: &FxHashMap<BlockNodeId, Vec<NodeId>>,
|
||||
follow_join: bool,
|
||||
) -> Vec<DefinitelyCallsThisBeforeSuper> {
|
||||
neighbors_filtered_by_edge_weight(
|
||||
|
|
@ -211,8 +211,8 @@ impl NoThisBeforeSuper {
|
|||
fn check_for_violation(
|
||||
cfg: &ControlFlowGraph,
|
||||
output: Vec<DefinitelyCallsThisBeforeSuper>,
|
||||
basic_blocks_with_super_called: &FxHashSet<BasicBlockId>,
|
||||
basic_blocks_with_local_violations: &FxHashMap<BasicBlockId, Vec<NodeId>>,
|
||||
basic_blocks_with_super_called: &FxHashSet<BlockNodeId>,
|
||||
basic_blocks_with_local_violations: &FxHashMap<BlockNodeId, Vec<NodeId>>,
|
||||
) -> bool {
|
||||
// Deciding whether we definitely call this before super in all
|
||||
// codepaths is as simple as seeing if any individual codepath
|
||||
|
|
|
|||
|
|
@ -86,10 +86,9 @@ fn main() -> std::io::Result<()> {
|
|||
|
||||
let basic_blocks_printed = cfg
|
||||
.basic_blocks
|
||||
.iter()
|
||||
.map(DisplayDot::display_dot)
|
||||
.enumerate()
|
||||
.iter_enumerated()
|
||||
.map(|(i, it)| {
|
||||
let it = it.display_dot();
|
||||
format!(
|
||||
"bb{i}: {{\n{}\n---\n{}\n}}",
|
||||
it.lines().map(|x| format!("\t{}", x.trim())).join("\n"),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use oxc_ast::AstKind;
|
||||
use oxc_cfg::BasicBlockId;
|
||||
use oxc_cfg::BlockNodeId;
|
||||
use oxc_index::IndexVec;
|
||||
use oxc_span::GetSpan;
|
||||
pub use oxc_syntax::node::{NodeFlags, NodeId};
|
||||
|
|
@ -17,7 +17,7 @@ pub struct AstNode<'a> {
|
|||
scope_id: ScopeId,
|
||||
|
||||
/// Associated `BasicBlockId` in CFG (initialized by control_flow)
|
||||
cfg_id: BasicBlockId,
|
||||
cfg_id: BlockNodeId,
|
||||
|
||||
flags: NodeFlags,
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ impl<'a> AstNode<'a> {
|
|||
pub(crate) fn new(
|
||||
kind: AstKind<'a>,
|
||||
scope_id: ScopeId,
|
||||
cfg_id: BasicBlockId,
|
||||
cfg_id: BlockNodeId,
|
||||
flags: NodeFlags,
|
||||
id: NodeId,
|
||||
) -> Self {
|
||||
|
|
@ -44,7 +44,7 @@ impl<'a> AstNode<'a> {
|
|||
///
|
||||
/// See [oxc_cfg::ControlFlowGraph] for more information.
|
||||
#[inline]
|
||||
pub fn cfg_id(&self) -> BasicBlockId {
|
||||
pub fn cfg_id(&self) -> BlockNodeId {
|
||||
self.cfg_id
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ impl<'a> AstNodes<'a> {
|
|||
kind: AstKind<'a>,
|
||||
scope_id: ScopeId,
|
||||
parent_node_id: NodeId,
|
||||
cfg_id: BasicBlockId,
|
||||
cfg_id: BlockNodeId,
|
||||
flags: NodeFlags,
|
||||
) -> NodeId {
|
||||
let node_id = self.parent_ids.push(Some(parent_node_id));
|
||||
|
|
@ -250,7 +250,7 @@ impl<'a> AstNodes<'a> {
|
|||
&mut self,
|
||||
kind: AstKind<'a>,
|
||||
scope_id: ScopeId,
|
||||
cfg_id: BasicBlockId,
|
||||
cfg_id: BlockNodeId,
|
||||
flags: NodeFlags,
|
||||
) -> NodeId {
|
||||
let node_id = self.parent_ids.push(None);
|
||||
|
|
|
|||
Loading…
Reference in a new issue