== Why is this an issue?

The https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#left-shift-operator-[shifting] operators are used to do an https://en.wikipedia.org/wiki/Arithmetic_shift[arithmetic shift] to the bits of an https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types[integral numeric] value, either to the left or the right. 

[source,csharp]
----
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 https://en.wikipedia.org/wiki/Modulo[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.

[source,csharp]
----
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.

include::../exceptions.adoc[]

== How to fix it

=== Code examples

==== Noncompliant code example

[source,csharp,diff-id=1,diff-type=noncompliant]
----
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

[source,csharp,diff-id=1,diff-type=compliant]
----
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 - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#left-shift-operator-[Bitwise and shift operators (C# reference)]
* Wikipedia - https://en.wikipedia.org/wiki/Arithmetic_shift[Arithmetic shift]
* Wikipedia - https://en.wikipedia.org/wiki/Modulo[Modulo]

include::../rspecator.adoc[]
