Use of the GoTo statement
ID |
vbnet.maintainability.avoid_goto |
Severity |
low |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Control Flow |
Language |
VB.NET |
Description
Reports a GoTo statement, which transfers control to a label elsewhere in the same procedure. Only the structured GoTo is reported. The legacy error-handling forms On Error GoTo Handler and On Error GoTo 0 are a different construct and are not reported by this rule, and neither are the block-exit statements Exit For, Exit While, Exit Sub, Exit Function, Continue For and Continue While, which leave a single enclosing block rather than jumping to an arbitrary point.
Rationale
A GoTo breaks the correspondence between how the source is laid out and the order in which it runs. A reader can no longer work out how execution reached a line by looking at the lines above it, because any GoTo anywhere in the procedure may have jumped there, so understanding one branch means reading the whole procedure and tracking every label by hand. Jumping backwards also creates a loop with no header stating its termination condition, which is how procedures that never terminate on an unexpected input get shipped. Jumping forwards past declarations and assignments leaves variables holding whatever they held before, so a later line reads a value that was never computed for this path. The same jumps defeat the tools built to help here: coverage, complexity and refactoring tools all reason over structured blocks, and a labelled target cannot be extracted into a method without first untangling every jump into it.
The following code illustrates the pattern detected by this rule:
Dim total As Decimal = 0D
Dim index As Integer = 0
TryNext:
If index >= invoices.Count Then
Return total
End If
If invoices(index) < 0D Then
index += 1
' FLAGGED: Use of the GoTo statement
GoTo TryNext
End If
total += invoices(index)
index += 1
' FLAGGED: Use of the GoTo statement
GoTo TryNext
End Function
Remediation
Replace the jump with the structured statement that expresses the intent. A backwards GoTo into the middle of a procedure is a loop - write it as For Each, While or Do … Loop with the termination condition in the header. A forward GoTo that skips the rest of an iteration is Continue For or Continue While; one that skips the rest of the procedure is Return, Exit Sub or Exit Function. Where the label marks shared cleanup code, move the cleanup into a Finally block, or into a Using block if the resource implements IDisposable, so it runs on every exit path without a jump. Where the label marks error handling, use Try … Catch … End Try instead.