Skip to content

Unexpected output from Microsoft.CodeAnalysis.CSharp.SyntaxTree.ToString() after calling GetCompilationUnitRoot() #78593

@noiserious

Description

@noiserious

Version Used:
Bug was introduced when updating to Microsoft.CodeAnalysis.CSharp 4.13.0 from Microsoft.CodeAnalysis.CSharp 4.12.0

I am running dotnet 9.0.300 if that has any importance.

Steps to Reproduce:
I have no clue how to reproduce the bug normally, but i created a small repo with the bug reproducible. https://github.com/noiserious/CodeAnalysis_bug

Details
This feels hyper specific 😄

This is part of a code generation step in a project I have, all unnecessary items have been stripped away.
I have over 500 files being run through this process and this is the only one where I have observed this strange issue.

The step of getting the CompilationUnitSyntaxTree from the SyntaxTree will cause one specific node to get an extra parentheses.
Various things can cause this not to happen, for instance, removing a comment from the top of the file, reordering some unrelated lines, renaming a property in the line above it, or simply changing the value of the affected line from 0.03 to 1.03 will fix it. Prop: Create(1.03, .05, .07, .1, .16), will work as expected where Prop: Create(.03, .05, .07, .1, .16), will not.

I uploaded the whole unprocessed file into the reproduction repo because I couldn't find what to safely trim without causing the bug to stop appearing.

Expected Behavior:
A part of a larger code file the following syntax is fed to Microsoft.CodeAnalysis.CSharp.SyntaxTree.ParseText(); then
.GetCompilationUnitRoot().ToString() is called and the code is expected to come out logically the same.

// text contains:
// ...
// SecondaryStatByRarityFrom: Create(.03, .05, .07, .1, .16),
// ...
var tree = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(text);
var result = tree.GetCompilationUnitRoot().ToString();

// Expect to see:
// ...
// SecondaryStatByRarityFrom: Create(.03, .05, .07, .1, .16),
// ...

Actual Behavior:
See steps from Expected behavior, but the output is actually with an extra parentheses after Create:

// Actual result
// ...
// SecondaryStatByRarityFrom: Create((.03, .05, .07, .1, .16),
// ...

Metadata

Metadata

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions