Bitwise Number Truncation
ID |
javascript.bitwise_number_truncation |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
numeric, reliability, simplification |
Description
Reports the three bit operations used as a shorthand for dropping a number’s fractional part: x | 0, ~~x and x >> 0. None of them does any bitwise work — the operand is converted to a signed 32-bit integer, the operation leaves every bit alone, and the integer is converted back.
const index = position | 0; // FLAW
const index = ~~position; // FLAW
const index = position >> 0; // FLAW
Only the exact truncation spellings are matched. A shift by anything but zero and a mask against anything but zero are genuine bit operations and are left alone, as is x >>> 0 — the documented way to coerce to an unsigned 32-bit integer, deliberate wherever it appears.
Rationale
-
The conversion, not the syntax, is the problem. It is defined over signed 32 bits, so every value outside that range comes back wrong rather than merely rounded:
3e9 | 0is-1294967296. -
NaN | 0is0. A truncation that silently turns "not a number" into a valid-looking zero removes the one signal downstream code had. -
Array indices, millisecond timestamps and byte counts all reach those magnitudes in production while every test fixture stays comfortably below them, so the defect is invisible until it is not.
-
The three spellings also read as bit manipulation to anyone scanning the file, which sends the reader looking for a mask that is not there.
Remediation
Say what is meant. Math.trunc drops the fractional part over the whole range of a double; Math.floor and Math.round are there when rounding, rather than truncation, is what the code wants.
const index = Math.trunc(position);
const index = Math.floor(position);