Skip to content

Commit 6704752

Browse files
Specially handle using the literal suffix to change the type - fixes #1161
1 parent 2b3f316 commit 6704752

File tree

1 file changed

+27
-13
lines changed

1 file changed

+27
-13
lines changed

CodeConverter/CSharp/TypeConversionAnalyzer.cs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ private ExpressionSyntax AddTypeConversion(VBSyntax.ExpressionSyntax vbNode, Exp
9898
var enumUnderlyingType = ((INamedTypeSymbol) vbType).EnumUnderlyingType;
9999
csNode = AddTypeConversion(vbNode, csNode, TypeConversionKind.NonDestructiveCast, addParenthesisIfNeeded, vbType, enumUnderlyingType);
100100
return AddTypeConversion(vbNode, csNode, TypeConversionKind.Conversion, addParenthesisIfNeeded, enumUnderlyingType, vbConvertedType);
101+
case TypeConversionKind.LiteralSuffix:
102+
if (vbNode is VBSyntax.LiteralExpressionSyntax { Token: { Value: { } val, Text: { } text } } && LiteralConversions.GetLiteralExpression(val, text, vbConvertedType) is { } csLiteral) {
103+
return csLiteral;
104+
}
105+
return csNode;
101106
case TypeConversionKind.Unknown:
102107
case TypeConversionKind.Identity:
103108
return addParenthesisIfNeeded ? vbNode.ParenthesizeIfPrecedenceCouldChange(csNode) : csNode;
@@ -178,7 +183,7 @@ public TypeConversionKind AnalyzeConversion(VBSyntax.ExpressionSyntax vbNode, bo
178183
var csConvertedType = GetCSType(vbConvertedType);
179184

180185
if (csType != null && csConvertedType != null &&
181-
TryAnalyzeCsConversion(vbNode, csType, csConvertedType, vbConversion, vbConvertedType, vbType, isConst, forceSourceType != null, out TypeConversionKind analyzeConversion)) {
186+
TryAnalyzeCsConversion(vbCompilation, vbNode, csType, csConvertedType, vbConversion, vbConvertedType, vbType, isConst, forceSourceType != null, out TypeConversionKind analyzeConversion)) {
182187
return analyzeConversion;
183188
}
184189

@@ -273,20 +278,28 @@ private ITypeSymbol GetCSType(ITypeSymbol vbType, VBSyntax.ExpressionSyntax vbNo
273278
return csType;
274279
}
275280

276-
private bool TryAnalyzeCsConversion(VBSyntax.ExpressionSyntax vbNode, ITypeSymbol csType,
281+
private bool TryAnalyzeCsConversion(VBasic.VisualBasicCompilation vbCompilation, VBSyntax.ExpressionSyntax vbNode, ITypeSymbol csType,
277282
ITypeSymbol csConvertedType, Conversion vbConversion, ITypeSymbol vbConvertedType, ITypeSymbol vbType, bool isConst, bool sourceForced,
278283
out TypeConversionKind typeConversionKind)
279284
{
280285
var csConversion = _csCompilation.ClassifyConversion(csType, csConvertedType);
281-
vbType.IsNullable(out var underlyingType);
282-
vbConvertedType.IsNullable(out var underlyingConvertedType);
283-
var nullableVbType = underlyingType ?? vbType;
284-
var nullableVbConvertedType = underlyingConvertedType ?? vbConvertedType;
286+
287+
vbType.IsNullable(out var underlyingVbType);
288+
vbConvertedType.IsNullable(out var underlyingVbConvertedType);
289+
underlyingVbType ??= vbType;
290+
underlyingVbConvertedType ??= vbConvertedType;
291+
var vbUnderlyingConversion = vbCompilation.ClassifyConversion(underlyingVbType, underlyingVbConvertedType);
292+
293+
csType.IsNullable(out var underlyingCsType);
294+
csConvertedType.IsNullable(out var underlyingCsConvertedType);
295+
underlyingCsType ??= csType;
296+
underlyingCsConvertedType ??= csConvertedType;
297+
var csUnderlyingConversion = _csCompilation.ClassifyConversion(underlyingCsType, underlyingCsConvertedType);
285298

286299
bool isConvertToString =
287300
(vbConversion.IsString || vbConversion.IsReference && vbConversion.IsNarrowing) && vbConvertedType.SpecialType == SpecialType.System_String;
288301
bool isConvertFractionalToInt =
289-
!csConversion.IsImplicit && nullableVbType.IsFractionalNumericType() && nullableVbConvertedType.IsIntegralOrEnumType();
302+
!csConversion.IsImplicit && underlyingVbType.IsFractionalNumericType() && underlyingVbConvertedType.IsIntegralOrEnumType();
290303

291304
if (!csConversion.Exists || csConversion.IsUnboxing) {
292305
if (ConvertStringToCharLiteral(vbNode, vbConvertedType, out _)) {
@@ -300,27 +313,27 @@ private bool TryAnalyzeCsConversion(VBSyntax.ExpressionSyntax vbNode, ITypeSymbo
300313
return true;
301314
}
302315
if (isConvertToString || vbConversion.IsNarrowing) {
303-
typeConversionKind = nullableVbConvertedType.IsEnumType() && !csConversion.Exists
316+
typeConversionKind = underlyingVbConvertedType.IsEnumType() && !csConversion.Exists
304317
? TypeConversionKind.EnumConversionThenCast
305318
: TypeConversionKind.Conversion;
306319
return true;
307320
}
308321
} else if (vbConversion.IsNarrowing && vbConversion.IsNullableValueType && isConvertFractionalToInt) {
309322
typeConversionKind = TypeConversionKind.FractionalNumberRoundThenCast;
310323
return true;
311-
} else if (vbConversion.IsNumeric && (csConversion.IsNumeric || nullableVbConvertedType.IsEnumType()) && isConvertFractionalToInt) {
324+
} else if (vbConversion.IsNumeric && (csConversion.IsNumeric || underlyingVbConvertedType.IsEnumType()) && isConvertFractionalToInt) {
312325
typeConversionKind = TypeConversionKind.FractionalNumberRoundThenCast;
313326
return true;
314327
} else if (csConversion is {IsExplicit: true, IsEnumeration: true} or {IsBoxing: true, IsImplicit: false}) {
315328
typeConversionKind = TypeConversionKind.NonDestructiveCast;
316329
return true;
317-
} else if (vbConversion.IsNumeric && csConversion.IsNumeric) {
330+
} else if (vbUnderlyingConversion.IsNumeric && csUnderlyingConversion.IsNumeric) {
318331
// For widening, implicit, a cast is really only needed to help resolve the overload for the operator/method used.
319332
// e.g. When VB "&" changes to C# "+", there are lots more overloads available that implicit casts could match.
320333
// e.g. sbyte * ulong uses the decimal * operator in VB. In C# it's ambiguous - see ExpressionTests.vb "TestMul".
321334
typeConversionKind =
322-
isConst && IsImplicitConstantConversion(vbNode) || csConversion.IsIdentity || !sourceForced && IsExactTypeNumericLiteral(vbNode, vbConvertedType) ? TypeConversionKind.Identity :
323-
csConversion.IsImplicit || vbType.IsNumericType() ? TypeConversionKind.NonDestructiveCast
335+
isConst && IsImplicitConstantConversion(vbNode) || csUnderlyingConversion.IsIdentity || !sourceForced && IsExactTypeNumericLiteral(vbNode, underlyingVbConvertedType) ? TypeConversionKind.LiteralSuffix :
336+
csUnderlyingConversion.IsImplicit || underlyingVbType.IsNumericType() ? TypeConversionKind.NonDestructiveCast
324337
: TypeConversionKind.Conversion;
325338
return true;
326339
} else if (isConvertToString && vbType.SpecialType == SpecialType.System_Object) {
@@ -494,7 +507,8 @@ public enum TypeConversionKind
494507
NullableBool,
495508
StringToCharArray,
496509
DelegateConstructor,
497-
FractionalNumberRoundThenCast
510+
FractionalNumberRoundThenCast,
511+
LiteralSuffix
498512
}
499513

500514
public static bool ConvertStringToCharLiteral(VBSyntax.ExpressionSyntax node,

0 commit comments

Comments
 (0)