From 9afbcba79af4f5986028dd387dcf927afc638162 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Mon, 7 Sep 2020 11:27:09 +0200 Subject: [PATCH] Fix #1796: Use hexadecimal literals with bitwise operators. --- .../TestCases/Pretty/ConstantsTests.cs | 209 +++++++++++++++++- .../TestCases/Pretty/TypeAnalysisTests.cs | 19 ++ .../CSharp/ExpressionBuilder.cs | 81 +++++-- 3 files changed, 284 insertions(+), 25 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs index 83d9eb8bf..7984a9914 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs @@ -6,7 +6,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { public ulong Issue1308(ulong u = 8uL) { - Test((u & uint.MaxValue) != 0); + Test((u & 0xFFFFFFFFu) != 0); return 18446744069414584320uL; } @@ -50,5 +50,212 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty Test(decimal.MinValue); 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 _) + { + + } } } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs index 7c47e5aea..cd164998e 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/TypeAnalysisTests.cs @@ -28,6 +28,25 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } 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) { diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 7d2ea9324..702444d85 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -133,6 +133,20 @@ namespace ICSharpCode.Decompiler.CSharp 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) { Debug.Assert(inst != null); @@ -503,16 +517,11 @@ namespace ICSharpCode.Decompiler.CSharp ); } rr = AdjustConstantToType(rr, context.TypeHint); - astBuilder.PrintIntegralValuesAsHex = ShouldDisplayAsHex(inst.Value, inst.Parent); - try - { - return ConvertConstantValue(rr, allowImplicitConversion: true) - .WithILInstruction(inst); - } - finally - { - astBuilder.PrintIntegralValuesAsHex = false; - } + return ConvertConstantValue( + rr, + allowImplicitConversion: true, + ShouldDisplayAsHex(inst.Value, rr.Type, inst.Parent) + ).WithILInstruction(inst); } protected internal override TranslatedExpression VisitLdcI8(LdcI8 inst, TranslationContext context) @@ -533,23 +542,20 @@ namespace ICSharpCode.Decompiler.CSharp ); } rr = AdjustConstantToType(rr, context.TypeHint); - astBuilder.PrintIntegralValuesAsHex = ShouldDisplayAsHex(inst.Value, inst.Parent); - try - { - return ConvertConstantValue(rr, allowImplicitConversion: true) - .WithILInstruction(inst); - } - finally - { - astBuilder.PrintIntegralValuesAsHex = false; - } + return ConvertConstantValue( + rr, + allowImplicitConversion: true, + ShouldDisplayAsHex(inst.Value, rr.Type, inst.Parent) + ).WithILInstruction(inst); } - private bool ShouldDisplayAsHex(long value, ILInstruction parent) + private bool ShouldDisplayAsHex(long value, IType type, ILInstruction parent) { if (parent is Conv conv) parent = conv.Parent; - if (value <= 9) + if (value >= 0 && value <= 9) + return false; + if (value < 0 && type.GetSign() == Sign.Signed) return false; switch (parent) { @@ -1419,8 +1425,8 @@ namespace ICSharpCode.Decompiler.CSharp TranslatedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op, TranslationContext context) { var resolverWithOverflowCheck = resolver.WithCheckForOverflow(inst.CheckForOverflow); - var left = Translate(inst.Left); - var right = Translate(inst.Right); + var left = Translate(inst.Left, op.IsBitwise() ? context.TypeHint : null); + var right = Translate(inst.Right, op.IsBitwise() ? context.TypeHint : null); 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 sign = context.TypeHint.GetSign(); + if (sign == Sign.None) + { + sign = op.IsBitwise() ? Sign.Unsigned : Sign.Signed; + } } IType targetType = FindArithmeticType(inst.UnderlyingResultType, sign); 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); 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) .WithILInstruction(inst) .WithRR(rr);