Skip to content

fix(linter): fix useExhaustiveDependencies false positive with arrow function params#8906

Closed
ddmoney420 wants to merge 1 commit intobiomejs:mainfrom
ddmoney420:fix/8883-exhaustive-deps-false-positive
Closed

fix(linter): fix useExhaustiveDependencies false positive with arrow function params#8906
ddmoney420 wants to merge 1 commit intobiomejs:mainfrom
ddmoney420:fix/8883-exhaustive-deps-false-positive

Conversation

@ddmoney420
Copy link

Summary

Fixes false positive in useExhaustiveDependencies rule when props are destructured in function body or accessed directly with arrow function params without parentheses.

Problem

The rule incorrectly flagged hook dependencies as "unnecessary" when:

  1. Arrow functions used parameters without parentheses (e.g., props =>)
  2. Props were accessed via destructuring in function body (e.g., const { msg } = props)

Example that was incorrectly flagged:

const Component: React.FC<Props> = props => {
  const { msg } = props
  useEffect(() => console.log(msg), [msg]); // ❌ false positive: "msg" is unnecessary
};

Root Cause

The bug was in the is_stable_expression function. It had a "self-reference" check that returned true (stable) when an identifier's ancestors included its declaration node.

For arrow functions with parameters without parentheses (props =>), the binding's declaration is the entire JsArrowFunctionExpression. Since the arrow function is an ancestor of any identifier used inside it, the check incorrectly returned true for parameter usages in the body.

Solution

Modified the self-reference check to exclude arrow function parameters, formal parameters, and rest parameters from being considered "stable self-references":

if is_ancestor
    && !matches!(
        decl,
        AnyJsBindingDeclaration::JsArrowFunctionExpression(_)
            | AnyJsBindingDeclaration::JsFormalParameter(_)
            | AnyJsBindingDeclaration::JsRestParameter(_)
    )
{
    return true;
}

Test plan

  • Added test case covering all scenarios from the issue
  • All existing useExhaustiveDependencies tests pass (53 tests)
  • All biome_js_analyze tests pass (1990 tests)

AI Disclosure

This PR was written primarily by Claude Code (AI assistant).

Fixes #8883

🤖 Generated with Claude Code

…function params

The rule incorrectly flagged hook dependencies as "unnecessary" when:
1. Arrow functions used parameters without parentheses (e.g., `props =>`)
2. Props were accessed via destructuring in function body

Root cause: The self-reference check in `is_stable_expression` returned
`true` for any identifier whose declaration node was an ancestor. For
arrow functions, the entire expression is the declaration, so any
parameter usage in the body was incorrectly marked as stable.

Fix: Exclude arrow function parameters, formal parameters, and rest
parameters from being considered stable self-references.

Fixes biomejs#8883

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@changeset-bot
Copy link

changeset-bot bot commented Jan 29, 2026

⚠️ No Changeset found

Latest commit: b6de69d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions bot added A-Linter Area: linter L-JavaScript Language: JavaScript and super languages labels Jan 29, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

Walkthrough

This PR fixes false positives in the useExhaustiveDependencies linter rule. The changes refine the is_stable_binding function to check for binding declarations before pattern matching, and update is_stable_expression to accurately determine whether an identifier's declaration is an ancestor of the reference. The logic now treats unknown references as stable rather than potentially unstable. A new test file validates the fix for destructuring in function bodies versus parameters.

Possibly related PRs

Suggested labels

A-Linter, L-JavaScript

Suggested reviewers

  • dyc3
  • ematipico
  • arendjr
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: addressing a false positive in useExhaustiveDependencies when arrow function params lack parentheses.
Description check ✅ Passed The description clearly explains the problem, root cause, solution, and test coverage—all directly related to the code changes.
Linked Issues check ✅ Passed The PR directly addresses issue #8883 by fixing the false positive when props are destructured in function body or accessed via arrow function params, and preserves detection of actual missing dependencies.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the reported issue: modifications to is_stable_expression logic and an aligned test case for the specific scenarios.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Netail
Copy link
Member

Netail commented Jan 29, 2026

I believe this has already been included in #8900

@ematipico
Copy link
Member

Thank you @ddmoney420 . We will go with #8900 fix

@ematipico ematipico closed this Jan 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Linter Area: linter L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 useExhaustiveDependencies: False positive when destructuring props in function body

3 participants