Skip to content

BRO1143: No 'else' after a branch that ends in a jump

When the if branch ends in return, throw, break, continue, goto or yield break, the else is not needed: its body can follow the if statement. Not a StyleCop rule: from Meziantou's MA0071 and Roslynator's RCS1211. Off by default, also in the preset.

Example

root = true

[*.cs]
dotnet_diagnostic.BRO1143.severity = warning

Before

public static class Pricing
{
    public static decimal Price(decimal amount, bool member)
    {
        if (amount <= 0)
        {
            return 0;
        }
        else
        {
            var discount = member ? 0.1m : 0m;
            return amount * (1 - discount);
        }
    }
}

After

public static class Pricing
{
    public static decimal Price(decimal amount, bool member)
    {
        if (amount <= 0)
        {
            return 0;
        }

        var discount = member ? 0.1m : 0m;
        return amount * (1 - discount);
    }
}

Why

The early return is a guard: after it, the normal path continues at the method's own level instead of one level deeper. It's a matter of taste, though: some teams prefer the symmetric if/else when both branches are equally important. That's why the rule is off by default; turn it on with dotnet_diagnostic.BRO1143.severity = warning.

How the fix works

It removes the else (and the braces of its block) and moves the body one indentation level out, below the if statement. Indentation follows indent_style/indent_size. When the if branch is a multi-line block, BRO1519 wants a blank line after its }, and the fix adds it. An else body that contains another such if/else is fixed in the same pass: every line moves out once per else it leaves.

When the if branch has no braces and BRO1514-BRO1516 want braces on it (for example BRO1516, because the else block makes the chain inconsistent), the fix adds them too, so the result is the same whichever rule dotnet format runs first:

if (x)
    return 1;
else
{
    return 2;
}

becomes

if (x)
{
    return 1;
}

return 2;

"Ends in a jump" is decided by syntax: the branch is a jump statement, a block whose last statement ends in one, or an if/else whose branches both end in one (so an outer and an inner else go in the same run). Loops, switch and try don't count.

Not reported

  • else if chains (if (a) return 1; else if (b) return 2; else return 3;): removing the first else would leave a new candidate for a second run. Only an if whose else is not another if.
  • An if that isn't a statement of a block (the branch of another if, a case section's statement list, a label's statement), or that doesn't start its line.
  • An empty else block.
  • Comments or directives around the else: between the if branch and the first statement of the body, or between the body's last statement and its }. And any #if in the whole statement.
  • A body that starts on the else line but goes on below it, a body whose lines aren't indented one level deeper than the if, and strings or /* */ comments spanning lines (their inner lines can't be moved out).
  • using declarations in the body (using var x = ...;): moved out, they would be disposed at the end of the enclosing block instead of the else block.
  • Names declared in the body (locals, local functions, pattern variables, lambda parameters, labels) that the enclosing block also uses: they would clash there.
  • An if branch without braces that a brace rule wants braces on but can't add (a comment or directive where the { would go, a string spanning lines): see How the fix works.

Compared with StyleCop

StyleCop has no such rule. stylebro-migrate leaves it off.