Skip to content

Commit 4fdb645

Browse files
Loop over enum
1 parent bf98217 commit 4fdb645

File tree

3 files changed

+28
-10
lines changed

3 files changed

+28
-10
lines changed

CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using VBasic = Microsoft.CodeAnalysis.VisualBasic;
1414
using VBSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax;
1515
using Microsoft.CodeAnalysis.Text;
16+
using ICSharpCode.CodeConverter.Util.FromRoslyn;
1617

1718
namespace ICSharpCode.CodeConverter.CSharp
1819
{
@@ -474,12 +475,12 @@ public override async Task<SyntaxList<StatementSyntax>> VisitForBlock(VBSyntax.F
474475
id = (ExpressionSyntax) await stmt.ControlVariable.AcceptAsync(_expressionVisitor);
475476

476477
// If missing semantic info, the compiler just guesses object. In this branch there was no explicit type, so let's try to improve on that guess:
477-
var bestType = controlVarType.Yield()
478+
controlVarType = controlVarType.Yield()
478479
.Concat(new[] { stmt.FromValue, stmt.ToValue, stmt.StepClause?.StepValue }.Select(exp => _semanticModel.GetTypeInfo(exp).Type))
479480
.FirstOrDefault(t => t != null && t.SpecialType != SpecialType.System_Object);
480481

481482
if (controlVarSymbol != null && controlVarSymbol.DeclaringSyntaxReferences.Any(r => r.Span.OverlapsWith(stmt.ControlVariable.Span))) {
482-
declaration = CommonConversions.CreateVariableDeclarationAndAssignment(controlVarSymbol.Name, startValue, CommonConversions.GetTypeSyntax(bestType));
483+
declaration = CommonConversions.CreateVariableDeclarationAndAssignment(controlVarSymbol.Name, startValue, CommonConversions.GetTypeSyntax(controlVarType));
483484
} else {
484485
startValue = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, id, startValue);
485486
initializers.Add(startValue);
@@ -498,6 +499,7 @@ public override async Task<SyntaxList<StatementSyntax>> VisitForBlock(VBSyntax.F
498499
var loopToAssignment = CommonConversions.CreateVariableDeclarator(loopToVariableName, csToValue);
499500
declaration = declaration.AddVariables(loopToAssignment);
500501
} else {
502+
csToValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(stmt.ToValue, csToValue, forceTargetType: controlVarType);
501503
var loopEndDeclaration = SyntaxFactory.LocalDeclarationStatement(
502504
CommonConversions.CreateVariableDeclarationAndAssignment(loopToVariableName, csToValue));
503505
// Does not do anything about porting newline trivia upwards to maintain spacing above the loop
@@ -507,8 +509,7 @@ public override async Task<SyntaxList<StatementSyntax>> VisitForBlock(VBSyntax.F
507509
csToValue = toVariableId;
508510
};
509511

510-
511-
var (csCondition, csStep) = await ConvertConditionAndStepClause(stmt, id, csToValue);
512+
var (csCondition, csStep) = await ConvertConditionAndStepClause(stmt, id, csToValue, controlVarType);
512513

513514
var block = SyntaxFactory.Block(await ConvertStatements(node.Statements));
514515
var forStatementSyntax = SyntaxFactory.ForStatement(
@@ -525,11 +526,15 @@ public override async Task<SyntaxList<StatementSyntax>> VisitForBlock(VBSyntax.F
525526
return await CommonConversions.SplitVariableDeclarations(v, _localsToInlineInLoop, preferExplicitType);
526527
}
527528

528-
private async Task<(ExpressionSyntax, ExpressionSyntax)> ConvertConditionAndStepClause(VBSyntax.ForStatementSyntax stmt, ExpressionSyntax id, ExpressionSyntax csToValue)
529+
private async Task<(ExpressionSyntax, ExpressionSyntax)> ConvertConditionAndStepClause(VBSyntax.ForStatementSyntax stmt, ExpressionSyntax id, ExpressionSyntax csToValue, ITypeSymbol controlVarType)
529530
{
530531
var vbStepValue = stmt.StepClause?.StepValue;
531532
var csStepValue = (ExpressionSyntax)await (stmt.StepClause?.StepValue).AcceptAsync(_expressionVisitor);
532-
csStepValue = csStepValue?.SkipParens();
533+
// For an enum, you need to add on an integer for example:
534+
var forceStepType = controlVarType is INamedTypeSymbol nt && nt.IsEnumType() ? nt.EnumUnderlyingType : controlVarType;
535+
csStepValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(vbStepValue, csStepValue?.SkipParens(), forceTargetType: forceStepType);
536+
csToValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(stmt.ToValue, csToValue?.SkipParens(), forceTargetType: controlVarType);
537+
533538
var nonNegativeCondition = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, id, csToValue);
534539
var negativeCondition = SyntaxFactory.BinaryExpression(SyntaxKind.GreaterThanOrEqualExpression, id, csToValue);
535540
if (csStepValue == null) {

Tests/CSharp/MissingSemanticModelInfo/StatementTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ internal partial class MissingLoopType
2727
public void Test()
2828
{
2929
Asadf x = default;
30-
for (int i = 1, loopTo = x.SomeInteger; i <= loopTo; i++)
30+
var loopTo = x.SomeInteger;
31+
for (int i = 1; i <= loopTo; i++)
3132
{
3233
}
3334
}

Tests/CSharp/StatementTests/LoopStatementTests.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ public void PrintLoop(int startIndex, int endIndex, int step)
383383
public async Task ForEnumAsync()
384384
{
385385
await TestConversionVisualBasicToCSharpAsync(@"Friend Enum MyEnum
386-
Zero,
386+
Zero
387387
One
388388
End Enum
389389
@@ -404,12 +404,24 @@ Sub PrintLoop(startIndex As MyEnum, endIndex As MyEnum, [step] As MyEnum)
404404
End Sub
405405
End Class", @"using System.Diagnostics;
406406
407+
internal enum MyEnum
408+
{
409+
Zero,
410+
One
411+
}
412+
407413
internal partial class ForEnumAsync
408414
{
409-
public void PrintLoop(int startIndex, int endIndex, int step)
415+
public void PrintLoop(MyEnum startIndex, MyEnum endIndex, MyEnum step)
410416
{
411-
for (int i = startIndex, loopTo = endIndex; step >= 0 ? i <= loopTo : i >= loopTo; i += step)
417+
for (MyEnum i = startIndex, loopTo = endIndex; step >= 0 ? i <= loopTo : i >= loopTo; i += (int)step)
412418
Debug.WriteLine(i);
419+
for (MyEnum i2 = startIndex, loopTo1 = endIndex; step >= 0 ? i2 <= loopTo1 : i2 >= loopTo1; i2 += (int)step)
420+
Debug.WriteLine(i2);
421+
for (MyEnum i3 = startIndex, loopTo2 = endIndex; i3 <= loopTo2; i3 += 3)
422+
Debug.WriteLine(i3);
423+
for (MyEnum i4 = startIndex; i4 <= (MyEnum)4; i4++)
424+
Debug.WriteLine(i4);
413425
}
414426
}");
415427
}

0 commit comments

Comments
 (0)