Skip to content

Commit

Permalink
perf(linter/react-exhaustive-deps): use stack of AstTypes instead o…
Browse files Browse the repository at this point in the history
…f `AstKind`s (#8522)

This lint rule keeps a stack tracing the "visitation path" during `Visit`. Only the type of the nodes is used, not their values, so store only `AstType` (1 byte) rather than `AstKind` (16 bytes).

This should be more performant, but the main motivation is #8461. This is one of very few places in the codebase which uses `enter_node` and `leave_node`. Not storing `AstKind`s here clears the way to remove the unsound lifetime extension in `Visit::alloc`.
  • Loading branch information
overlookmotel committed Jan 16, 2025
1 parent a6d71f8 commit 250bbd1
Showing 1 changed file with 15 additions and 19 deletions.
34 changes: 15 additions & 19 deletions crates/oxc_linter/src/rules/react/exhaustive_deps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use oxc_ast::{
},
match_expression,
visit::walk::walk_function_body,
AstKind, Visit,
AstKind, AstType, Visit,
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
Expand Down Expand Up @@ -973,7 +973,7 @@ fn func_call_without_react_namespace<'a>(

struct ExhaustiveDepsVisitor<'a, 'b> {
semantic: &'b Semantic<'a>,
stack: Vec<AstKind<'a>>,
stack: Vec<AstType>,
skip_reporting_dependency: bool,
set_state_call: bool,
found_dependencies: FxHashSet<Dependency<'a>>,
Expand All @@ -999,7 +999,7 @@ impl<'a, 'b> ExhaustiveDepsVisitor<'a, 'b> {

impl<'a> Visit<'a> for ExhaustiveDepsVisitor<'a, '_> {
fn enter_node(&mut self, kind: AstKind<'a>) {
self.stack.push(kind);
self.stack.push(kind.ty());
}

fn leave_node(&mut self, _kind: AstKind<'a>) {
Expand Down Expand Up @@ -1041,10 +1041,8 @@ impl<'a> Visit<'a> for ExhaustiveDepsVisitor<'a, '_> {
return;
}

let is_parent_call_expr = self
.stack
.get(self.stack.len() - 2)
.is_some_and(|kind| matches!(kind, AstKind::CallExpression(_)));
let is_parent_call_expr =
self.stack.get(self.stack.len() - 2).is_some_and(|&ty| ty == AstType::CallExpression);

match analyze_property_chain(&it.object, self.semantic) {
Ok(source) => {
Expand Down Expand Up @@ -1110,30 +1108,28 @@ impl<'a> Visit<'a> for ExhaustiveDepsVisitor<'a, '_> {
};

if is_set_state_call
&& self.stack.iter().all(|kind| {
!matches!(kind, AstKind::Function(_) | AstKind::ArrowFunctionExpression(_))
})
&& self
.stack
.iter()
.all(|&ty| !matches!(ty, AstType::Function | AstType::ArrowFunctionExpression))
{
self.set_state_call = true;
}
}
}
}

fn is_inside_effect_cleanup(stack: &[AstKind<'_>]) -> bool {
fn is_inside_effect_cleanup(stack: &[AstType]) -> bool {
let mut iter = stack.iter().rev();
let mut is_in_returned_function = false;

while let Some(cur) = iter.next() {
match cur {
AstKind::Function(_) | AstKind::ArrowFunctionExpression(_) => {
if let Some(parent) = iter.next() {
if matches!(parent, AstKind::ReturnStatement(_)) {
is_in_returned_function = true;
}
while let Some(&cur) = iter.next() {
if matches!(cur, AstType::Function | AstType::ArrowFunctionExpression) {
if let Some(&parent) = iter.next() {
if parent == AstType::ReturnStatement {
is_in_returned_function = true;
}
}
_ => {}
}
}

Expand Down

0 comments on commit 250bbd1

Please sign in to comment.