Browse Source

Fix #1796: Use hexadecimal literals with bitwise operators.

pull/2153/head
Siegfried Pammer 5 years ago
parent
commit
9afbcba79a
  1. 209
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs
  2. 19
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs
  3. 81
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

209
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs

@ -6,7 +6,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
public ulong Issue1308(ulong u = 8uL) public ulong Issue1308(ulong u = 8uL)
{ {
Test((u & uint.MaxValue) != 0); Test((u & 0xFFFFFFFFu) != 0);
return 18446744069414584320uL; return 18446744069414584320uL;
} }
@ -50,5 +50,212 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Test(decimal.MinValue); Test(decimal.MinValue);
Test(decimal.MaxValue); Test(decimal.MaxValue);
} }
public void BitwiseAndWithConstantUInt64(ulong a)
{
ExpectUInt64(a & 7);
ExpectUInt64(a & 0x7FFFFFFF);
ExpectUInt64(a & 0xFFFFFFFFu);
ExpectUInt64(a & 0x7FFFFFFFFFFFFFFFuL);
ExpectUInt64(a & 0xFFFFFFFFFFFFFFFFuL);
}
public void BitwiseAndWithConstantInt64(long a)
{
ExpectInt64(a & 7);
ExpectInt64(a & 0x7FFFFFFF);
ExpectInt64(a & 0xFFFFFFFFu);
ExpectInt64(a & 0x7FFFFFFFFFFFFFFFL);
}
public void BitwiseAndWithConstantUInt32(uint a)
{
ExpectUInt32(a & 7u);
ExpectUInt32(a & 0x7FFFFFFFu);
ExpectUInt32(a & 0xFFFFFFFFu);
}
public void BitwiseAndWithConstantInt32(int a)
{
ExpectInt32(a & 7);
ExpectInt32(a & 0x7FFFFFFF);
}
public void BitwiseAndWithConstantUInt16(ushort a)
{
ExpectUInt16((ushort)(a & 7u));
ExpectUInt16((ushort)(a & 0x7FFFu));
ExpectUInt16((ushort)(a & 0xFFFFu));
}
public void BitwiseAndWithConstantInt16(short a)
{
ExpectInt16((short)(a & 7));
ExpectInt16((short)(a & 0x7FFF));
}
public void BitwiseAndWithConstantUInt8(byte a)
{
ExpectUInt8((byte)(a & 7u));
ExpectUInt8((byte)(a & 0x7Fu));
ExpectUInt8((byte)(a & 0xFFu));
}
public void BitwiseAndWithConstantInt8(sbyte a)
{
ExpectInt8((sbyte)(a & 7));
ExpectInt8((sbyte)(a & 0x7F));
}
public void BitwiseOrWithConstantUInt64(ulong a)
{
ExpectUInt64(a | 7);
ExpectUInt64(a | 0x7FFFFFFF);
ExpectUInt64(a | 0xFFFFFFFFu);
ExpectUInt64(a | 0x7FFFFFFFFFFFFFFFuL);
ExpectUInt64(a | 0xFFFFFFFFFFFFFFFFuL);
}
public void BitwiseOrWithConstantInt64(long a)
{
ExpectInt64(a | 7);
ExpectInt64(a | 0x7FFFFFFF);
ExpectInt64(a | 0xFFFFFFFFu);
ExpectInt64(a | 0x7FFFFFFFFFFFFFFFL);
}
public void BitwiseOrWithConstantUInt32(uint a)
{
ExpectUInt32(a | 7u);
ExpectUInt32(a | 0x7FFFFFFFu);
ExpectUInt32(a | 0xFFFFFFFFu);
}
public void BitwiseOrWithConstantInt32(int a)
{
ExpectInt32(a | 7);
ExpectInt32(a | 0x7FFFFFFF);
}
public void BitwiseOrWithConstantUInt16(ushort a)
{
ExpectUInt16((ushort)(a | 7u));
ExpectUInt16((ushort)(a | 0x7FFFu));
ExpectUInt16((ushort)(a | 0xFFFFu));
}
public void BitwiseOrWithConstantInt16(short a)
{
ExpectInt16((short)(a | 7));
ExpectInt16((short)(a | 0x7FFF));
}
public void BitwiseOrWithConstantUInt8(byte a)
{
ExpectUInt8((byte)(a | 7u));
ExpectUInt8((byte)(a | 0x7Fu));
ExpectUInt8((byte)(a | 0xFFu));
}
public void BitwiseOrWithConstantInt8(sbyte a)
{
ExpectInt8((sbyte)(a | 7));
ExpectInt8((sbyte)(a | 0x7F));
}
public void BitwiseXorWithConstantUInt64(ulong a)
{
ExpectUInt64(a ^ 7);
ExpectUInt64(a ^ 0x7FFFFFFF);
ExpectUInt64(a ^ 0xFFFFFFFFu);
ExpectUInt64(a ^ 0x7FFFFFFFFFFFFFFFuL);
ExpectUInt64(a ^ 0xFFFFFFFFFFFFFFFFuL);
}
public void BitwiseXorWithConstantInt64(long a)
{
ExpectInt64(a ^ 7);
ExpectInt64(a ^ 0x7FFFFFFF);
ExpectInt64(a ^ 0xFFFFFFFFu);
ExpectInt64(a ^ 0x7FFFFFFFFFFFFFFFL);
}
public void BitwiseXorWithConstantUInt32(uint a)
{
ExpectUInt32(a ^ 7u);
ExpectUInt32(a ^ 0x7FFFFFFFu);
ExpectUInt32(a ^ 0xFFFFFFFFu);
}
public void BitwiseXorWithConstantInt32(int a)
{
ExpectInt32(a ^ 7);
ExpectInt32(a ^ 0x7FFFFFFF);
}
public void BitwiseXorWithConstantUInt16(ushort a)
{
ExpectUInt16((ushort)(a ^ 7u));
ExpectUInt16((ushort)(a ^ 0x7FFFu));
ExpectUInt16((ushort)(a ^ 0xFFFFu));
}
public void BitwiseXorWithConstantInt16(short a)
{
ExpectInt16((short)(a ^ 7));
ExpectInt16((short)(a ^ 0x7FFF));
}
public void BitwiseXorWithConstantUInt8(byte a)
{
ExpectUInt8((byte)(a ^ 7u));
ExpectUInt8((byte)(a ^ 0x7Fu));
ExpectUInt8((byte)(a ^ 0xFFu));
}
public void BitwiseXorWithConstantInt8(sbyte a)
{
ExpectInt8((sbyte)(a ^ 7));
ExpectInt8((sbyte)(a ^ 0x7F));
}
private void ExpectUInt64(ulong _)
{
}
private void ExpectInt64(long _)
{
}
private void ExpectUInt32(uint _)
{
}
private void ExpectInt32(int _)
{
}
private void ExpectUInt16(ushort _)
{
}
private void ExpectInt16(short _)
{
}
private void ExpectUInt8(byte _)
{
}
private void ExpectInt8(sbyte _)
{
}
} }
} }

