Skip to content

fix(linter/react): return-position JSX detection (stacked on #22755)#1

Draft
pbomb wants to merge 1 commit into
pbomb/react-display-name-false-positive-basefrom
pbomb/react-display-name-returns-jsx
Draft

fix(linter/react): return-position JSX detection (stacked on #22755)#1
pbomb wants to merge 1 commit into
pbomb/react-display-name-false-positive-basefrom
pbomb/react-display-name-returns-jsx

Conversation

@pbomb

@pbomb pbomb commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Note

Stacked on top of oxc-project#22755. The base branch here is a snapshot of that PR's head, so this PR's diff is only the delta — it can be cherry-picked / squashed straight into oxc-project#22755 if accepted. It is intentionally kept separate so oxc-project#22755's author can decide whether to incorporate it.

AI usage disclosure

Implemented with Claude Code, then reviewed and tested by me.

Summary

Addresses the change-request review on oxc-project#22755 (review). That PR narrowed the shared JsxFinder so JSX in call-argument position is ignored everywhere — which (1) changes behavior for every *_contains_jsx consumer (no-multi-comp, prefer-function-component, …) and (2) is narrower than upstream eslint-plugin-react, which still reports HOFs that return JSX via conditionals / logical exprs / sequences / JSX-valued identifiers.

This delta swaps that approach for dedicated return-position helpers, used only where component detection is intended, and restores the shared helpers to their original "JSX anywhere" semantics.

Details

  • Revert the JsxFinder change — expression_contains_jsx / function_body_contains_jsx / function_contains_jsx are unchanged for all other rules.
  • New helpers in utils/react.rs: expression_returns_jsx, function_returns_jsx, function_body_returns_jsx, arrow_returns_jsx, plus private expression_is_jsx_value. They detect JSX in return position — recognizing ?:, &&/||, sequence expressions, React.createElement, and JSX-valued identifiers (const x = <div/>; return x;) — while ignoring JSX passed only as a call argument.
  • Swapped call sites (arrow/HOF component-detection only): display-name (variable declarator + find_innermost_function_with_jsx) and no-unstable-nested-components (arrow candidate + parent-component lookup). Named-function and HOC-argument paths are left on the shared helpers to avoid behavior drift.

Tests

Generated with Claude Code

…narrowing shared helper

Replaces the change to the shared `JsxFinder` (which affected every
`*_contains_jsx` consumer) with dedicated return-position helpers used only
where component detection is intended.

- revert `JsxFinder` to "JSX anywhere"; `expression_contains_jsx` /
  `function_body_contains_jsx` / `function_contains_jsx` are unchanged for all
  other rules.
- add `expression_returns_jsx` / `function_returns_jsx` /
  `function_body_returns_jsx` / `arrow_returns_jsx` (plus private
  `expression_is_jsx_value`): JSX in return position, recognizing conditionals,
  logical/sequence expressions, `React.createElement`, and JSX-valued
  identifiers; ignoring JSX passed only as a call argument.
- use the returns helpers in display-name (variable declarator +
  `find_innermost_function_with_jsx`) and no-unstable-nested-components
  (arrow candidate + parent-component lookup).
- regression guards in no-multi-comp / prefer-function-component pin the shared
  helpers' "JSX anywhere" behavior (these fail if `JsxFinder` is re-narrowed).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant