Skip to content

fix(linter/unicorn/prefer-math-trunc): don't suggest a fix for a side-effecting assignment LHS#23531

Closed
hyf0 wants to merge 1 commit into
oxc-project:mainfrom
hyf0:fix/prefer-math-trunc-side-effect
Closed

fix(linter/unicorn/prefer-math-trunc): don't suggest a fix for a side-effecting assignment LHS#23531
hyf0 wants to merge 1 commit into
oxc-project:mainfrom
hyf0:fix/prefer-math-trunc-side-effect

Conversation

@hyf0

@hyf0 hyf0 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Bug

The x |= 0x = Math.trunc(x) suggestion is built by duplicating the assignment LHS source text. For a side-effecting LHS this re-runs the side effect:

foo[i++] |= 0      // suggested: foo[i++] = Math.trunc(foo[i++])   → `i++` runs twice
obj[bar()] ^= 0    // → obj[bar()] = Math.trunc(obj[bar()])        → `bar()` runs twice
getFoo().baz >>= 0 // → getFoo().baz = Math.trunc(getFoo().baz)    → `getFoo()` runs twice

Expected

Side-effecting LHS should still be reported but offered NO fix/suggestion — eslint-plugin-unicorn guards exactly this (if (!isAssignment || !hasSideEffect(left, sourceCode))).

Fix

Detect a side effect in the assignment LHS (Call / New / Update / Await / Yield / Assignment / dynamic import / delete — matching eslint-utils hasSideEffect) via a small Visit walker, and report without a suggestion in that case. Side-effect-free targets (x, foo.bar, [foo][0]) still get the fix. Regression tests added for the side-effecting cases.

Prepared with AI assistance.

…-effecting assignment LHS

The `x |= 0` → `x = Math.trunc(x)` suggestion duplicates the assignment LHS
source text. For a side-effecting LHS this re-runs the side effect: e.g.
`foo[i++] |= 0` was suggested as `foo[i++] = Math.trunc(foo[i++])`, evaluating
`i++` twice; likewise `obj[bar()] ^= 0`, `getFoo().baz >>= 0`, etc.

Detect a side effect in the LHS (Call / New / Update / Await / Yield /
Assignment / dynamic `import` / `delete`, matching eslint-plugin-unicorn's
`hasSideEffect`) and report without a suggestion in that case. Side-effect-free
targets (`x`, `foo.bar`, `[foo][0]`) still get the fix.
@hyf0 hyf0 marked this pull request as ready for review June 17, 2026 03:00
@hyf0 hyf0 requested a review from camc314 as a code owner June 17, 2026 03:00
@codspeed-hq

codspeed-hq Bot commented Jun 17, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 5 untouched benchmarks
⏩ 66 skipped benchmarks1


Comparing hyf0:fix/prefer-math-trunc-side-effect (4642659) with main (1a40b71)

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 self-assigned this Jun 17, 2026
@camc314 camc314 added the A-linter Area - Linter label Jun 17, 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 working on this.

The approach you've taken doesn't work correctly in certain scenarios.

For example, given the following:

obj.foo.bar |= 0;

The current suggestion would become:

obj.foo.bar = Math.trunc(obj.foo.bar);

which evaluates obj.foo twice.

If that property read is a getter/proxy, this suggestion can change behaviour.

@hyf0

hyf0 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

#23531

@hyf0 hyf0 closed this Jun 17, 2026
graphite-app Bot pushed a commit that referenced this pull request Jun 17, 2026
…ffects (#23548)

closes #23531

fixes the edge cases mentioned in my review of #23531
camc314 added a commit that referenced this pull request Jul 3, 2026
…ffects (#23548)

closes #23531

fixes the edge cases mentioned in my review of #23531
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

Development

Successfully merging this pull request may close these issues.

2 participants