Browse Source

Fix decompiling comparison operators:

* add casts when comparing integers
* fix "unordered" float comparisons
pull/728/head
Daniel Grunwald 9 years ago
parent
commit
1a77b931a7
  1. 49
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 2
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  3. 51
      ICSharpCode.Decompiler/Tests/TestCases/FloatComparisons.cs
  4. 6
      ICSharpCode.Decompiler/Tests/TestRunner.cs

49
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -325,13 +325,48 @@ namespace ICSharpCode.Decompiler.CSharp @@ -325,13 +325,48 @@ namespace ICSharpCode.Decompiler.CSharp
{
var left = Translate(inst.Left);
var right = Translate(inst.Right);
// TODO: ensure the arguments are signed
// or with _Un: ensure the arguments are unsigned; and that float comparisons are performed unordered
return new BinaryOperatorExpression(left.Expression, op, right.Expression)
// Ensure the inputs have the correct sign:
KnownTypeCode inputType = KnownTypeCode.None;
switch (inst.OpType) {
case StackType.I8:
inputType = un ? KnownTypeCode.UInt64 : KnownTypeCode.Int64;
break;
case StackType.I:
inputType = un ? KnownTypeCode.UIntPtr : KnownTypeCode.IntPtr;
break;
case StackType.I4:
inputType = un ? KnownTypeCode.UInt32 : KnownTypeCode.Int32;
break;
case StackType.F:
if (un) {
// for floats, _Un means "unordered":
// clt_un returns 1 if left < right or if either input is not-a-number
// The C# operators never return true for NaN, so we need to use a negation:
// clt_un => !(left >= right)
// cgt_un => !(left <= right)
if (op == BinaryOperatorType.LessThan)
op = BinaryOperatorType.GreaterThanOrEqual;
else if (op == BinaryOperatorType.GreaterThan)
op = BinaryOperatorType.LessThanOrEqual;
else
throw new ArgumentException("op");
}
break;
}
if (inputType != KnownTypeCode.None) {
left = left.ConvertTo(compilation.FindType(inputType), this);
right = right.ConvertTo(compilation.FindType(inputType), this);
}
var result = new BinaryOperatorExpression(left.Expression, op, right.Expression)
.WithILInstruction(inst)
.WithRR(new OperatorResolveResult(compilation.FindType(TypeCode.Boolean),
BinaryOperatorExpression.GetLinqNodeType(op, false),
left.ResolveResult, right.ResolveResult));
if (un && inst.OpType == StackType.F) {
// add negation if we turned around the operator symbol above
result = LogicNot(result).WithILInstruction(inst);
}
return result;
}
ExpressionWithResolveResult Assignment(TranslatedExpression left, TranslatedExpression right)
@ -483,9 +518,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -483,9 +518,11 @@ namespace ICSharpCode.Decompiler.CSharp
var target = TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn);
return new ObjectCreateExpression(ConvertType(inst.Method.DeclaringType), new MemberReferenceExpression(target, method.Name))
.WithILInstruction(inst)
.WithRR(new ConversionResolveResult(method.DeclaringType,
new MemberResolveResult(target.ResolveResult, method),
Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false))); // TODO handle extension methods capturing the first argument
.WithRR(new ConversionResolveResult(
method.DeclaringType,
new MemberResolveResult(target.ResolveResult, method),
// TODO handle extension methods capturing the first argument
Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false)));
}
TranslatedExpression TranslateTarget(IMember member, ILInstruction target, bool nonVirtualInvocation)

2
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -95,7 +95,6 @@ @@ -95,7 +95,6 @@
<Project>{d68133bd-1e63-496e-9ede-4fbdbf77b486}</Project>
<Name>Mono.Cecil</Name>
</ProjectReference>
<ProjectReference Include="..\..\NRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
<Project>{53dca265-3c3c-42f9-b647-f72ba678122b}</Project>
<Name>ICSharpCode.NRefactory.CSharp</Name>
@ -119,6 +118,7 @@ @@ -119,6 +118,7 @@
<Compile Include="TestCases\CompoundAssignment.cs" />
<Compile Include="TestCases\ControlFlow.cs" />
<Compile Include="TestCases\DecimalFields.cs" />
<Compile Include="TestCases\FloatComparisons.cs" />
<Compile Include="TestCases\Generics.cs" />
<Compile Include="TestCases\HelloWorld.cs" />
<Compile Include="TestCases\InitializerTests.cs" />

51
ICSharpCode.Decompiler/Tests/TestCases/FloatComparisons.cs

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// Copyright (c) 2016 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases
{
public class FloatComparisons
{
public static int Main()
{
// disable CompareOfFloatsByEqualityOperator
TestFloatOp("==", (a, b) => a == b);
TestFloatOp("!=", (a, b) => a != b);
TestFloatOp("<", (a, b) => a < b);
TestFloatOp(">", (a, b) => a > b);
TestFloatOp("<=", (a, b) => a <= b);
TestFloatOp(">=", (a, b) => a >= b);
TestFloatOp("!<", (a, b) => !(a < b));
TestFloatOp("!>", (a, b) => !(a > b));
TestFloatOp("!<=", (a, b) => !(a <= b));
TestFloatOp("!>=", (a, b) => !(a >= b));
return 0;
}
static void TestFloatOp(string name, Func<float, float, bool> f)
{
float[] vals = { -1, 0, 3, float.PositiveInfinity, float.NaN };
for (int i = 0; i < vals.Length; i++) {
for (int j = 0; j < vals.Length; j++) {
Console.WriteLine("{0:r} {1} {2:r} = {3}", vals[i], name, vals[j], f(vals[i], vals[j]));
}
}
}
}
}

6
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -28,6 +28,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -28,6 +28,12 @@ namespace ICSharpCode.Decompiler.Tests
}
}
[Test]
public void FloatComparisons()
{
TestCompileDecompileCompileOutputAll("FloatComparisons.cs");
}
[Test]
public void HelloWorld()
{

Loading…
Cancel
Save