Select Case statement has no Case Else clause

ID

vbnet.maintainability.missing_switch_default

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Control Flow

Language

VB.NET

Description

Reports a Select Case statement that has at least one Case clause and no Case Else clause, so there is no branch for a value that matches none of the listed cases. A Select Case that ends in a Case Else clause is not reported, whether that clause supplies a fallback value or throws.

Rationale

A Select Case with no matching clause is legal Visual Basic and simply does nothing, which means an unexpected value produces neither an error nor a trace of having been unexpected. The variable the statement was meant to assign keeps whatever it held before, and a Function that falls past the statement returns the type’s default - Nothing, zero or False - which the caller cannot distinguish from a real result. This is exactly what happens when an enum member, a status code or a carrier code is added months later and this site is not among the ones updated: the build stays green, the tests that only cover the known values stay green, and the new value quietly renders as a blank label or prices at zero.

The following code illustrates the pattern detected by this rule:

Public Function LabelFor(ByVal state As ShipmentState) As String
    Dim label As String = String.Empty
    ' FLAGGED: Select Case statement has no Case Else clause
    Select Case state
        Case ShipmentState.Created
            label = "Awaiting packing"
        Case ShipmentState.Packed
            label = "Ready to ship"
        Case ShipmentState.Shipped
            label = "In transit"
    End Select
    Return label
End Function

Remediation

Add a Case Else clause that states what happens to every other value. Where a fallback is meaningful, make it explicit and documented - Case Else returning "Unknown carrier" is a decision a reader can check. Where no sensible fallback exists, because reaching the clause means the value came from somewhere that should have been updated, fail loudly with Throw New ArgumentOutOfRangeException(NameOf(state)), so the first unforeseen value is reported at the site that has to change rather than surfacing as wrong output downstream.

Configuration

This detector does not need any configuration.