/// <summary> /// Gets whether the specific binary instruction is compatible with a compound operation on the specified type. /// </summary> internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type) { if (binary.IsLifted) { if (!NullableType.IsNullable(type)) { return(false); } type = NullableType.GetUnderlyingType(type); } if (type.Kind == TypeKind.Enum) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: case BinaryNumericOperator.BitAnd: case BinaryNumericOperator.BitOr: case BinaryNumericOperator.BitXor: break; // OK default: return(false); // operator not supported on enum types } } else if (type.Kind == TypeKind.Pointer) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: // ensure that the byte offset is a multiple of the pointer size return(PointerArithmeticOffset.Detect( binary.Right, (PointerType)type, checkForOverflow: binary.CheckForOverflow ) != null); default: return(false); // operator not supported on pointer types } } if (binary.Sign != Sign.None) { if (type.GetSign() != binary.Sign) { return(false); } } return(true); }
/// <summary> /// Gets whether the specific binary instruction is compatible with a compound operation on the specified type. /// </summary> internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type) { if (binary.IsLifted) { if (!NullableType.IsNullable(type)) { return(false); } type = NullableType.GetUnderlyingType(type); } if (type.Kind == TypeKind.Unknown) { return(false); // avoid introducing a potentially-incorrect compound assignment } else if (type.Kind == TypeKind.Enum) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: case BinaryNumericOperator.BitAnd: case BinaryNumericOperator.BitOr: case BinaryNumericOperator.BitXor: break; // OK default: return(false); // operator not supported on enum types } } else if (type.Kind == TypeKind.Pointer) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: // ensure that the byte offset is a multiple of the pointer size return(PointerArithmeticOffset.Detect( binary.Right, (PointerType)type, checkForOverflow: binary.CheckForOverflow ) != null); default: return(false); // operator not supported on pointer types } } if (binary.Sign != Sign.None) { if (type.IsCSharpSmallIntegerType()) { // C# will use numeric promotion to int, binary op must be signed if (binary.Sign != Sign.Signed) { return(false); } } else { // C# will use sign from type if (type.GetSign() != binary.Sign) { return(false); } } } // Can't transform if the RHS value would be need to be truncated for the LHS type. if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, binary.IsLifted)) { return(false); } return(true); }
/// <summary> /// Gets whether the specific binary instruction is compatible with a compound operation on the specified type. /// </summary> internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type, DecompilerSettings settings) { if (binary.IsLifted) { if (!NullableType.IsNullable(type)) { return(false); } type = NullableType.GetUnderlyingType(type); } if (type.Kind == TypeKind.Unknown) { return(false); // avoid introducing a potentially-incorrect compound assignment } else if (type.Kind == TypeKind.Enum) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: case BinaryNumericOperator.BitAnd: case BinaryNumericOperator.BitOr: case BinaryNumericOperator.BitXor: break; // OK default: return(false); // operator not supported on enum types } } else if (type.Kind == TypeKind.Pointer) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: // ensure that the byte offset is a multiple of the pointer size return(PointerArithmeticOffset.Detect( binary.Right, ((PointerType)type).ElementType, checkForOverflow: binary.CheckForOverflow ) != null); default: return(false); // operator not supported on pointer types } } else if (type.IsKnownType(KnownTypeCode.IntPtr) || type.IsKnownType(KnownTypeCode.UIntPtr)) { // "target.intptr *= 2;" is compiler error, but // "target.intptr *= (nint)2;" works if (settings != null && !settings.NativeIntegers) { // But if native integers are not available, we cannot use compound assignment. return(false); } // The trick with casting the RHS to n(u)int doesn't work for shifts: switch (binary.Operator) { case BinaryNumericOperator.ShiftLeft: case BinaryNumericOperator.ShiftRight: return(false); } } if (binary.Sign != Sign.None) { if (type.IsCSharpSmallIntegerType()) { // C# will use numeric promotion to int, binary op must be signed if (binary.Sign != Sign.Signed) { return(false); } } else { // C# will use sign from type if (type.GetSign() != binary.Sign) { return(false); } } } // Can't transform if the RHS value would be need to be truncated for the LHS type. if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, null, binary.IsLifted)) { return(false); } return(true); }