Avoid loss of precision after conversion

This commit is contained in:
GrahamTheCoder 2018-03-13 10:34:46 +00:00
Родитель 120d333c62
Коммит 178f51c124
3 изменённых файлов: 58 добавлений и 15 удалений

Просмотреть файл

@ -782,13 +782,13 @@ namespace ICSharpCode.CodeConverter.CSharp
if (node.Token.Value == null) {
var type = semanticModel.GetTypeInfo(node).ConvertedType;
if (type == null) {
return Literal(null)
return Literal("null", null)
.WithTrailingTrivia(
SyntaxFactory.Comment("/* TODO Change to default(_) if this is not a reference type */"));
}
return !type.IsReferenceType ? SyntaxFactory.DefaultExpression(SyntaxFactory.ParseTypeName(type.ToMinimalDisplayString(semanticModel, node.SpanStart))) : Literal(null);
return !type.IsReferenceType ? SyntaxFactory.DefaultExpression(SyntaxFactory.ParseTypeName(type.ToMinimalDisplayString(semanticModel, node.SpanStart))) : Literal("null", null);
}
return Literal(node.Token.Value);
return Literal(node.Token.Text, node.Token.Value);
}
public override CSharpSyntaxNode VisitInterpolatedStringExpression(VBSyntax.InterpolatedStringExpressionSyntax node)
@ -1230,13 +1230,30 @@ namespace ICSharpCode.CodeConverter.CSharp
return SyntaxFactory.BinaryExpression(SyntaxKind.NotEqualsExpression, otherArgument, SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression));
}
}
var kind = ConvertToken(VBasic.VisualBasicExtensions.Kind(node), TokenContext.Local);
return SyntaxFactory.BinaryExpression(
kind,
(ExpressionSyntax)node.Left.Accept(TriviaConvertingVisitor),
SyntaxFactory.Token(CSharpUtil.GetExpressionOperatorTokenKind(kind)),
(ExpressionSyntax)node.Right.Accept(TriviaConvertingVisitor)
);
var lhs = (ExpressionSyntax)node.Left.Accept(TriviaConvertingVisitor);
var op = SyntaxFactory.Token(CSharpUtil.GetExpressionOperatorTokenKind(kind));
var rhs = (ExpressionSyntax)node.Right.Accept(TriviaConvertingVisitor);
// VB DivideExpression "/" is always on doubles unless you use the "\" IntegerDivideExpression, so need to cast in C#
// Need the unconverted type, since the whole point is that it gets converted to a double by the operator
if (node.IsKind(VBasic.SyntaxKind.DivideExpression) && !HasOperandOfUnconvertedType(node, "System.Double")) {
var doubleType = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DoubleKeyword));
rhs = SyntaxFactory.CastExpression(doubleType, rhs);
}
return SyntaxFactory.BinaryExpression(kind, lhs, op, rhs);
}
private bool HasOperandOfUnconvertedType(VBSyntax.BinaryExpressionSyntax node, string operandType)
{
return new[] {node.Left, node.Right}.Any(e => UnconvertedIsType(e, operandType));
}
private bool UnconvertedIsType(VBSyntax.ExpressionSyntax e, string fullTypeName)
{
return semanticModel.GetTypeInfo(e).Type?.GetFullMetadataName() == fullTypeName;
}
public override CSharpSyntaxNode VisitInvocationExpression(VBSyntax.InvocationExpressionSyntax node)

Просмотреть файл

@ -80,9 +80,9 @@ namespace ICSharpCode.CodeConverter.CSharp
return newDecls;
}
static ExpressionSyntax Literal(object o) => GetLiteralExpression(o);
static ExpressionSyntax Literal(string valueText, object o) => GetLiteralExpression(valueText, o);
internal static ExpressionSyntax GetLiteralExpression(object value)
internal static ExpressionSyntax GetLiteralExpression(string valueText, object value)
{
if (value is bool)
return SyntaxFactory.LiteralExpression((bool)value ? SyntaxKind.TrueLiteralExpression : SyntaxKind.FalseLiteralExpression);
@ -105,10 +105,14 @@ namespace ICSharpCode.CodeConverter.CSharp
if (value is float)
return SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal((float)value));
if (value is double)
return SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal((double)value));
if (value is decimal)
if (value is double) {
// Important to use value text, otherwise "10.0" gets coerced to and integer literal of 10 which can change semantics
return SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(valueText, (double)value));
}
if (value is decimal) {
// Don't use value text - it has a "D" in VB, but an "M" in C#
return SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal((decimal)value));
}
if (value is char)
return SyntaxFactory.LiteralExpression(SyntaxKind.CharacterLiteralExpression, SyntaxFactory.Literal((char)value));

Просмотреть файл

@ -104,6 +104,28 @@ End Class", @"class TestClass
}");
}
[Fact]
public void FloatingPointDivisionIsForced()
{
TestConversionVisualBasicToCSharp(@"Class TestClass
Private Sub TestMethod()
Dim x = 10 / 3
x /= 2
Dim y = 10.0 / 3
y /= 2
End Sub
End Class", @"class TestClass
{
private void TestMethod()
{
var x = 10 / (double)3;
x /= 2;
var y = 10.0 / 3;
y /= 2;
}
}");
}
[Fact]
public void FullyTypeInferredEnumerableCreation()
{
@ -482,7 +504,7 @@ class TestClass
var test2 = (a, b) =>
{
if (b > 0)
return a / b;
return a / (double)b;
return 0;
};