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.

Configuration

This detector does not need any configuration.