Shift Operand Must Be Int

ID

csharp.shift_operand_must_be_int

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Code Smell

Language

CSharp

Tags

code_smell, suspicious-operator, type-conversion

Description

Reports a shift (<<, >>, <⇐, >>=) whose left operand is declared dynamic and whose shift count cannot convert to int — a floating-point literal, null, a string, or a newly constructed object.

Rationale

Declaring an operand dynamic moves overload resolution from compile time to run time. That is the point of the feature, but it also means the diagnostics the compiler would normally give up front are gone. Shift is a good example: with a statically typed left operand, x << 5.4 does not build. With a dynamic left operand the same expression builds without a word and throws when the line executes, from inside the runtime binder, with a message about candidate operators rather than about the value that was actually wrong.

Shifts on statically typed operands are not reported at all — the compiler already enforces the shift count there, and second-guessing it would only add noise. When the left operand cannot be traced back to a dynamic declaration, the rule stays silent.

public class Bits
{
    public dynamic Wrong(dynamic value)
    {
        return value << 5.4;      // FLAW — throws at run time, not at build time
    }

    public dynamic WrongNull(dynamic value)
    {
        return value >> null;     // FLAW — null is not a shift count
    }

    public dynamic Right(dynamic value)
    {
        return value << 2;        // OK — an int shift count
    }

    public int Static(int value)
    {
        return value << 2;        // OK — the compiler checks this shift
    }
}

Remediation

Supply an int shift count, converting explicitly where the value comes from somewhere else. If the shift count is genuinely computed at run time, validate and convert it before the shift so a bad value surfaces as your own error rather than a binder exception. Where the left operand does not need late binding, give it a static type and let the compiler check the expression.