dotnet / dotnet/roslyn

Formatter.Format does not expand empty constructor body to Allman style when constructor initializer is present

Open
#82,974 0 comments 0 reactions 0 assignees View on GitHub
Area-IDE
Dominant language
C#
Stars
20.7k
Forks
4.3k
PR merge metrics
PR metrics pending

Description

**Version Used**: Microsoft.CodeAnalysis.CSharp.Workspaces 5.0.0 (net9.0)

**Steps to Reproduce**:

```csharp
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Formatting;
using Microsoft.CodeAnalysis.Formatting;

var source = """
class MyException : Exception
{
public MyException() : base(){}
public MyException(string m) : base(m){}
}
""";

var tree = CSharpSyntaxTree.ParseText(source);
var root = tree.GetRoot();

using var workspace = new AdhocWorkspace();
var options = workspace.Options
.WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInMethods, true)
.WithChangedOption(CSharpFormattingOptions.WrappingPreserveSingleLine, false)
.WithChangedOption(CSharpFormattingOptions.WrappingKeepStatementsOnSingleLine, false);

var formatted = Formatter.Format(root, workspace, options).ToFullString();
Console.WriteLine(formatted);

// For comparison:
var normalized = root.NormalizeWhitespace().ToFullString();
Console.WriteLine("--- NormalizeWhitespace ---");
Console.WriteLine(normalized);
```

**Diagnostic Id**: N/A (formatting API, not analyzer)

**Expected Behavior**:

`Formatter.Format` with `NewLinesForBracesInMethods=true` and `WrappingPreserveSingleLine=false` should place the opening brace of an empty constructor body on a new line (Allman style), matching what `NormalizeWhitespace()` produces:

```csharp
class MyException : Exception
{
public MyException() : base()
{
}

public MyException(string m) : base(m)
{
}
}
```

**Actual Behavior**:

`Formatter.Format` keeps empty constructor bodies on one line when a constructor initializer (`: base(...)`) is present. No combination of formatting options changes this:

```csharp
class MyException : Exception
{
public MyException() : base() { }
public MyException(string m) : base(m) { }
}
```

`NormalizeWhitespace()` correctly produces multi-line Allman-style braces for the same input.

**Additional context**:

This was tested exhaustively with every `NewLinesForBraces*` and `Wrapping*` option — individually and in combination — none cause the formatter to expand empty constructor bodies when a constructor initializer is present. Constructors without an initializer (e.g. `public Foo(){}`) are expanded correctly by `NewLinesForBracesInMethods=true`.

Contributor guide

Open the contributing guide

Research direction

Run the supplied C# reproduction with Formatter.Format, AdhocWorkspace, and the listed CSharpFormattingOptions, then trace how formatting handles constructors with initializer clauses. Done means empty constructor bodies with initializers expand to separate Allman-style brace lines when NewLinesForBracesInMethods and the wrapping options are enabled, without regressing constructors that already format correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.