Skip to content

BRO1514: Braces should not be omitted

The child statement of an if, else, for, foreach, while, do, using, lock or fixed statement is a block. Replaces StyleCop SA1503.

Example

Before

public class Counter
{
    public int Clamp(int value)
    {
        if (value < 0)
            return 0;

        return value;
    }
}

After

public class Counter
{
    public int Clamp(int value)
    {
        if (value < 0)
        {
            return 0;
        }

        return value;
    }
}

Why

A statement added below an if without braces looks like part of it but always runs. Braces make the extent of every condition and loop explicit.

How the fix works

The braces go at the indentation of the statement that owns them, the child statement one level deeper (from indent_style/indent_size). { starts its own line unless csharp_new_line_before_open_brace leaves out control_blocks; an else follows the } as csharp_new_line_before_else says; a do statement's while keeps its line. A trailing comment stays with the statement. Nested statements are all fixed in one pass.

This rule replaces the SDK's IDE0011, whose fix breaks multi-targeted projects under dotnet format (reported upstream as dotnet/roslyn#86000 and dotnet/roslyn#86001; see decisions).

Configuration

[*.cs]
# StyleCop's allowConsecutiveUsings, also for 'fixed (a) fixed (b) { }'. false: the inner 'using' or 'fixed' gets its
# own braces.
stylebro_allow_consecutive_usings = true
# Not a StyleCop setting (StyleCop issue #2252). true: a jump statement ('return', 'throw', 'break', 'continue',
# 'goto', 'yield break') on the line of its 'if' needs no braces: 'if (x) return;'. On the next line, or after
# 'else', it still gets braces. Default false.
stylebro_allow_single_line_jump_statements = false
# Not a StyleCop setting. all (default): every statement StyleCop checks. if_and_loops: if/else, for, foreach, while
# and do only, like Sonar's S121: not 'using', 'lock', 'fixed' or a foreach that deconstructs ('foreach (var (a, b) in x)').
# Applies to BRO1515 and BRO1516 too.
stylebro_braces_statements = all
# The SDK's setting, which BRO1514-BRO1516 follow:
#   true (or not set): StyleCop's rules, as described here
#   when_multiline: only multi-line child statements (BRO1515) and inconsistent if/else chains (BRO1516); "multi-line"
#                   as the SDK counts it: the statement, its header (a 'for' split over lines) or a do statement's
#                   'while' part spans lines
#   false: braces aren't required (nothing is reported)
csharp_prefer_braces = true

stylebro-migrate copies allowConsecutiveUsings from stylecop.json and writes csharp_prefer_braces from the StyleCop rules that are on: true when any of SA1503, SA1519 and SA1520 is (each of BRO1514-BRO1516 is then on where its StyleCop rule was, so exactly StyleCop's statements are reported), false when none is. Not when_multiline for SA1519/SA1520 alone: its "multi-line" also counts a split if header, which SA1519 accepts (#1488). A csharp_prefer_braces the repository sets at severity silent or none isn't kept: nothing enforced it.

stylebro_allow_single_line_jump_statements narrows csharp_prefer_braces = true. With when_multiline, every single-line child statement is already allowed, so the option changes nothing there; with false nothing is reported anyway. The option only exempts statements from BRO1514: when another clause of the same if/else chain has or gets braces, BRO1516 still asks for them on the jump too (if (x) return; else { ... } becomes fully braced in one run). stylebro-migrate doesn't write it: stylecop.json has no such setting.

stylebro_braces_statements = if_and_loops is what stylebro-migrate writes for a repository that enforces Sonar's S121 (with csharp_prefer_braces = true), so BRO1514 reports nothing S121 accepts. When the StyleCop setup turns BRO1514 on too (SA1503), StyleCop's statements stay checked and the option isn't written.

Not reported

  • A multi-line child statement when BRO1515 is on, and a clause of an if/else chain where another clause has braces when BRO1516 is on: those rules report them (like StyleCop).
  • if (x) return; (a jump statement on the if line) with stylebro_allow_single_line_jump_statements = true.
  • using, lock, fixed and deconstructing foreach statements with stylebro_braces_statements = if_and_loops (an if whose child is one still gets braces around it).
  • using (a) using (b) { } and fixed (a) fixed (b) { }: consecutive using statements, and consecutive fixed statements, share one block, unless stylebro_allow_consecutive_usings = false (see Configuration). StyleCop only allows usings; the SDK's IDE0011 allows both.
  • Comments or directives where the braces would go, #if in the owning statement, a multi-line string in the statement, or other code after it on its line: the fix can't place the braces safely.
  • A statement in a one-line block (void M(bool x) { if (x) return; }) when BRO1508/ BRO1509 is on: expanding the block adds the braces too.

Compared with StyleCop

Same positions and output, apart from the cases above that are skipped.