Skip to content

BRO1405: Statement should not use unnecessary parenthesis

Parentheses around a single value, or around a whole expression where nothing binds to it, are removed. Replaces StyleCop SA1119.

Example

Before

public class Totals
{
    private int count = (1 + 2);

    public int Sum(int a, int b)
    {
        var total = (a + b);
        return (total);
    }
}

After

public class Totals
{
    private int count = 1 + 2;

    public int Sum(int a, int b)
    {
        var total = a + b;
        return total;
    }
}

Why

Parentheses that don't group anything make the reader look for a precedence question that isn't there.

How the fix works

The fix removes ( and ) and any spaces just inside them; where the tokens would run together (return(x)), a space is left. Before removing, the statement (or member) is parsed again without the parentheses, and they're only removed when the result means the same: parentheses can turn F(a < b, (c > (d + 1))) into a generic method call a<b, c>(d + 1) when they go.

Like StyleCop, parentheses inside an operator expression (a + (b * c), a ?? (b ?? c)) are left alone: they say how the expression groups, or make it clearer. Adding parentheses for clarity is SA1407/SA1408 (the SDK's IDE0048).

In an IDE the parentheses are also faded, like StyleCop's SA1119_p: a hidden companion diagnostic, BRO1405_p, is reported on the ( and ) of every finding with the Unnecessary tag. It can't be configured, has no fix of its own (the build and dotnet format ignore hidden diagnostics), and is only reported where BRO1405 is on. Parentheses around patterns are BRO1410's (with BRO1410_p).

This rule replaces the SDK's IDE0047, whose fix writes merge conflict markers in multi-targeted projects under dotnet format (reported upstream as dotnet/roslyn#86000) and which also removes a ?? (b ?? c) (see decisions).

Not reported

StyleCop's exceptions: operator expressions inside other expressions, a conditional in an interpolation ($"{(f ? 1 : 2)}"), a conditional access before ./[] ((s?.Length).ToString()), a switch or with expression that is called, cast or accessed, stackalloc in an initializer, the left side of a ref conditional assignment. Also: parentheses with a comment and a line break inside them (( / x + 1 // one / ): removing them would leave the ; on a line of its own), and ones whose removal would change how the code parses. A comment on one line with the code is kept: (x + 1 /* one */) becomes x + 1 /* one */.

Configuration

The SDK's dotnet_style_parentheses_* settings don't change this rule: it removes what StyleCop's SA1119 removes. With never_if_unnecessary the SDK would also remove parentheses inside operator expressions (a ?? (b ?? c)); StyleBro leaves those, so a StyleCop-clean codebase stays unchanged after migrating. never_if_unnecessary does turn off adding parentheses (BRO1406, BRO1407).

Compared with StyleCop

Same positions, except the parse-changing case above, where StyleCop's fix doesn't compile. StyleCop's fix leaves the spaces of ( b ) behind.

StyleCop also reports a hidden SA1119_p on the same parentheses' ( and ), only so the IDE greys them out; StyleBro does the same with BRO1405_p (see above). StyleCop doesn't check parentheses in patterns (x is (> 0)); StyleBro's BRO1410 does.