diff --git a/crates/oxc_linter/Cargo.toml b/crates/oxc_linter/Cargo.toml index 7a147075b77c1..5f51c314c4e7b 100644 --- a/crates/oxc_linter/Cargo.toml +++ b/crates/oxc_linter/Cargo.toml @@ -40,7 +40,7 @@ oxc_macros = { workspace = true, features = ["ruledocs"] } oxc_parser = { workspace = true } oxc_regular_expression = { workspace = true } oxc_resolver = { workspace = true } -oxc_semantic = { workspace = true, features = ["cfg"] } +oxc_semantic = { workspace = true, features = ["cfg", "linter"] } oxc_span = { workspace = true, features = ["schemars", "serialize"] } oxc_syntax = { workspace = true, features = ["serialize"] } diff --git a/crates/oxc_semantic/Cargo.toml b/crates/oxc_semantic/Cargo.toml index 30d59ae3ab468..5d3dbf54b42b4 100644 --- a/crates/oxc_semantic/Cargo.toml +++ b/crates/oxc_semantic/Cargo.toml @@ -46,4 +46,5 @@ serde_json = { workspace = true } [features] default = [] cfg = ["dep:oxc_cfg"] +linter = [] serialize = ["oxc_span/serialize", "oxc_syntax/serialize"] diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index e61e5b8a9d658..10122fce59077 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -336,6 +336,7 @@ impl<'a> SemanticBuilder<'a> { kind, self.current_scope_id, self.current_node_id, + #[cfg(feature = "cfg")] control_flow!(self, |cfg| cfg.current_node_ix), flags, ); @@ -649,6 +650,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { self.current_node_id = self.nodes.add_program_node( kind, self.current_scope_id, + #[cfg(feature = "cfg")] control_flow!(self, |cfg| cfg.current_node_ix), self.current_node_flags, ); diff --git a/crates/oxc_semantic/src/lib.rs b/crates/oxc_semantic/src/lib.rs index ccb23611df374..96b473c381d58 100644 --- a/crates/oxc_semantic/src/lib.rs +++ b/crates/oxc_semantic/src/lib.rs @@ -24,6 +24,7 @@ pub use oxc_syntax::{ #[cfg(feature = "cfg")] pub mod dot; +#[cfg(feature = "linter")] mod ast_types_bitset; mod binder; mod builder; @@ -38,6 +39,7 @@ mod scoping; mod stats; mod unresolved_stack; +#[cfg(feature = "linter")] pub use ast_types_bitset::AstTypesBitset; pub use builder::{SemanticBuilder, SemanticBuilderReturn}; pub use is_global_reference::IsGlobalReference; diff --git a/crates/oxc_semantic/src/node/mod.rs b/crates/oxc_semantic/src/node/mod.rs index 770d015183f21..ce3993b617b92 100644 --- a/crates/oxc_semantic/src/node/mod.rs +++ b/crates/oxc_semantic/src/node/mod.rs @@ -4,8 +4,6 @@ pub use nodes::AstNodes; use oxc_allocator::{Address, GetAddress}; use oxc_ast::AstKind; -#[cfg(feature = "cfg")] -use oxc_cfg::BlockNodeId; use oxc_span::{GetSpan, Span}; use oxc_syntax::{node::NodeId, scope::ScopeId}; @@ -21,19 +19,7 @@ pub struct AstNode<'a> { } impl<'a> AstNode<'a> { - #[inline] - #[cfg(feature = "cfg")] - pub(crate) fn new( - kind: AstKind<'a>, - scope_id: ScopeId, - _cfg_id: BlockNodeId, - id: NodeId, - ) -> Self { - Self { id, kind, scope_id } - } - - #[cfg(not(feature = "cfg"))] - pub(crate) fn new(kind: AstKind<'a>, scope_id: ScopeId, _cfg_id: (), id: NodeId) -> Self { + pub(crate) fn new(kind: AstKind<'a>, scope_id: ScopeId, id: NodeId) -> Self { Self { id, kind, scope_id } } diff --git a/crates/oxc_semantic/src/node/nodes.rs b/crates/oxc_semantic/src/node/nodes.rs index 44880e37eb96a..bc9d0f112da5c 100644 --- a/crates/oxc_semantic/src/node/nodes.rs +++ b/crates/oxc_semantic/src/node/nodes.rs @@ -1,15 +1,21 @@ use std::iter::FusedIterator; -use oxc_ast::{AstKind, AstType, ast::Program}; -#[cfg(feature = "cfg")] -use oxc_cfg::BlockNodeId; +use oxc_ast::{AstKind, ast::Program}; use oxc_index::{IndexSlice, IndexVec}; use oxc_syntax::{ node::{NodeFlags, NodeId}, scope::ScopeId, }; +#[cfg(feature = "linter")] +use oxc_ast::AstType; + +#[cfg(feature = "cfg")] +use oxc_cfg::BlockNodeId; + use super::AstNode; + +#[cfg(feature = "linter")] use crate::ast_types_bitset::AstTypesBitset; /// Untyped AST nodes flattened into an vec @@ -26,6 +32,7 @@ pub struct AstNodes<'a> { /// Stores a set of bits of a fixed size, where each bit represents a single [`AstKind`]. If the bit is set (1), /// then the AST contains at least one node of that kind. If the bit is not set (0), then the AST does not contain /// any nodes of that kind. + #[cfg(feature = "linter")] node_kinds_set: AstTypesBitset, } @@ -148,38 +155,21 @@ impl<'a> AstNodes<'a> { /// [`Program`]: oxc_ast::ast::Program /// [`add_program_node`]: AstNodes::add_program_node #[inline] - #[cfg(feature = "cfg")] pub fn add_node( &mut self, kind: AstKind<'a>, scope_id: ScopeId, parent_node_id: NodeId, - cfg_id: BlockNodeId, + #[cfg(feature = "cfg")] cfg_id: BlockNodeId, flags: NodeFlags, ) -> NodeId { let node_id = self.parent_ids.push(parent_node_id); - let node = AstNode::new(kind, scope_id, cfg_id, node_id); + let node = AstNode::new(kind, scope_id, node_id); self.nodes.push(node); self.flags.push(flags); + #[cfg(feature = "cfg")] self.cfg_ids.push(cfg_id); - self.node_kinds_set.set(kind.ty()); - node_id - } - - #[inline] - #[cfg(not(feature = "cfg"))] - pub fn add_node( - &mut self, - kind: AstKind<'a>, - scope_id: ScopeId, - parent_node_id: NodeId, - _cfg_id: (), - flags: NodeFlags, - ) -> NodeId { - let node_id = self.parent_ids.push(parent_node_id); - let node = AstNode::new(kind, scope_id, (), node_id); - self.nodes.push(node); - self.flags.push(flags); + #[cfg(feature = "linter")] self.node_kinds_set.set(kind.ty()); node_id } @@ -189,12 +179,11 @@ impl<'a> AstNodes<'a> { /// # Panics /// /// Panics if this is not the first node being added to the AST. - #[cfg(feature = "cfg")] pub fn add_program_node( &mut self, kind: AstKind<'a>, scope_id: ScopeId, - cfg_id: BlockNodeId, + #[cfg(feature = "cfg")] cfg_id: BlockNodeId, flags: NodeFlags, ) -> NodeId { assert!(self.parent_ids.is_empty(), "Program node must be the first node in the AST."); @@ -203,29 +192,11 @@ impl<'a> AstNodes<'a> { "Program node must be of kind `AstKind::Program`" ); self.parent_ids.push(NodeId::ROOT); - self.nodes.push(AstNode::new(kind, scope_id, cfg_id, NodeId::ROOT)); + self.nodes.push(AstNode::new(kind, scope_id, NodeId::ROOT)); self.flags.push(flags); + #[cfg(feature = "cfg")] self.cfg_ids.push(cfg_id); - self.node_kinds_set.set(AstType::Program); - NodeId::ROOT - } - - #[cfg(not(feature = "cfg"))] - pub fn add_program_node( - &mut self, - kind: AstKind<'a>, - scope_id: ScopeId, - _cfg_id: (), - flags: NodeFlags, - ) -> NodeId { - assert!(self.parent_ids.is_empty(), "Program node must be the first node in the AST."); - debug_assert!( - matches!(kind, AstKind::Program(_)), - "Program node must be of kind `AstKind::Program`" - ); - self.parent_ids.push(NodeId::ROOT); - self.nodes.push(AstNode::new(kind, scope_id, (), NodeId::ROOT)); - self.flags.push(flags); + #[cfg(feature = "linter")] self.node_kinds_set.set(AstType::Program); NodeId::ROOT } @@ -260,6 +231,7 @@ impl<'a> AstNodes<'a> { /// // `true` if there is at least one import OR one export in the AST /// nodes.contains_any(&import_export_decl); /// ``` + #[cfg(feature = "linter")] pub fn contains_any(&self, bitset: &AstTypesBitset) -> bool { self.node_kinds_set.intersects(bitset) } @@ -285,6 +257,7 @@ impl<'a> AstNodes<'a> { /// // `true` if there is at least one import AND one export in the AST /// nodes.contains_all(&import_export_decl); /// ``` + #[cfg(feature = "linter")] pub fn contains_all(&self, bitset: &AstTypesBitset) -> bool { self.node_kinds_set.contains(bitset) } @@ -304,6 +277,7 @@ impl<'a> AstNodes<'a> { /// // `true` if there is an `ImportDeclaration` anywhere in the AST /// nodes.contains(AstType::ImportDeclaration); /// ``` + #[cfg(feature = "linter")] pub fn contains(&self, ty: AstType) -> bool { self.node_kinds_set.has(ty) }