Browse Source

Fix #1308: Consider type hint in ldc.i8 translation.

pull/1322/head
Daniel Grunwald 7 years ago
parent
commit
b33d338558
  1. 6
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs
  2. 75
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 2
      ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs

6
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs

@ -591,7 +591,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -591,7 +591,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
num++;
}
return -2147483648;
return int.MinValue;
}
//public int InterestingLoop()
@ -615,7 +615,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -615,7 +615,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
// num++;
// }
// // This instruction is still dominated by the loop header
// num = -2147483648;//int.MinValue;
// num = int.MinValue;
// }
// return num;
//}
@ -638,7 +638,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -638,7 +638,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
num++;
}
}
num = -2147483648;
num = int.MinValue;
}
return num;
}

75
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -323,25 +323,40 @@ namespace ICSharpCode.Decompiler.CSharp @@ -323,25 +323,40 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLdcI4(LdcI4 inst, TranslationContext context)
{
string literalValue = null;
if (ShouldDisplayAsHex(inst.Value, inst.Parent)) {
literalValue = $"0x{inst.Value:X}";
ResolveResult rr;
if (context.TypeHint.GetSign() == Sign.Unsigned) {
rr = new ConstantResolveResult(
compilation.FindType(KnownTypeCode.UInt32),
unchecked((uint)inst.Value)
);
} else {
rr = new ConstantResolveResult(
compilation.FindType(KnownTypeCode.Int32),
inst.Value
);
}
var expr = new PrimitiveExpression(inst.Value, literalValue)
.WithILInstruction(inst)
.WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), inst.Value));
return AdjustConstantExpressionToType(expr, context.TypeHint);
rr = AdjustConstantToType(rr, context.TypeHint);
return ConvertConstantValue(rr, allowImplicitConversion: true)
.WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitLdcI8(LdcI8 inst, TranslationContext context)
{
string literalValue = null;
if (ShouldDisplayAsHex(inst.Value, inst.Parent)) {
literalValue = $"0x{inst.Value:X}";
ResolveResult rr;
if (context.TypeHint.GetSign() == Sign.Unsigned) {
rr = new ConstantResolveResult(
compilation.FindType(KnownTypeCode.UInt64),
unchecked((ulong)inst.Value)
);
} else {
rr = new ConstantResolveResult(
compilation.FindType(KnownTypeCode.Int64),
inst.Value
);
}
return new PrimitiveExpression(inst.Value, literalValue)
.WithILInstruction(inst)
.WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int64), inst.Value));
rr = AdjustConstantToType(rr, context.TypeHint);
return ConvertConstantValue(rr, allowImplicitConversion: true)
.WithILInstruction(inst);
}
private bool ShouldDisplayAsHex(long value, ILInstruction parent)
@ -2245,22 +2260,36 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2245,22 +2260,36 @@ namespace ICSharpCode.Decompiler.CSharp
/// convert the expression into the target type.
/// Otherwise, returns the expression unmodified.
/// </summary>
TranslatedExpression AdjustConstantExpressionToType(TranslatedExpression expr, IType type)
TranslatedExpression AdjustConstantExpressionToType(TranslatedExpression expr, IType typeHint)
{
if (!expr.ResolveResult.IsCompileTimeConstant) {
var newRR = AdjustConstantToType(expr.ResolveResult, typeHint);
if (newRR == expr.ResolveResult) {
return expr;
} else {
return ConvertConstantValue(newRR).WithILInstruction(expr.ILInstructions);
}
type = NullableType.GetUnderlyingType(type);
if (type.IsKnownType(KnownTypeCode.Boolean)
&& (object.Equals(expr.ResolveResult.ConstantValue, 0) || object.Equals(expr.ResolveResult.ConstantValue, 1))) {
return expr.ConvertToBoolean(this);
} else if (type.Kind == TypeKind.Enum || type.IsKnownType(KnownTypeCode.Char)) {
var castRR = resolver.WithCheckForOverflow(true).ResolveCast(type, expr.ResolveResult);
}
private ResolveResult AdjustConstantToType(ResolveResult rr, IType typeHint)
{
if (!rr.IsCompileTimeConstant) {
return rr;
}
typeHint = NullableType.GetUnderlyingType(typeHint);
// Convert to type hint, if this is possible without loss of accuracy
if (typeHint.IsKnownType(KnownTypeCode.Boolean)) {
if (object.Equals(rr.ConstantValue, 0)) {
rr = new ConstantResolveResult(typeHint, false);
} else if (object.Equals(rr.ConstantValue, 1)) {
rr = new ConstantResolveResult(typeHint, true);
}
} else if (typeHint.Kind == TypeKind.Enum || typeHint.IsKnownType(KnownTypeCode.Char) || typeHint.IsCSharpSmallIntegerType()) {
var castRR = resolver.WithCheckForOverflow(true).ResolveCast(typeHint, rr);
if (castRR.IsCompileTimeConstant && !castRR.IsError) {
return ConvertConstantValue(castRR).WithILInstruction(expr.ILInstructions);
rr = castRR;
}
}
return expr;
return rr;
}
protected internal override TranslatedExpression VisitNullCoalescingInstruction(NullCoalescingInstruction inst, TranslationContext context)

2
ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs

@ -116,7 +116,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -116,7 +116,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// <summary>
/// Gets whether the type is a C# small integer type: byte, sbyte, short or ushort.
///
/// Unlike the ILAst, C# does not consider bool or enums to be small integers.
/// Unlike the ILAst, C# does not consider bool, char or enums to be small integers.
/// </summary>
public static bool IsCSharpSmallIntegerType(this IType type)
{

Loading…
Cancel
Save