perf(linter/react-exhaustive-deps): use stack of AstTypes instead of AstKinds (#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`.
This commit is contained in:
overlookmotel 2025-01-16 00:32:38 +00:00
parent a6d71f8f27
commit 250bbd193b

View file

@ -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;
@ -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>>,
@ -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>) {
@ -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) => {
@ -1110,9 +1108,10 @@ 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;
}
@ -1120,20 +1119,17 @@ impl<'a> Visit<'a> for ExhaustiveDepsVisitor<'a, '_> {
}
}
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;
}
}
_ => {}
}
}