|
|
|
@ -109,15 +109,10 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -109,15 +109,10 @@ namespace ICSharpCode.Decompiler.CSharp
|
|
|
|
|
if (!allowImplicitConversion) { |
|
|
|
|
if (expr is NullReferenceExpression && rr.Type.Kind != TypeKind.Null) { |
|
|
|
|
expr = new CastExpression(ConvertType(rr.Type), expr); |
|
|
|
|
} else { |
|
|
|
|
switch (rr.Type.GetDefinition()?.KnownTypeCode) { |
|
|
|
|
case KnownTypeCode.SByte: |
|
|
|
|
case KnownTypeCode.Byte: |
|
|
|
|
case KnownTypeCode.Int16: |
|
|
|
|
case KnownTypeCode.UInt16: |
|
|
|
|
expr = new CastExpression(new PrimitiveType(KnownTypeReference.GetCSharpNameByTypeCode(rr.Type.GetDefinition().KnownTypeCode)), expr); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} else if (rr.Type.IsCSharpSmallIntegerType()) { |
|
|
|
|
expr = new CastExpression(new PrimitiveType(KnownTypeReference.GetCSharpNameByTypeCode(rr.Type.GetDefinition().KnownTypeCode)), expr); |
|
|
|
|
} else if (rr.Type.IsCSharpNativeIntegerType()) { |
|
|
|
|
expr = new CastExpression(new PrimitiveType(rr.Type.Name), expr); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
var exprRR = expr.Annotation<ResolveResult>(); |
|
|
|
@ -900,24 +895,14 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -900,24 +895,14 @@ namespace ICSharpCode.Decompiler.CSharp
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Ensure the inputs have the correct sign:
|
|
|
|
|
KnownTypeCode inputType = KnownTypeCode.None; |
|
|
|
|
switch (inst.InputType) { |
|
|
|
|
case StackType.I: // In order to generate valid C# we need to treat (U)IntPtr as (U)Int64 in comparisons.
|
|
|
|
|
case StackType.I8: |
|
|
|
|
inputType = inst.Sign == Sign.Unsigned ? KnownTypeCode.UInt64 : KnownTypeCode.Int64; |
|
|
|
|
break; |
|
|
|
|
case StackType.I4: |
|
|
|
|
inputType = inst.Sign == Sign.Unsigned ? KnownTypeCode.UInt32 : KnownTypeCode.Int32; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (inputType != KnownTypeCode.None) { |
|
|
|
|
IType targetType = compilation.FindType(inputType); |
|
|
|
|
if (inst.InputType.IsIntegerType()) { |
|
|
|
|
// Ensure the inputs have the correct sign:
|
|
|
|
|
IType inputType = FindArithmeticType(inst.InputType, inst.Sign); |
|
|
|
|
if (inst.IsLifted) { |
|
|
|
|
targetType = NullableType.Create(compilation, targetType); |
|
|
|
|
inputType = NullableType.Create(compilation, inputType); |
|
|
|
|
} |
|
|
|
|
left = left.ConvertTo(targetType, this); |
|
|
|
|
right = right.ConvertTo(targetType, this); |
|
|
|
|
left = left.ConvertTo(inputType, this); |
|
|
|
|
right = right.ConvertTo(inputType, this); |
|
|
|
|
} |
|
|
|
|
return new BinaryOperatorExpression(left.Expression, op, right.Expression) |
|
|
|
|
.WithILInstruction(inst) |
|
|
|
@ -993,22 +978,22 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -993,22 +978,22 @@ namespace ICSharpCode.Decompiler.CSharp
|
|
|
|
|
{ |
|
|
|
|
switch (inst.Operator) { |
|
|
|
|
case BinaryNumericOperator.Add: |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.Add); |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.Add, context); |
|
|
|
|
case BinaryNumericOperator.Sub: |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.Subtract); |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.Subtract, context); |
|
|
|
|
case BinaryNumericOperator.Mul: |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.Multiply); |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.Multiply, context); |
|
|
|
|
case BinaryNumericOperator.Div: |
|
|
|
|
return HandlePointerSubtraction(inst) |
|
|
|
|
?? HandleBinaryNumeric(inst, BinaryOperatorType.Divide); |
|
|
|
|
?? HandleBinaryNumeric(inst, BinaryOperatorType.Divide, context); |
|
|
|
|
case BinaryNumericOperator.Rem: |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.Modulus); |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.Modulus, context); |
|
|
|
|
case BinaryNumericOperator.BitAnd: |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseAnd); |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseAnd, context); |
|
|
|
|
case BinaryNumericOperator.BitOr: |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseOr); |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.BitwiseOr, context); |
|
|
|
|
case BinaryNumericOperator.BitXor: |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.ExclusiveOr); |
|
|
|
|
return HandleBinaryNumeric(inst, BinaryOperatorType.ExclusiveOr, context); |
|
|
|
|
case BinaryNumericOperator.ShiftLeft: |
|
|
|
|
return HandleShift(inst, BinaryOperatorType.ShiftLeft); |
|
|
|
|
case BinaryNumericOperator.ShiftRight: |
|
|
|
@ -1158,7 +1143,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1158,7 +1143,7 @@ namespace ICSharpCode.Decompiler.CSharp
|
|
|
|
|
|
|
|
|
|
TranslatedExpression EnsureIntegerType(TranslatedExpression expr) |
|
|
|
|
{ |
|
|
|
|
if (!expr.Type.IsCSharpPrimitiveIntegerType()) { |
|
|
|
|
if (!expr.Type.IsCSharpPrimitiveIntegerType() && !expr.Type.IsCSharpNativeIntegerType()) { |
|
|
|
|
// pointer arithmetic accepts all primitive integer types, but no enums etc.
|
|
|
|
|
StackType targetType = expr.Type.GetStackType() == StackType.I4 ? StackType.I4 : StackType.I8; |
|
|
|
|
expr = expr.ConvertTo( |
|
|
|
@ -1254,7 +1239,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1254,7 +1239,7 @@ namespace ICSharpCode.Decompiler.CSharp
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TranslatedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op) |
|
|
|
|
TranslatedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOperatorType op, TranslationContext context) |
|
|
|
|
{ |
|
|
|
|
var resolverWithOverflowCheck = resolver.WithCheckForOverflow(inst.CheckForOverflow); |
|
|
|
|
var left = Translate(inst.Left); |
|
|
|
@ -1312,8 +1297,12 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1312,8 +1297,12 @@ namespace ICSharpCode.Decompiler.CSharp
|
|
|
|
|
|| !IsCompatibleWithSign(left.Type, inst.Sign) || !IsCompatibleWithSign(right.Type, inst.Sign)) |
|
|
|
|
{ |
|
|
|
|
// Left and right operands are incompatible, so convert them to a common type
|
|
|
|
|
StackType targetStackType = inst.UnderlyingResultType == StackType.I ? StackType.I8 : inst.UnderlyingResultType; |
|
|
|
|
IType targetType = compilation.FindType(targetStackType.ToKnownTypeCode(inst.Sign)); |
|
|
|
|
Sign sign = inst.Sign; |
|
|
|
|
if (sign == Sign.None) { |
|
|
|
|
// If the sign doesn't matter, try to use the same sign as expected by the context
|
|
|
|
|
sign = context.TypeHint.GetSign(); |
|
|
|
|
} |
|
|
|
|
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); |
|
|
|
@ -1327,6 +1316,28 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1327,6 +1316,28 @@ namespace ICSharpCode.Decompiler.CSharp
|
|
|
|
|
return resultExpr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
IType FindType(StackType stackType, Sign sign) |
|
|
|
|
{ |
|
|
|
|
if (stackType == StackType.I && settings.NativeIntegers) { |
|
|
|
|
return sign == Sign.Unsigned ? SpecialType.NUInt : SpecialType.NInt; |
|
|
|
|
} else { |
|
|
|
|
return compilation.FindType(stackType.ToKnownTypeCode(sign)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
IType FindArithmeticType(StackType stackType, Sign sign) |
|
|
|
|
{ |
|
|
|
|
if (stackType == StackType.I) { |
|
|
|
|
if (settings.NativeIntegers) { |
|
|
|
|
return sign == Sign.Unsigned ? SpecialType.NUInt : SpecialType.NInt; |
|
|
|
|
} else { |
|
|
|
|
// If native integers are not available, use 64-bit arithmetic instead
|
|
|
|
|
stackType = StackType.I8; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return compilation.FindType(stackType.ToKnownTypeCode(sign)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Handle oversized arguments needing truncation; and avoid IntPtr/pointers in arguments.
|
|
|
|
|
/// </summary>
|
|
|
|
@ -1339,17 +1350,17 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1339,17 +1350,17 @@ namespace ICSharpCode.Decompiler.CSharp
|
|
|
|
|
if (argStackType.IsIntegerType() && argStackType.GetSize() < argUType.GetSize()) { |
|
|
|
|
// If the argument is oversized (needs truncation to match stack size of its ILInstruction),
|
|
|
|
|
// perform the truncation now.
|
|
|
|
|
IType targetType = compilation.FindType(argStackType.ToKnownTypeCode(sign)); |
|
|
|
|
IType targetType = FindType(argStackType, sign); |
|
|
|
|
argUType = targetType; |
|
|
|
|
if (isLifted) |
|
|
|
|
targetType = NullableType.Create(compilation, targetType); |
|
|
|
|
arg = arg.ConvertTo(targetType, this); |
|
|
|
|
} |
|
|
|
|
if (argUType.GetStackType() == StackType.I) { |
|
|
|
|
if (argUType.IsKnownType(KnownTypeCode.IntPtr) || argUType.IsKnownType(KnownTypeCode.UIntPtr)) { |
|
|
|
|
// None of the operators we might want to apply are supported by IntPtr/UIntPtr.
|
|
|
|
|
// Also, pointer arithmetic has different semantics (works in number of elements, not bytes).
|
|
|
|
|
// So any inputs of size StackType.I must be converted to long/ulong.
|
|
|
|
|
IType targetType = compilation.FindType(StackType.I8.ToKnownTypeCode(sign)); |
|
|
|
|
IType targetType = FindArithmeticType(StackType.I, sign); |
|
|
|
|
if (isLifted) |
|
|
|
|
targetType = NullableType.Create(compilation, targetType); |
|
|
|
|
arg = arg.ConvertTo(targetType, this); |
|
|
|
@ -1631,7 +1642,11 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1631,7 +1642,11 @@ namespace ICSharpCode.Decompiler.CSharp
|
|
|
|
|
|
|
|
|
|
protected internal override TranslatedExpression VisitConv(Conv inst, TranslationContext context) |
|
|
|
|
{ |
|
|
|
|
var arg = Translate(inst.Argument); |
|
|
|
|
Sign hintSign = inst.InputSign; |
|
|
|
|
if (hintSign == Sign.None) { |
|
|
|
|
hintSign = context.TypeHint.GetSign(); |
|
|
|
|
} |
|
|
|
|
var arg = Translate(inst.Argument, typeHint: FindArithmeticType(inst.InputType, hintSign)); |
|
|
|
|
IType inputType = NullableType.GetUnderlyingType(arg.Type); |
|
|
|
|
StackType inputStackType = inst.InputType; |
|
|
|
|
// Note: we're dealing with two conversions here:
|
|
|
|
@ -2344,8 +2359,17 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2344,8 +2359,17 @@ namespace ICSharpCode.Decompiler.CSharp
|
|
|
|
|
|
|
|
|
|
protected internal override TranslatedExpression VisitBox(Box inst, TranslationContext context) |
|
|
|
|
{ |
|
|
|
|
IType targetType = inst.Type; |
|
|
|
|
var arg = Translate(inst.Argument, typeHint: targetType); |
|
|
|
|
if (settings.NativeIntegers && !arg.Type.Equals(targetType)) { |
|
|
|
|
if (targetType.IsKnownType(KnownTypeCode.IntPtr)) { |
|
|
|
|
targetType = SpecialType.NInt; |
|
|
|
|
} else if (targetType.IsKnownType(KnownTypeCode.UIntPtr)) { |
|
|
|
|
targetType = SpecialType.NUInt; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
arg = arg.ConvertTo(targetType, this); |
|
|
|
|
var obj = compilation.FindType(KnownTypeCode.Object); |
|
|
|
|
var arg = Translate(inst.Argument, typeHint: inst.Type).ConvertTo(inst.Type, this); |
|
|
|
|
return new CastExpression(ConvertType(obj), arg.Expression) |
|
|
|
|
.WithILInstruction(inst) |
|
|
|
|
.WithRR(new ConversionResolveResult(obj, arg.ResolveResult, Conversion.BoxingConversion)); |
|
|
|
|