Duplicate Branches

ID

go.duplicate_branches

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Code Smell

Language

Go

Tags

code-style, duplicate-code

Description

Reports a conditional structure whose branches all run exactly the same code: an if / else pair or an if / else if / else chain where every body is identical, or a switch where every case, default included, is identical.

Requiring every branch to match — rather than any two of them — is what keeps the rule quiet across the whole chain and the switch. Two arms of a long dispatch chain sharing a body is a deliberate idiom; all of them sharing a body is always a defect, whatever the body’s size.

The rest of the scope is deliberately narrow too:

  • The chain must be complete — an if / else if with no trailing else is not a candidate, because falling through the whole chain does something different from entering any branch. A switch must likewise carry a default, and hold at least two clauses.

  • Empty bodies are left alone: an empty branch may be a deliberate no-op, and an empty if body is already reported by go.empty_if_body.

  • Type switches are excluded. In switch t := v.(type) the guard variable has a different static type in each case, so two textually identical bodies do not run the same code.

Branch bodies are compared over the parsed token sequence, so comments and formatting differences between branches are ignored.

Rationale

When every branch does the same thing, the condition decides nothing. Either the structure is dead weight that should collapse to its body, or — far more often — a branch was copy-pasted and the edit that was supposed to follow never happened. The second reading is the dangerous one: the code looks like it handles each case separately, reviewers read the shape rather than the bodies, and one case is silently mishandled.

func describe(kind int, count int) string {
    if kind == 1 { // FLAW — every branch of the chain runs the same code
        log.Printf("kind %d", kind)
        return "handled"
    } else if kind == 2 {
        log.Printf("kind %d", kind)
        return "handled"
    } else {
        log.Printf("kind %d", kind)
        return "handled"
    }
}

Remediation

Decide which reading applies. If the branches were meant to differ, write the behaviour each case actually needs. If they were not, drop the conditional and keep the body.

func describe(kind int, count int) string {
    switch kind {
    case 1:
        return "first"
    case 2:
        return "second"
    default:
        return "unknown"
    }
}

© 2026 Xygeni. All rights reserved