Skip to content

fix: resolve local member .use() false positive in rules-of-hooks - #1798

Draft
skoshx wants to merge 1 commit into
mainfrom
cursor/triage-1797-20db
Draft

skoshx wants to merge 1 commit into
mainfrom
cursor/triage-1797-20db

Conversation

@skoshx

@skoshx skoshx commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Root Cause

rules-of-hooks was incorrectly treating all PascalCase member calls with .use() as React hooks, without verifying if the receiver was actually from React.

Example false positive:

declare const Service: {
  use: (callback: (value: string) => unknown) => unknown;
};

export const fixture = async () => {
  Service.use((value) => value); // ❌ Incorrectly reported as hook violation
};

The issue was in isHookCall at line 225-240: after checking isPackageImportedNonReactHookMemberCallee for imports, the code would return { hookName: propertyName } for any PascalCase identifier without verifying it resolves to React.

Fix

Added a targeted check that verifies .use() member call receivers actually resolve to React:

if (propertyName === "use") {
  const symbol = scopes.symbolFor(callObject);
  if (symbol) {
    const reactName = resolveReactImportName(symbol, scopes);
    if (!reactName || reactName === "use") return null;
  }
}

This reuses the existing resolveReactImportName helper (used for bare use() calls) to trace the receiver's origin.

Scope

Narrowly scoped to .use() member calls only:

  • Service.use(...) where Service is local → no longer reported (false positive fixed)
  • React.use(...) → still correctly reported in async functions
  • ✅ Bare use(...) from React import → still correctly reported
  • useState(), useEffect(), other hooks → unchanged behavior

Testing

  • Unit tests: Added 6 comprehensive regression tests covering:
    • Declared local APIs (Service.use)
    • Local classes (Api.use)
    • Const objects (Database.use)
    • React namespace calls (still flagged)
    • Bare React imports (still flagged)
    • Plugin registration pattern (X.use([]))
  • Full suite: All 27,642 existing tests pass
  • Manual validation: Tested against the reported case - false positive resolved

Parity Status

🔄 In progress: Running rde run path:/agent/repos/react-doctor to scan the corpus with the fix (1,444+ repos processed so far). Will follow up with rde parity npm:0.9.13 path:/agent/repos/react-doctor comparison once complete.

Given the narrow scope (only .use() member calls with local receivers), low risk of cross-repo regressions.

Checklist

  • Root cause identified and documented
  • Fix implemented with minimal scope
  • Regression tests added (6 new tests)
  • All tests pass (27,642 tests)
  • Manual validation confirms fix works
  • Changeset added
  • rde parity clean (scan in progress)
  • CI passing
  • Code review addressed

Closes #1797

Open in Web Open in Cursor 

- Skip member calls like Service.use(...) where Service is a local identifier
- Preserve detection of React.use(...) and destructured use(...)
- Add comprehensive regression tests for local member APIs
- Fixes #1797

Co-authored-by: Skosh <skoshx@users.noreply.github.com>
@pkg-pr-new

pkg-pr-new Bot commented Sep 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/eslint-plugin-react-doctor@1798
npm i https://pkg.pr.new/oxlint-plugin-react-doctor@1798
npm i https://pkg.pr.new/react-doctor@1798

commit: 9bed834

@github-actions

Copy link
Copy Markdown
Contributor

Interactive terminal E2E

Terminal Control verified the built CLI at 9bed834 in a real PTY:

  • selected a project interactively and observed Scanning... before the three-second Git delay completed
  • waited for the clean result and exercised the compact report
  • opened copy context and the GitHub Actions confirmation, then cancelled safely

Download the edited MP4 and PNG evidence

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rules-of-hooks: local member methods named .use are misclassified as React hooks

2 participants