Skip to content

BRO1110: Closing parenthesis or bracket should be on the line of the last item

A parameter or argument list ends on the line where its last item ends, not with the closing parenthesis on a line of its own. Replaces StyleCop SA1111.

Example

Before

public class Mailer
{
    public void Send(
        string to,
        string subject
        )
    {
        Log(
            to,
            subject
            );
    }

    private void Log(string to, string subject)
    {
    }
}

After

public class Mailer
{
    public void Send(
        string to,
        string subject)
    {
        Log(
            to,
            subject);
    }

    private void Log(string to, string subject)
    {
    }
}

Why

A lone ) is a line that says nothing, and it makes the end of a call look like the start of a block. It's also the C# convention in the .NET runtime and most libraries.

How the fix works

The ) or ] moves right after the last item. A comment at the end of the last item's line goes after it: string subject // required then ) becomes string subject) // required.

Checked: the same lists as BRO1109, plus lambda parameter lists.

Configuration

[*.cs]
# last_item (default, like StyleCop): ')' ends the last item's line; own_line: a split list's ')' gets its own line
stylebro_closing_parenthesis_placement = last_item

own_line is the layout CSharpier writes (checked on Mapperly, which is formatted with CSharpier: nothing changes). It applies to split lists: lists whose last item ends on a line below the opening token ((, or the name's line when BRO1109 moves the ( up there). Their ) or ] goes on a line of its own, indented like the line with the opening token. One exception, again like CSharpier: when every item starts on the ( line and the last one ends with a structure the ) can hug, the ) follows it directly. Hugged are multi-line braces (a lambda's block body, an initializer) and an argument list, tuple or collection expression opened on the ( line. A list that isn't split, or hugs, keeps its ) at the end of the last item, as with last_item. A ) that is already below the last item is left where it is, at any indentation: CSharpier indents it deeper inside a wrapped expression, and keeps } and ) apart when a lambda's body starts below =>.

// last_item
Log(
    to,
    subject);
var open = items.Where(x =>
    x.IsOpen
    && x.Owner == user);

// own_line
Log(
    to,
    subject
);
var open = items.Where(x =>
    x.IsOpen
    && x.Owner == user
);

// own_line, hugged
items.ForEach(x =>
{
    Send(x);
});
var mapped = items.Select(x => new Mapped(
    x.Id,
    x.Name
));

A single argument that starts on the ( line and continues below it counts as split too, also when it's a string concatenation, so its ) gets its own line, as CSharpier places it. Only the ) moves; the ( keeps its line:

// own_line
throw new InvalidOperationException("The first part " +
    "and the second part"
);

Only the gap before the ) changes, so whatever follows it stays with it () =>, ) : base(...), ).Trim(), ); // done). "The line with the opening token" means that line as the other fixes leave it: BRO1105 moving : base( to its own line, an inner list's ) that BRO1110 itself moves down to the start of the line, or an empty () that BRO1109 joins to its name, so nested lists end up aligned in one run. In own_line mode a split list is also not reported when a comment sits between the last item and the ), when the list contains a directive (each target framework's copy of the file may have another last item), or when the last item ends in braces on one line (x => then { Send(x); }): expanding them would make them hugged). A parenthesized expression is never hugged ((a then + b)) gets the lone )): other rules add and remove such parentheses.

Not reported

  • Empty lists (Send( then )): that's spacing, not the last item's line.
  • A comment on its own line or a directive before the closing parenthesis.
  • A comment at the end of the last item's line when code follows the parenthesis on its line (2 // two then ); var x = 1;): the code would end up behind the comment.

Compared with StyleCop

StyleCop has no own_line option. With the default, same results as StyleCop, with the same fixed output, except the last case above, which StyleCop reports, and two kinds of lists StyleCop doesn't check (neither 1.1.118 nor 1.2): target-typed new(...) and constructor initializers (: this(...), : base(...)). StyleBro treats them like any other argument list.