Skip to content

Commit

Permalink
Merge pull request #45778 from mahalex/fix-refactor-anonymous-types
Browse files Browse the repository at this point in the history
Remove trailing commas during conversion to class
  • Loading branch information
CyrusNajmabadi authored Jul 10, 2020
2 parents bf301b0 + 3f0d34c commit ecd7f38
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,126 @@ void Method()
}
}
internal class NewClass
{
public int A { get; }
public int B { get; }
public NewClass(int a, int b)
{
A = a;
B = b;
}
public override bool Equals(object obj)
{
return obj is NewClass other &&
A == other.A &&
B == other.B;
}
public override int GetHashCode()
{
var hashCode = -1817952719;
hashCode = hashCode * -1521134295 + A.GetHashCode();
hashCode = hashCode * -1521134295 + B.GetHashCode();
return hashCode;
}
}";
await TestInRegularAndScriptAsync(text, expected, options: this.PreferImplicitTypeWithInfo());
}

[WorkItem(45747, "https://github.com/dotnet/roslyn/issues/45747")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertAnonymousTypeToClass)]
public async Task ConvertOmittingTrailingComma()
{
var text = @"
class Test
{
void Method()
{
var t1 = [||]new
{
a = 1,
b = 2,
};
}
}
";
var expected = @"
class Test
{
void Method()
{
var t1 = new {|Rename:NewClass|}(
1,
2
);
}
}
internal class NewClass
{
public int A { get; }
public int B { get; }
public NewClass(int a, int b)
{
A = a;
B = b;
}
public override bool Equals(object obj)
{
return obj is NewClass other &&
A == other.A &&
B == other.B;
}
public override int GetHashCode()
{
var hashCode = -1817952719;
hashCode = hashCode * -1521134295 + A.GetHashCode();
hashCode = hashCode * -1521134295 + B.GetHashCode();
return hashCode;
}
}";
await TestInRegularAndScriptAsync(text, expected, options: this.PreferImplicitTypeWithInfo());
}

[WorkItem(45747, "https://github.com/dotnet/roslyn/issues/45747")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertAnonymousTypeToClass)]
public async Task ConvertOmittingTrailingCommaButPreservingTrivia()
{
var text = @"
class Test
{
void Method()
{
var t1 = [||]new
{
a = 1,
b = 2 // and
// more
,
};
}
}
";
var expected = @"
class Test
{
void Method()
{
var t1 = new {|Rename:NewClass|}(
1,
2 // and
// more
);
}
}
internal class NewClass
{
public int A { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;

namespace Microsoft.CodeAnalysis.CSharp.ConvertAnonymousTypeToClass
{
Expand Down Expand Up @@ -41,7 +42,25 @@ private ArgumentListSyntax CreateArgumentList(AnonymousObjectCreationExpressionS
SyntaxFactory.Token(SyntaxKind.CloseParenToken).WithTriviaFrom(anonymousObject.CloseBraceToken));

private SeparatedSyntaxList<ArgumentSyntax> CreateArguments(SeparatedSyntaxList<AnonymousObjectMemberDeclaratorSyntax> initializers)
=> SyntaxFactory.SeparatedList<ArgumentSyntax>(CreateArguments(initializers.GetWithSeparators()));
=> SyntaxFactory.SeparatedList<ArgumentSyntax>(CreateArguments(OmitTrailingComma(initializers.GetWithSeparators())));

private static SyntaxNodeOrTokenList OmitTrailingComma(SyntaxNodeOrTokenList list)
{
// Trailing comma is allowed in initializer list, but disallowed in method calls.
if (list.Count == 0 || list.Count % 2 == 1)
{
// The list is either empty, or does not end with a trailing comma.
return list;
}

return list
.Replace(
list[^2],
list[^2].AsNode()
.WithAppendedTrailingTrivia(list[^1].GetLeadingTrivia())
.WithAppendedTrailingTrivia(list[^1].GetTrailingTrivia()))
.RemoveAt(list.Count - 1);
}

private SyntaxNodeOrTokenList CreateArguments(SyntaxNodeOrTokenList list)
=> new SyntaxNodeOrTokenList(list.Select(CreateArgumentOrComma));
Expand Down

0 comments on commit ecd7f38

Please sign in to comment.