org.sonar.plugins.csharp.S2183.html Maven / Gradle / Ivy
Why is this an issue?
The shifting
operators are used to do an arithmetic shift to the bits of an integral numeric value, either to
the left or the right.
var number = 14; // ...01110 (14)
var left = number << 1; // ...11100 (28)
var right = number >> 1; // ...00111 (7)
Therefore, shifting an integral number by 0 is equivalent to doing nothing, since the bits do not move any positions to the left or the right.
On the other hand, shifting an integral number by a value greater than their count of bits minus one (n_bits-1
) is equivalent to
shifting by the value modulo the bit count of the number (value % n_bits
).
In the case of int
and uint
, which take 32 bits in the memory, the shift count is given by the five low-order bits of the
second operand, which can represent numbers from 0 to 31. This means that numbers having the same five low-order bits are treated the same by the
shift operators.
var one = 0b0_00001;
var thirtyThree = 0b1_00001; // Same five low-order bits, 33 % 32 = 1
var shifted1 = 42 << one; // Results in 84
var shifted2 = 42 << thirtyThree; // Results in 84
Note that integral number with a less than 32-bit quantity (e.g. short
, ushort
) are implicitly converted to
int
before the shifting operation and so the rule for int
/uint
applies.
If the first operand is a long
or ulong
(64-bit quantity), the shift count is given by the six low-order bits of the
second operand. That is, the actual shift count is 0 to 63 bits.
Exceptions
This rule doesn’t raise an issue when the shift by zero is obviously for cosmetic reasons:
- When the value shifted is a literal.
- When there is a similar shift at the same position on line before or after. E.g.:
bytes[loc+0] = (byte)(value >> 8);
bytes[loc+1] = (byte)(value >> 0);
How to fix it
Code examples
Noncompliant code example
short s = 1;
short shortShift1 = (short)(s << 0); // Noncompliant: the value does not change
short shortShift2 = (short)(s << 33); // Noncompliant: this is equivalent to shifting by 1
int i = 1;
int intShift = i << 33; // Noncompliant: this is equivalent to shifting by 1
long lg = 1;
long longShift1 = lg << 0; // Noncompliant: the value does not change
long longShift2 = lg << 65; // Noncompliant: this is equivalent to shifting by 1
Compliant solution
short s = 1;
short shortShift1 = s;
short shortShift2 = (short)(s << 1);
int i = 1;
var intShift = i << 1;
long lg = 1;
var longShift1 = lg;
var longShift2 = lg << 1;
Resources
Documentation
- Microsoft Learn - Bitwise and
shift operators (C# reference)
- Wikipedia - Arithmetic shift
- Wikipedia - Modulo