Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/ast_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ pub fn is_callee<'a>(node: &AstNode<'a>, semantic: &Semantic<'a>) -> bool {

fn has_jsdoc_this_tag<'a>(semantic: &Semantic<'a>, node: &AstNode<'a>) -> bool {
let Some(jsdocs) = get_function_nearest_jsdoc_node(node, semantic)
.and_then(|node| semantic.jsdoc().get_all_by_node(node))
.and_then(|node| semantic.jsdoc().get_all_by_node(semantic.nodes(), node))
else {
return false;
};
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/rules/eslint/require_yield.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ declare_oxc_lint!(
impl Rule for RequireYield {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
if let AstKind::Function(func) = node.kind()
&& !node.flags().has_yield()
&& !ctx.nodes().flags(node.id()).has_yield()
&& func.generator
&& func.body.as_ref().is_some_and(|body| !body.statements.is_empty())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ impl Rule for ImplementsOnClasses {
}

let Some(jsdocs) = get_function_nearest_jsdoc_node(node, ctx)
.and_then(|node| ctx.jsdoc().get_all_by_node(node))
.and_then(|node| ctx.jsdoc().get_all_by_node(ctx.nodes(), node))
else {
return;
};
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/rules/jsdoc/no_defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl Rule for NoDefaults {
}

let Some(jsdocs) = get_function_nearest_jsdoc_node(node, ctx)
.and_then(|node| ctx.jsdoc().get_all_by_node(node))
.and_then(|node| ctx.jsdoc().get_all_by_node(ctx.nodes(), node))
else {
return;
};
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/rules/jsdoc/require_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl Rule for RequireParam {
return;
};
// If no JSDoc is found, skip
let Some(jsdocs) = ctx.jsdoc().get_all_by_node(func_def_node) else {
let Some(jsdocs) = ctx.jsdoc().get_all_by_node(ctx.nodes(), func_def_node) else {
return;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl Rule for RequireParamDescription {

// If no JSDoc is found, skip
let Some(jsdocs) = get_function_nearest_jsdoc_node(node, ctx)
.and_then(|node| ctx.jsdoc().get_all_by_node(node))
.and_then(|node| ctx.jsdoc().get_all_by_node(ctx.nodes(), node))
else {
return;
};
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/rules/jsdoc/require_param_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl Rule for RequireParamName {

// If no JSDoc is found, skip
let Some(jsdocs) = get_function_nearest_jsdoc_node(node, ctx)
.and_then(|node| ctx.jsdoc().get_all_by_node(node))
.and_then(|node| ctx.jsdoc().get_all_by_node(ctx.nodes(), node))
else {
return;
};
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/rules/jsdoc/require_param_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl Rule for RequireParamType {

// If no JSDoc is found, skip
let Some(jsdocs) = get_function_nearest_jsdoc_node(node, ctx)
.and_then(|node| ctx.jsdoc().get_all_by_node(node))
.and_then(|node| ctx.jsdoc().get_all_by_node(ctx.nodes(), node))
else {
return;
};
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/rules/jsdoc/require_returns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ impl Rule for RequireReturns {
continue;
};
// If no JSDoc is found, skip
let Some(jsdocs) = ctx.jsdoc().get_all_by_node(func_def_node) else {
let Some(jsdocs) = ctx.jsdoc().get_all_by_node(ctx.nodes(), func_def_node) else {
continue;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl Rule for RequireReturnsDescription {

// If no JSDoc is found, skip
let Some(jsdocs) = get_function_nearest_jsdoc_node(node, ctx)
.and_then(|node| ctx.jsdoc().get_all_by_node(node))
.and_then(|node| ctx.jsdoc().get_all_by_node(ctx.nodes(), node))
else {
return;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl Rule for RequireReturnsType {

// If no JSDoc is found, skip
let Some(jsdocs) = get_function_nearest_jsdoc_node(node, ctx)
.and_then(|node| ctx.jsdoc().get_all_by_node(node))
.and_then(|node| ctx.jsdoc().get_all_by_node(ctx.nodes(), node))
else {
return;
};
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_linter/src/rules/jsdoc/require_yields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl Rule for RequireYields {
{
// If no JSDoc is found, skip
let Some(jsdocs) = get_function_nearest_jsdoc_node(node, ctx)
.and_then(|node| ctx.jsdoc().get_all_by_node(node))
.and_then(|node| ctx.jsdoc().get_all_by_node(ctx.nodes(), node))
else {
return;
};
Expand Down Expand Up @@ -216,7 +216,7 @@ impl Rule for RequireYields {

// If no JSDoc is found, skip
let Some(jsdocs) = get_function_nearest_jsdoc_node(generator_func_node, ctx)
.and_then(|node| ctx.jsdoc().get_all_by_node(node))
.and_then(|node| ctx.jsdoc().get_all_by_node(ctx.nodes(), node))
else {
return;
};
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_linter/src/utils/jsdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub fn get_function_nearest_jsdoc_node<'a, 'b>(
) -> Option<&'b AstNode<'a>> {
let mut current_node = node;
// Whether the node has attached JSDoc or not is determined by `JSDocBuilder`
while semantic.jsdoc().get_all_by_node(current_node).is_none() {
while semantic.jsdoc().get_all_by_node(semantic.nodes(), current_node).is_none() {
// Tie-breaker, otherwise every loop will end at `Program` node!
// Maybe more checks should be added
match current_node.kind() {
Expand Down
3 changes: 1 addition & 2 deletions crates/oxc_semantic/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2150,8 +2150,7 @@ impl<'a> SemanticBuilder<'a> {
AstKind::YieldExpression(_) => {
// If not in a function, `current_function_node_id` is `NodeId` of `Program`.
// But it shouldn't be possible for `yield` to be at top level - that's a parse error.
*self.nodes.get_node_mut(self.current_function_node_id).flags_mut() |=
NodeFlags::HasYield;
*self.nodes.flags_mut(self.current_function_node_id) |= NodeFlags::HasYield;
}
AstKind::CallExpression(call_expr) => {
if !call_expr.optional && call_expr.callee.is_specific_id("eval") {
Expand Down
5 changes: 3 additions & 2 deletions crates/oxc_semantic/src/checker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ pub fn check_unresolved_exports(ctx: &SemanticBuilder<'_>) {
for reference_ids in ctx.unresolved_references.root().values() {
for reference_id in reference_ids {
let reference = ctx.scoping.get_reference(*reference_id);
let node = ctx.nodes.get_node(reference.node_id());
if node.flags().has_export_specifier()
let node_id = reference.node_id();
let node = ctx.nodes.get_node(node_id);
if ctx.nodes.flags(node_id).has_export_specifier()
&& let AstKind::IdentifierReference(ident) = node.kind()
{
ctx.errors.borrow_mut().push(undefined_export(&ident.name, ident.span));
Expand Down
18 changes: 13 additions & 5 deletions crates/oxc_semantic/src/jsdoc/finder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use rustc_hash::FxHashMap;

use oxc_span::{GetSpan, Span};

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

use super::parser::JSDoc;

Expand All @@ -18,16 +18,24 @@ impl<'a> JSDocFinder<'a> {
Self { attached, not_attached }
}

pub fn get_one_by_node<'b>(&'b self, node: &AstNode<'a>) -> Option<JSDoc<'a>> {
let jsdocs = self.get_all_by_node(node)?;
pub fn get_one_by_node<'b>(
&'b self,
nodes: &AstNodes<'a>,
node: &AstNode<'a>,
) -> Option<JSDoc<'a>> {
let jsdocs = self.get_all_by_node(nodes, node)?;

// If flagged, at least 1 JSDoc is attached
// If multiple JSDocs are attached, return the last = nearest
jsdocs.last().cloned()
}

pub fn get_all_by_node<'b>(&'b self, node: &AstNode<'a>) -> Option<Vec<JSDoc<'a>>> {
if !node.flags().has_jsdoc() {
pub fn get_all_by_node<'b>(
&'b self,
nodes: &AstNodes<'a>,
node: &AstNode<'a>,
) -> Option<Vec<JSDoc<'a>>> {
if !nodes.flags(node.id()).has_jsdoc() {
return None;
}

Expand Down
54 changes: 26 additions & 28 deletions crates/oxc_semantic/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ pub struct AstNode<'a> {
/// Associated `BasicBlockId` in CFG (initialized by control_flow)
#[cfg(feature = "cfg")]
cfg_id: BlockNodeId,

flags: NodeFlags,
}

impl<'a> AstNode<'a> {
Expand All @@ -37,21 +35,14 @@ impl<'a> AstNode<'a> {
kind: AstKind<'a>,
scope_id: ScopeId,
cfg_id: BlockNodeId,
flags: NodeFlags,
id: NodeId,
) -> Self {
Self { id, kind, scope_id, cfg_id, flags }
Self { id, kind, scope_id, cfg_id }
}

#[cfg(not(feature = "cfg"))]
pub(crate) fn new(
kind: AstKind<'a>,
scope_id: ScopeId,
_cfg_id: (),
flags: NodeFlags,
id: NodeId,
) -> Self {
Self { id, kind, scope_id, flags }
pub(crate) fn new(kind: AstKind<'a>, scope_id: ScopeId, _cfg_id: (), id: NodeId) -> Self {
Self { id, kind, scope_id }
}

/// This node's unique identifier.
Expand Down Expand Up @@ -84,18 +75,6 @@ impl<'a> AstNode<'a> {
pub fn scope_id(&self) -> ScopeId {
self.scope_id
}

/// Flags providing additional information about the node.
#[inline]
pub fn flags(&self) -> NodeFlags {
self.flags
}

/// Get a mutable reference to this node's flags.
#[inline]
pub fn flags_mut(&mut self) -> &mut NodeFlags {
&mut self.flags
}
}

impl GetSpan for AstNode<'_> {
Expand All @@ -118,6 +97,8 @@ pub struct AstNodes<'a> {
nodes: IndexVec<NodeId, AstNode<'a>>,
/// `node` -> `parent`
parent_ids: IndexVec<NodeId, NodeId>,
/// `node` -> `flags`
flags: IndexVec<NodeId, NodeFlags>,
/// 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.
Expand Down Expand Up @@ -204,6 +185,18 @@ impl<'a> AstNodes<'a> {
&mut self.nodes[node_id]
}

/// Get flags for a node.
#[inline]
pub fn flags(&self, node_id: NodeId) -> NodeFlags {
self.flags[node_id]
}

/// Get a mutable reference to a node's flags.
#[inline]
pub fn flags_mut(&mut self, node_id: NodeId) -> &mut NodeFlags {
&mut self.flags[node_id]
}

/// Get the [`Program`] that's also the root of the AST.
#[inline]
pub fn program(&self) -> &'a Program<'a> {
Expand Down Expand Up @@ -232,8 +225,9 @@ impl<'a> AstNodes<'a> {
flags: NodeFlags,
) -> NodeId {
let node_id = self.parent_ids.push(parent_node_id);
let node = AstNode::new(kind, scope_id, cfg_id, flags, node_id);
let node = AstNode::new(kind, scope_id, cfg_id, node_id);
self.nodes.push(node);
self.flags.push(flags);
self.node_kinds_set.set(kind.ty());
node_id
}
Expand All @@ -249,8 +243,9 @@ impl<'a> AstNodes<'a> {
flags: NodeFlags,
) -> NodeId {
let node_id = self.parent_ids.push(parent_node_id);
let node = AstNode::new(kind, scope_id, (), flags, node_id);
let node = AstNode::new(kind, scope_id, (), node_id);
self.nodes.push(node);
self.flags.push(flags);
self.node_kinds_set.set(kind.ty());
node_id
}
Expand All @@ -274,7 +269,8 @@ 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, flags, NodeId::ROOT));
self.nodes.push(AstNode::new(kind, scope_id, cfg_id, NodeId::ROOT));
self.flags.push(flags);
self.node_kinds_set.set(AstType::Program);
NodeId::ROOT
}
Expand All @@ -293,7 +289,8 @@ 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, (), flags, NodeId::ROOT));
self.nodes.push(AstNode::new(kind, scope_id, (), NodeId::ROOT));
self.flags.push(flags);
self.node_kinds_set.set(AstType::Program);
NodeId::ROOT
}
Expand All @@ -302,6 +299,7 @@ impl<'a> AstNodes<'a> {
pub fn reserve(&mut self, additional: usize) {
self.nodes.reserve(additional);
self.parent_ids.reserve(additional);
self.flags.reserve(additional);
}

/// Checks if the AST contains any nodes of the given types.
Expand Down
Loading