19
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs

@ -28,6 +28,25 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
private byte[] byteArray; private byte[] byteArray;
private ulong uint64Field;
public int Issue1796a {
get {
return (int)(uint64Field & 0x7FFFFFFF);
}
set {
uint64Field = ((uint64Field & 0xFFFFFFFF80000000uL) | (ulong)value);
}
}
public ushort Issue1796b {
get {
return (ushort)((uint64Field & 0xFFFF000000000000uL) >> 48);
}
set {
uint64Field = ((uint64Field & 0xFFFFFFFFFFFFuL) | ((ulong)value << 48));
}
}
public byte SubtractFrom256(byte b) public byte SubtractFrom256(byte b)
{ {

81
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -133,6 +133,20 @@ namespace ICSharpCode.Decompiler.CSharp
return new ExpressionWithResolveResult(expr, exprRR); return new ExpressionWithResolveResult(expr, exprRR);
} }
public ExpressionWithResolveResult ConvertConstantValue(ResolveResult rr,
bool allowImplicitConversion = false, bool displayAsHex = false)
{
astBuilder.PrintIntegralValuesAsHex = displayAsHex;
try
{
return ConvertConstantValue(rr, allowImplicitConversion);
}
finally
{
astBuilder.PrintIntegralValuesAsHex = false;
}
}
public TranslatedExpression Translate(ILInstruction inst, IType typeHint = null) public TranslatedExpression Translate(ILInstruction inst, IType typeHint = null)
{ {
Debug.Assert(inst != null); Debug.Assert(inst != null);
@ -503,16 +517,11 @@ namespace ICSharpCode.Decompiler.CSharp
); );
} }
rr = AdjustConstantToType(rr, context.TypeHint); rr = AdjustConstantToType(rr, context.TypeHint);
astBuilder.PrintIntegralValuesAsHex = ShouldDisplayAsHex(inst.Value, inst.Parent); return ConvertConstantValue(
try rr,
{ allowImplicitConversion: true,
return ConvertConstantValue(rr, allowImplicitConversion: true) ShouldDisplayAsHex(inst.Value, rr.Type, inst.Parent)
.WithILInstruction(inst); ).WithILInstruction(inst);
}
finally
{
astBuilder.PrintIntegralValuesAsHex = false;
}
} }
protected internal override TranslatedExpression VisitLdcI8(LdcI8 inst, TranslationContext context) protected internal override TranslatedExpression VisitLdcI8(LdcI8 inst, TranslationContext context)
@ -533,23 +542,20 @@ namespace ICSharpCode.Decompiler.CSharp
); );
} }
rr = AdjustConstantToType(rr, context.TypeHint); rr = AdjustConstantToType(rr, context.TypeHint);
astBuilder.PrintIntegralValuesAsHex = ShouldDisplayAsHex(inst.Value, inst.Parent); return ConvertConstantValue(
try rr,
{ allowImplicitConversion: true,
return ConvertConstantValue(rr, allowImplicitConversion: true) ShouldDisplayAsHex(inst.Value, rr.Type, inst.Parent)
.WithILInstruction(inst); ).WithILInstruction(inst);
}
finally
{
astBuilder.PrintIntegralValuesAsHex = false;
}
} }
private bool ShouldDisplayAsHex(long value, ILInstruction parent) private bool ShouldDisplayAsHex(long value, IType type, ILInstruction parent)
{ {
if (parent is Conv conv) if (parent is Conv conv)
parent = conv.Parent; parent = conv.Parent;
if (value <= 9) if (value >= 0 && value <= 9)
return false;
if (value < 0 && type.GetSign() == Sign.Signed)
return false; return false;
switch (parent) switch (parent)
{ {
@ -1419,8 +1425,8 @@ namespace ICSharpCode.Decompiler.CSharp
TranslatedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op, TranslationContext context) TranslatedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op, TranslationContext context)
{ {
var resolverWithOverflowCheck = resolver.WithCheckForOverflow(inst.CheckForOverflow); var resolverWithOverflowCheck = resolver.WithCheckForOverflow(inst.CheckForOverflow);
var left = Translate(inst.Left); var left = Translate(inst.Left, op.IsBitwise() ? context.TypeHint : null);
var right = Translate(inst.Right); var right = Translate(inst.Right, op.IsBitwise() ? context.TypeHint : null);
if (left.Type.Kind == TypeKind.ByReference || right.Type.Kind == TypeKind.ByReference) if (left.Type.Kind == TypeKind.ByReference || right.Type.Kind == TypeKind.ByReference)
{ {
@ -1488,12 +1494,39 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
// If the sign doesn't matter, try to use the same sign as expected by the context // If the sign doesn't matter, try to use the same sign as expected by the context
sign = context.TypeHint.GetSign(); sign = context.TypeHint.GetSign();
if (sign == Sign.None)
{
sign = op.IsBitwise() ? Sign.Unsigned : Sign.Signed;
}
} }
IType targetType = FindArithmeticType(inst.UnderlyingResultType, sign); IType targetType = FindArithmeticType(inst.UnderlyingResultType, sign);
left = left.ConvertTo(NullableType.IsNullable(left.Type) ? NullableType.Create(compilation, targetType) : targetType, this); left = left.ConvertTo(NullableType.IsNullable(left.Type) ? NullableType.Create(compilation, targetType) : targetType, this);
right = right.ConvertTo(NullableType.IsNullable(right.Type) ? NullableType.Create(compilation, targetType) : targetType, this); right = right.ConvertTo(NullableType.IsNullable(right.Type) ? NullableType.Create(compilation, targetType) : targetType, this);
rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult); rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
} }
if (op.IsBitwise())
{
if (left.ResolveResult.ConstantValue != null)
{
long value = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, left.ResolveResult.ConstantValue, checkForOverflow: false);
left = ConvertConstantValue(
left.ResolveResult,
allowImplicitConversion: false,
ShouldDisplayAsHex(value, left.Type, inst)
).WithILInstruction(left.ILInstructions);
}
if (right.ResolveResult.ConstantValue != null)
{
long value = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, right.ResolveResult.ConstantValue, checkForOverflow: false);
right = ConvertConstantValue(
right.ResolveResult,
allowImplicitConversion: false,
ShouldDisplayAsHex(value, right.Type, inst)
).WithILInstruction(right.ILInstructions);
}
}
var resultExpr = new BinaryOperatorExpression(left.Expression, op, right.Expression) var resultExpr = new BinaryOperatorExpression(left.Expression, op, right.Expression)
.WithILInstruction(inst) .WithILInstruction(inst)
.WithRR(rr); .WithRR(rr);

Loading…
Cancel
Save