Skip to content

Commit 15fda14

Browse files
Merge pull request #862 from Yozer/fix-conversions-calls
use explicit cast when integral numeric types are casted to enum # Conflicts: # CodeConverter/CSharp/ExpressionNodeVisitor.cs # CodeConverter/Util/FromRoslyn/ITypeSymbolExtensions.cs # Tests/CSharp/TypeCastTests.cs
1 parent 5435a8e commit 15fda14

4 files changed

Lines changed: 62 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1111
### VB -> C#
1212

1313
* Xml Namespace Imports now converted [#836](https://github.com/icsharpcode/CodeConverter/issues/836)
14+
* Use explicit cast when integral numeric types are casted to enum [#861](https://github.com/icsharpcode/CodeConverter/issues/861)
1415
* Correct inconsistent casing of event handlers [#854](https://github.com/icsharpcode/CodeConverter/issues/854)
1516

1617
### C# -> VB

CodeConverter/CSharp/ExpressionNodeVisitor.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ public override async Task<CSharpSyntaxNode> VisitCTypeExpression(VBasic.Syntax.
283283
{
284284
var nodeForType = node;
285285
var convertMethodForKeyword = GetConvertMethodForKeywordOrNull(nodeForType);
286-
if (_semanticModel.GetTypeInfo(nodeForType).Type is INamedTypeSymbol typeSymbol && typeSymbol.IsEnumType()) {
286+
if (_semanticModel.GetTypeInfo(nodeForType).Type is INamedTypeSymbol typeSymbol && typeSymbol.IsEnumType() &&
287+
_semanticModel.GetTypeInfo(node.Expression).Type is {} expressionType && !expressionType.IsIntegralType() && !expressionType.IsEnumType()) {
287288
convertMethodForKeyword = GetConvertMethodForKeywordOrNull(typeSymbol.EnumUnderlyingType);
288289
} else if (convertMethodForKeyword != null) {
289290
nodeForType = null;
@@ -690,7 +691,7 @@ public override async Task<CSharpSyntaxNode> VisitNamedFieldInitializer(VBasic.S
690691
var csExpressionSyntax = await node.Expression.AcceptAsync<ExpressionSyntax>(TriviaConvertingExpressionVisitor);
691692
csExpressionSyntax =
692693
CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.Expression, csExpressionSyntax);
693-
if (node?.Parent?.Parent is VBasic.Syntax.AnonymousObjectCreationExpressionSyntax) {
694+
if (node.Parent?.Parent is VBasic.Syntax.AnonymousObjectCreationExpressionSyntax) {
694695
return SyntaxFactory.AnonymousObjectMemberDeclarator(
695696
SyntaxFactory.NameEquals(SyntaxFactory.IdentifierName(ConvertIdentifier(node.Name.Identifier))),
696697
csExpressionSyntax);
@@ -1769,7 +1770,7 @@ private ArgumentListSyntax CreateArgList(ISymbol invocationSymbol)
17691770
private async Task<CSharpSyntaxNode> SubstituteVisualBasicMethodOrNullAsync(VBSyntax.InvocationExpressionSyntax node, ISymbol invocationSymbol, ISymbol symbol)
17701771
{
17711772
ExpressionSyntax cSharpSyntaxNode = null;
1772-
if (symbol?.ContainingNamespace.MetadataName == nameof(Microsoft.VisualBasic) && symbol?.Name == "ChrW" || symbol?.Name == "Chr") {
1773+
if (symbol?.ContainingNamespace.MetadataName == nameof(Microsoft.VisualBasic) && symbol.Name == "ChrW" || symbol?.Name == "Chr") {
17731774
var vbArg = node.ArgumentList.Arguments.Single().GetExpression();
17741775
var constValue = _semanticModel.GetConstantValue(vbArg);
17751776
if (IsCultureInvariant(symbol, constValue)) {

CodeConverter/Util/FromRoslyn/ITypeSymbolExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ public static bool IsUnexpressibleTypeParameterConstraint(this ITypeSymbol typeS
254254
return false;
255255
}
256256

257+
public static bool IsIntegralType(this ITypeSymbol? type) => type.IsNumericType() && !type.IsFractionalNumericType();
258+
257259
public static bool IsFractionalNumericType(this ITypeSymbol? type)
258260
{
259261
if (type != null) {

Tests/CSharp/TypeCastTests.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,61 @@ private void Test()
256256
}");
257257
}
258258

259+
[Fact]
260+
public async Task CastingIntegralTypeToEnumShouldUseExplicitCastAsync()
261+
{
262+
await TestConversionVisualBasicToCSharpAsync(
263+
@"
264+
Enum TestEnum
265+
None = 0
266+
End Enum
267+
Enum TestEnum2
268+
None = 1
269+
End Enum
270+
Class Class1
271+
Private Sub Test()
272+
Dim res = CType(5S, TestEnum)
273+
res = CType(5D, TestEnum)
274+
res = CType(5L, TestEnum)
275+
res = CType(5.4F, TestEnum)
276+
res = CType(5.7R, TestEnum)
277+
res = CType(5UL, TestEnum)
278+
res = CType(5, TestEnum)
279+
280+
Dim otherEnum = TestEnum2.None
281+
res = CType(otherEnum, TestEnum)
282+
End Sub
283+
End Class",
284+
@"using Microsoft.VisualBasic.CompilerServices; // Install-Package Microsoft.VisualBasic
285+
286+
internal enum TestEnum
287+
{
288+
None = 0
289+
}
290+
291+
internal enum TestEnum2
292+
{
293+
None = 1
294+
}
295+
296+
internal partial class Class1
297+
{
298+
private void Test()
299+
{
300+
TestEnum res = (TestEnum)5;
301+
res = (TestEnum)Conversions.ToInteger(5m);
302+
res = (TestEnum)5L;
303+
res = (TestEnum)Conversions.ToInteger(5.4f);
304+
res = (TestEnum)Conversions.ToInteger(5.7d);
305+
res = (TestEnum)5UL;
306+
res = (TestEnum)5;
307+
var otherEnum = TestEnum2.None;
308+
res = (TestEnum)otherEnum;
309+
}
310+
}
311+
");
312+
}
313+
259314
[Fact]
260315
public async Task TryCastObjectToGenericListAsync()
261316
{

0 commit comments

Comments
 (0)