Skip to content

Commit

Permalink
Merge pull request #829 from Yozer/432-fix
Browse files Browse the repository at this point in the history
Remove redundant  break expressions in switch-case statements.
  • Loading branch information
GrahamTheCoder authored Feb 11, 2022
2 parents 068c7dd + 6d23c2c commit ac30790
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* Fix access modifiers for explicit interface implementations. [#819](https://github.com/icsharpcode/CodeConverter/issues/819)
* Fix code generation for explicit interface implementations. [#813](https://github.com/icsharpcode/CodeConverter/issues/813)
* Replace VB-specific library methods with idiomatic framework alternatives [#814](https://github.com/icsharpcode/CodeConverter/pull/814)
* Remove redundant break expressions in switch-case statements. [#432](https://github.com/icsharpcode/CodeConverter/issues/432)

### C# -> VB

Expand Down
39 changes: 37 additions & 2 deletions CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -765,8 +765,7 @@ public override async Task<SyntaxList<StatementSyntax>> VisitSelectBlock(VBSynta
}

var csBlockStatements = (await ConvertStatementsAsync(block.Statements)).ToList();
if (csBlockStatements.LastOrDefault()
?.IsKind(SyntaxKind.ReturnStatement, SyntaxKind.BreakStatement) != true) {
if (!DefinitelyExits(csBlockStatements.LastOrDefault())) {
csBlockStatements.Add(SyntaxFactory.BreakStatement());
}
var list = SingleStatement(SyntaxFactory.Block(csBlockStatements));
Expand All @@ -777,6 +776,42 @@ public override async Task<SyntaxList<StatementSyntax>> VisitSelectBlock(VBSynta
return SingleStatement(switchStatementSyntax);
}

private static bool DefinitelyExits(StatementSyntax statement)
{
if (statement == null) {
return false;
}

StatementSyntax GetLastStatement(StatementSyntax node) => node is BlockSyntax block ? block.Statements.LastOrDefault() : node;
bool IsExitStatement(StatementSyntax node)
{
node = GetLastStatement(node);
return node != null && node.IsKind(SyntaxKind.ReturnStatement, SyntaxKind.BreakStatement, SyntaxKind.ThrowStatement, SyntaxKind.ContinueStatement);
}

if (IsExitStatement(statement)) {
return true;
}

if (statement is not IfStatementSyntax ifStatement) {
return false;
}

while(ifStatement.Else != null) {
if (!IsExitStatement(ifStatement.Statement)) {
return false;
}

if (ifStatement.Else.Statement is IfStatementSyntax x) {
ifStatement = x;
} else {
return IsExitStatement(ifStatement.Else.Statement);
}
}

return false;
}

private static bool IsEnumOrNullableEnum(ITypeSymbol convertedType) =>
convertedType?.IsEnumType() == true || convertedType?.GetNullableUnderlyingType()?.IsEnumType() == true;

Expand Down
270 changes: 270 additions & 0 deletions Tests/CSharp/ExpressionTests/ExpressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1660,6 +1660,276 @@ public void OnLoad(UserInterface? ui)
}");
}

[Fact]
public async Task SelectCaseDoesntGenerateBreakWhenLastStatementWillExitAsync()
{
await TestConversionVisualBasicToCSharpAsync(
@"Public Class Test
Public Function OnLoad() As Integer
Dim x = 5
While True
Select Case x
Case 0
Continue While
Case 1
x = 1
Case 2
Return 2
Case 3
Throw New Exception()
Case 4
If True Then
x = 4
Else
Return x
End If
Case 5
If True Then
Return x
Else
x = 5
End If
Case 6
If True Then
Return x
Else If False Then
x = 6
Else
Return x
End If
Case 7
If True Then
Return x
End If
Case 8
If True Then Return x
Case 9
If True Then x = 9
Case 10
If True Then Return x Else x = 10
Case 11
If True Then x = 11 Else Return x
Case 12
If True Then Return x Else Return x
Case 13
If True Then
Return x
Else If False Then
Continue While
Else If False Then
Throw New Exception()
Else If False Then
Exit Select
Else
Return x
End If
Case 14
If True Then
Return x
Else If False Then
Return x
Else If False Then
Exit Select
End If
Case Else
If True Then
Return x
Else
Return x
End If
End Select
End While
Return x
End Function
End Class", @"using System;
public partial class Test
{
public int OnLoad()
{
int x = 5;
while (true)
{
switch (x)
{
case 0:
{
continue;
}
case 1:
{
x = 1;
break;
}
case 2:
{
return 2;
}
case 3:
{
throw new Exception();
}
case 4:
{
if (true)
{
x = 4;
}
else
{
return x;
}
break;
}
case 5:
{
if (true)
{
return x;
}
else
{
x = 5;
}
break;
}
case 6:
{
if (true)
{
return x;
}
else if (false)
{
x = 6;
}
else
{
return x;
}
break;
}
case 7:
{
if (true)
{
return x;
}
break;
}
case 8:
{
if (true)
return x;
break;
}
case 9:
{
if (true)
x = 9;
break;
}
case 10:
{
if (true)
return x;
else
x = 10;
break;
}
case 11:
{
if (true)
x = 11;
else
return x;
break;
}
case 12:
{
if (true)
return x;
else
return x;
}
case 13:
{
if (true)
{
return x;
}
else if (false)
{
continue;
}
else if (false)
{
throw new Exception();
}
else if (false)
{
break;
}
else
{
return x;
}
}
case 14:
{
if (true)
{
return x;
}
else if (false)
{
return x;
}
else if (false)
{
break;
}
break;
}
default:
{
if (true)
{
return x;
}
else
{
return x;
}
}
}
}
return x;
}
}");
}

[Fact]
public async Task TupleAsync()
{
Expand Down
1 change: 0 additions & 1 deletion Tests/CSharp/StatementTests/StatementTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1709,7 +1709,6 @@ public void DoesNotThrow()
default:
{
throw new Exception();
break;
}
}
}
Expand Down

0 comments on commit ac30790

Please sign in to comment.