Skip to content

fix(linter/react): react/display-name no longer flags arrows that only pass JSX as an argument#22755

Closed
kapobajza wants to merge 8 commits into
oxc-project:mainfrom
kapobajza:fix/linter-react-display-name-false-positive
Closed

fix(linter/react): react/display-name no longer flags arrows that only pass JSX as an argument#22755
kapobajza wants to merge 8 commits into
oxc-project:mainfrom
kapobajza:fix/linter-react-display-name-false-positive

Conversation

@kapobajza

@kapobajza kapobajza commented May 27, 2026

Copy link
Copy Markdown
Contributor

AI usage disclosure

I've used Claude Code to assist me with the solution, and it has been reviewed and tested by me. I've also used it to generate more tests to harden the fix, and avoid introducing regressions.
I've also used it to generate this PR description.

Summary

Closes #22685
Closes #22608

react/display-name reported a false positive for higher-order functions whose inner arrow contains JSX but never returns it:

const createHandler = () => () => {
  someGlobalFunc(<div />); // JSX is an argument, not a return value
};

This is a utility function, not a component, so the rule should stay silent.

Cause

expression_contains_jsx detected JSX anywhere in an arrow function's body (via a full visitor walk), so JSX passed as a call argument was treated the same as JSX returned from the component.

Fix

For arrow functions, expression_contains_jsx now only inspects the return position — the concise-body expression, or top-level return statements — instead of the whole body. JSX appearing only as a call argument no longer counts as a component.

The full-walk helper (function_body_contains_jsx) is left untouched and still used by the anonymous-export path and by no-multi-comp / no-unstable-nested-components / prefer-function-component, so their behavior is unchanged.

@kapobajza
kapobajza requested a review from camc314 as a code owner May 27, 2026 09:36
@codspeed-hq

codspeed-hq Bot commented May 27, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 5 untouched benchmarks
⏩ 66 skipped benchmarks1


Comparing kapobajza:fix/linter-react-display-name-false-positive (26d8887) with main (a421215)

Open in CodSpeed

Footnotes

  1. 66 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@camc314 camc314 added the A-linter Area - Linter label May 27, 2026

@camc314 camc314 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix. I agree with the underlying issue: react/display-name should not treat an inner arrow as a component just because JSX appears as a call argument.

However, this change narrows the sharedexpression_contains_jsx helper which is also used by the other react rules. It also becomes narrower than upstream eslint-plugin-react: upstream allows the reported someGlobalFunc(<div />) case, but still reports HOFs that return JSX through conditionals, logical expressions, sequences, or JSX-valued identifiers.

For example, upstream still reports:

const renderer = a => listItem => cond ? <div>{listItem}</div> : null;
const renderer = a => listItem => { const x = <div>{listItem}</div>; return x; };

This branch no longer reports those cases.

I'll take a look at another approach to fixing this issue

@kapobajza

Copy link
Copy Markdown
Contributor Author

However, this change narrows the sharedexpression_contains_jsx helper which is also used by the other react rules. It also becomes narrower than upstream eslint-plugin-react: upstream allows the reported someGlobalFunc(<div />) case, but still reports HOFs that return JSX through conditionals, logical expressions, sequences, or JSX-valued identifiers.

I see where that's coming from. I was also worried about introducing regressions with these changes, but since all of the tests passed, that gave me at least a bit of confidence.

I'll take a look at another approach to fixing this issue

I will also try thinking about another solution. One where we wouldn't have to worry about regressions (at least not obvious ones), and that would also cover these cases you mentioned:

const renderer = a => listItem => cond ? <div>{listItem}</div> : null;
const renderer = a => listItem => { const x = <div>{listItem}</div>; return x; };

Anyways, thanks for the feedback. If I come up with a different solution than the current one before you, I will push the changes to this PR.

@camc314 camc314 self-assigned this May 28, 2026
@kapobajza

kapobajza commented May 28, 2026

Copy link
Copy Markdown
Contributor Author

Hey @camc314. I've come up with a different solution, which reverts my previous changes and introduces a new field, is_in_argument, to the JsxFinder visitor. You can find the gist of it here: https://github.com/oxc-project/oxc/pull/22755/changes#diff-c559e7c3a5671192062891f14906b459ceef7fecd9ab6db4bf081ecd8395879bR875-R891

I have to admit that I am not really proud of it, since I have a gut feeling that this could've been done in a better, cleaner way. But I might be wrong, please do let me know about it!

@kapobajza
kapobajza requested a review from camc314 May 28, 2026 17:22
@kapobajza

Copy link
Copy Markdown
Contributor Author

I've realized that the changes in this PR are also applicable to #22608. So I've added test cases to also cover them.

@pbomb

pbomb commented Jun 23, 2026

Copy link
Copy Markdown

@kapobajza Just wanted to see what the status of this was and if there's anything I could do to help get this across the line since a bug this fixes is impacting us.

@kapobajza

Copy link
Copy Markdown
Contributor Author

@kapobajza Just wanted to see what the status of this was and if there's anything I could do to help get this across the line since a bug this fixes is impacting us.

Hey @pbomb. I've come up with a solution that works, the test cases pass, but I am not particularly proud of it. I have a gut feeling that there might be a better way to do it. Right now I am waiting for @camc314 to review it, and if this is fine as it is, we might be able to proceed with it. However, if it's not fine, then we would have to come up with something better.

And thank you for offering your help! If you have a better solution in mind, than the one I already implemented, I would be grateful if you could let me know!

@pbomb

pbomb commented Jun 24, 2026

Copy link
Copy Markdown

@kapobajza @camc314 I (and Claude) created this stacked PR that attempts to address the PR feedback here. I didn't want to push to this branch, so if you like the direction, we can merge it into this one and if not, we can just drop it.

graphite-app Bot pushed a commit that referenced this pull request Jul 15, 2026
## Summary

- detect React function components from reachable JSX/null returns using a shared CFG utility
- avoid function-component-definition false positives for callbacks, lowercase helpers, class methods, and functions that only contain JSX
- avoid display-name false positives for higher-order functions that contain but do not return JSX

fixes  [https://github.com/oxc-project/oxc/issues/22685](https://github.com/oxc-project/oxc/issues/22685)

closes [#22755](#22755)

follow up to #24471
graphite-app Bot pushed a commit that referenced this pull request Jul 15, 2026
## Summary

- detect React function components from reachable JSX/null returns using a shared CFG utility
- avoid function-component-definition false positives for callbacks, lowercase helpers, class methods, and functions that only contain JSX
- avoid display-name false positives for higher-order functions that contain but do not return JSX

fixes  [https://github.com/oxc-project/oxc/issues/22685](https://github.com/oxc-project/oxc/issues/22685)

closes [#22755](#22755)

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

Labels

A-linter Area - Linter

Projects

None yet

3 participants