Overview
- Category: Good Practice (
BCC3xxx)
- Severity: Warning
- Target:
switch statements and switch expressions (SwitchStatementSyntax, SwitchExpressionSyntax)
Description
This rule ensures that when a switch block operates on an enum type expression, it explicitly handles every single defined value within that enumeration.
If any enum member is omitted from the switch labels, the analyzer triggers a warning. This forces developers to intentionally define the behavior for every possible enum state, significantly hardening the application against unhandled branch bugs.
Why is this rule needed?
Enumerations often expand over time as business requirements evolve. A developer might add a new status value (e.g., Suspended to a UserStatus enum) but forget to update the various switch structures scattered across the codebase that map or process that status.
Relying solely on a default: catch-all branch can obscure these omissions:
- Silent Fall-Through / Logic Bugs: If the
default branch simply returns a generic value or log statement, the application fails silently or acts unpredictably when processing the new enum value.
- Defensive Programming: Forcing explicit coverage for every case means that as soon as a new enum value is added, the compiler/analyzer will immediately point out every single location in the code that needs to be updated to support it.
Code Examples
Non-Compliant
A new order status (Shipped) was added to the enum, but this switch statement was left un-updated, causing it to fall into an unintended or generic fallback block.
public enum OrderStatus { Pending, Processing, Shipped, Cancelled }
public void HandleOrder(OrderStatus status)
{
// Violation: 'Shipped' is completely missing from the switch sections
switch (status)
{
case OrderStatus.Pending:
PreparePackage();
break;
case OrderStatus.Processing:
ChargeCustomer();
break;
case OrderStatus.Cancelled:
RestockItems();
break;
}
}
Compliant
Every enum value maps to its dedicated handling path. If a new member is added later, this block will immediately trigger a fresh BCC3008 warning until updated.
public void HandleOrder(OrderStatus status)
{
switch (status)
{
case OrderStatus.Pending:
PreparePackage();
break;
case OrderStatus.Processing:
ChargeCustomer();
break;
case OrderStatus.Shipped:
DispatchCourier();
break;
case OrderStatus.Cancelled:
RestockItems();
break;
default:
throw new ArgumentOutOfRangeException(nameof(status), status, null);
}
}
Implementation Heuristic & Technical Tips (Roslyn API)
Analyzer Logic (DiagnosticAnalyzer)
- Register a Syntax Node Action targeting
SyntaxKind.SwitchStatement and SyntaxKind.SwitchExpression.
- Use the
SemanticModel to obtain the type information of the governing expression (switch (expression)). Verify that its ITypeSymbol has a TypeKind equal to TypeKind.Enum.
- Extract Declared Enum Values: Cast the symbol to
INamedTypeSymbol and retrieve all fields that are enum constants (GetMembers().OfType<IFieldSymbol>()). Compile a list of their underlying constant values or names.
- Analyze Switch Labels:
- For
SwitchStatementSyntax, iterate through the Sections and analyze each CaseSwitchLabelSyntax.
- For
SwitchExpressionSyntax, iterate through the Arms.
- Use the semantic model to resolve which enum constant symbol each label refers to.
- Compare and Match: Subtract the covered constants from the master list of declared enum fields.
- Apply Flags Exception: Check if the enum type is decorated with the
[System.Flags] attribute. If it is a bitwise flag enum, abort the analysis, as exhaustive switch checks are mathematically unfeasible and inappropriate for bitwise combinations.
- If any standard enum value is completely omitted, report
BCC3008 on the switch keyword token, listing the missing enum members in the diagnostic message.
Overview
BCC3xxx)switchstatements andswitchexpressions (SwitchStatementSyntax,SwitchExpressionSyntax)Description
This rule ensures that when a
switchblock operates on anenumtype expression, it explicitly handles every single defined value within that enumeration.If any enum member is omitted from the switch labels, the analyzer triggers a warning. This forces developers to intentionally define the behavior for every possible enum state, significantly hardening the application against unhandled branch bugs.
Why is this rule needed?
Enumerations often expand over time as business requirements evolve. A developer might add a new status value (e.g.,
Suspendedto aUserStatusenum) but forget to update the variousswitchstructures scattered across the codebase that map or process that status.Relying solely on a
default:catch-all branch can obscure these omissions:defaultbranch simply returns a generic value or log statement, the application fails silently or acts unpredictably when processing the new enum value.Code Examples
Non-Compliant
A new order status (
Shipped) was added to the enum, but this switch statement was left un-updated, causing it to fall into an unintended or generic fallback block.Compliant
Every enum value maps to its dedicated handling path. If a new member is added later, this block will immediately trigger a fresh
BCC3008warning until updated.Implementation Heuristic & Technical Tips (Roslyn API)
Analyzer Logic (
DiagnosticAnalyzer)SyntaxKind.SwitchStatementandSyntaxKind.SwitchExpression.SemanticModelto obtain the type information of the governing expression (switch (expression)). Verify that itsITypeSymbolhas aTypeKindequal toTypeKind.Enum.INamedTypeSymboland retrieve all fields that are enum constants (GetMembers().OfType<IFieldSymbol>()). Compile a list of their underlying constant values or names.SwitchStatementSyntax, iterate through theSectionsand analyze eachCaseSwitchLabelSyntax.SwitchExpressionSyntax, iterate through theArms.[System.Flags]attribute. If it is a bitwise flag enum, abort the analysis, as exhaustive switch checks are mathematically unfeasible and inappropriate for bitwise combinations.BCC3008on theswitchkeyword token, listing the missing enum members in the diagnostic message.