diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 8eb0b517e..ff308e32e 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -1131,6 +1131,8 @@ namespace ICSharpCode.Decompiler.Ast return new Ast.PrimitiveExpression(false); else if (TypeAnalysis.IsBoolean(type) && val == 1) return new Ast.PrimitiveExpression(true); + else if (val == 0 && type is PointerType) + return new Ast.NullReferenceExpression(); if (type != null) { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) TypeDefinition enumDefinition = type.Resolve(); diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index baae6be02..133ad95d8 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -318,9 +318,9 @@ namespace ICSharpCode.Decompiler.Ast case ILCode.Conv_U2: case ILCode.Conv_U4: case ILCode.Conv_U8: + case ILCode.Conv_I: + case ILCode.Conv_U: return arg1; // conversion is handled by Convert() function using the info from type analysis - case ILCode.Conv_I: return arg1.CastTo(typeof(IntPtr)); // TODO - case ILCode.Conv_U: return arg1.CastTo(typeof(UIntPtr)); // TODO case ILCode.Conv_R4: return arg1.CastTo(typeof(float)); case ILCode.Conv_R8: return arg1.CastTo(typeof(double)); case ILCode.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO @@ -352,35 +352,18 @@ namespace ICSharpCode.Decompiler.Ast case ILCode.Unbox: return InlineAssembly(byteCode, args); #endregion #region Indirect - case ILCode.Ldind_I: - case ILCode.Ldind_I1: - case ILCode.Ldind_I2: - case ILCode.Ldind_I4: - case ILCode.Ldind_I8: - case ILCode.Ldind_U1: - case ILCode.Ldind_U2: - case ILCode.Ldind_U4: - case ILCode.Ldind_R4: - case ILCode.Ldind_R8: case ILCode.Ldind_Ref: case ILCode.Ldobj: - if (args[0] is DirectionExpression) - return ((DirectionExpression)args[0]).Expression.Detach(); + if (arg1 is DirectionExpression) + return ((DirectionExpression)arg1).Expression.Detach(); else - return InlineAssembly(byteCode, args); - case ILCode.Stind_I: - case ILCode.Stind_I1: - case ILCode.Stind_I2: - case ILCode.Stind_I4: - case ILCode.Stind_I8: - case ILCode.Stind_R4: - case ILCode.Stind_R8: + return new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1); case ILCode.Stind_Ref: case ILCode.Stobj: - if (args[0] is DirectionExpression) - return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), args[1]); + if (arg1 is DirectionExpression) + return new AssignmentExpression(((DirectionExpression)arg1).Expression.Detach(), arg2); else - return InlineAssembly(byteCode, args); + return new AssignmentExpression(new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1), arg2); #endregion case ILCode.Arglist: return InlineAssembly(byteCode, args); case ILCode.Break: return InlineAssembly(byteCode, args); @@ -769,6 +752,22 @@ namespace ICSharpCode.Decompiler.Ast { if (reqType == null || actualType == reqType) { return expr; + } else if (actualType is ByReferenceType && reqType is PointerType && expr is DirectionExpression) { + return Convert( + new UnaryOperatorExpression(UnaryOperatorType.AddressOf, ((DirectionExpression)expr).Expression.Detach()), + new PointerType(((ByReferenceType)actualType).ElementType), + reqType); + } else if (actualType is PointerType && reqType is ByReferenceType) { + expr = Convert(expr, actualType, new PointerType(((ByReferenceType)reqType).ElementType)); + return new DirectionExpression { + FieldDirection = FieldDirection.Ref, + Expression = new UnaryOperatorExpression(UnaryOperatorType.Dereference, expr) + }; + } else if (actualType is PointerType && reqType is PointerType) { + if (actualType.FullName != reqType.FullName) + return expr.CastTo(AstBuilder.ConvertType(reqType)); + else + return expr; } else { bool actualIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(actualType); bool requiredIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(reqType); diff --git a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs b/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs new file mode 100644 index 000000000..936313b72 --- /dev/null +++ b/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs @@ -0,0 +1,50 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using ICSharpCode.NRefactory.CSharp; + +namespace ICSharpCode.Decompiler.Ast.Transforms +{ + public class IntroduceUnsafeModifier : DepthFirstAstVisitor, IAstTransform + { + public void Run(AstNode compilationUnit) + { + compilationUnit.AcceptVisitor(this, null); + } + + protected override bool VisitChildren(AstNode node, object data) + { + bool result = false; + for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { + result |= child.AcceptVisitor(this, data); + } + if (result && node is AttributedNode && !(node is Accessor)) { + ((AttributedNode)node).Modifiers |= Modifiers.Unsafe; + return false; + } + return result; + } + + public override bool VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data) + { + return true; + } + + public override bool VisitComposedType(ComposedType composedType, object data) + { + if (composedType.PointerRank > 0) + return true; + else + return base.VisitComposedType(composedType, data); + } + + public override bool VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) + { + if (unaryOperatorExpression.Operator == UnaryOperatorType.Dereference || unaryOperatorExpression.Operator == UnaryOperatorType.AddressOf) + return true; + else + return base.VisitUnaryOperatorExpression(unaryOperatorExpression, data); + } + } +} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs b/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs index b4aedf175..88a44523f 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs @@ -22,6 +22,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms new PatternStatementTransform(context), new ConvertConstructorCallIntoInitializer(), new ReplaceMethodCallsWithOperators(), + new IntroduceUnsafeModifier(), }; } diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 2134b1f91..784a0e12a 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -60,6 +60,7 @@ + diff --git a/ICSharpCode.Decompiler/ILAst/ILCodes.cs b/ICSharpCode.Decompiler/ILAst/ILCodes.cs index a2cd160e5..7d5daed98 100644 --- a/ICSharpCode.Decompiler/ILAst/ILCodes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILCodes.cs @@ -102,24 +102,24 @@ namespace ICSharpCode.Decompiler.ILAst __Ble_Un, __Blt_Un, Switch, - Ldind_I1, - Ldind_U1, - Ldind_I2, - Ldind_U2, - Ldind_I4, - Ldind_U4, - Ldind_I8, - Ldind_I, - Ldind_R4, - Ldind_R8, + __Ldind_I1, + __Ldind_U1, + __Ldind_I2, + __Ldind_U2, + __Ldind_I4, + __Ldind_U4, + __Ldind_I8, + __Ldind_I, + __Ldind_R4, + __Ldind_R8, Ldind_Ref, Stind_Ref, - Stind_I1, - Stind_I2, - Stind_I4, - Stind_I8, - Stind_R4, - Stind_R8, + __Stind_I1, + __Stind_I2, + __Stind_I4, + __Stind_I8, + __Stind_R4, + __Stind_R8, Add, Sub, Mul, @@ -222,7 +222,7 @@ namespace ICSharpCode.Decompiler.ILAst Endfinally, Leave, __Leave_S, - Stind_I, + __Stind_I, Conv_U, Arglist, Ceq, @@ -375,49 +375,64 @@ namespace ICSharpCode.Decompiler.ILAst public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody) { switch (code) { - case ILCode.__Ldarg_0: code = ILCode.__Ldarg; operand = methodBody.GetParameter(0); break; - case ILCode.__Ldarg_1: code = ILCode.__Ldarg; operand = methodBody.GetParameter(1); break; - case ILCode.__Ldarg_2: code = ILCode.__Ldarg; operand = methodBody.GetParameter(2); break; - case ILCode.__Ldarg_3: code = ILCode.__Ldarg; operand = methodBody.GetParameter(3); break; - case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break; - case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break; - case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break; - case ILCode.__Ldloc_3: code = ILCode.Ldloc; operand = methodBody.Variables[3]; break; - case ILCode.__Stloc_0: code = ILCode.Stloc; operand = methodBody.Variables[0]; break; - case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break; - case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break; - case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break; - case ILCode.__Ldarg_S: code = ILCode.__Ldarg; break; - case ILCode.__Ldarga_S: code = ILCode.__Ldarga; break; - case ILCode.__Starg_S: code = ILCode.__Starg; break; - case ILCode.__Ldloc_S: code = ILCode.Ldloc; break; - case ILCode.__Ldloca_S: code = ILCode.Ldloca; break; - case ILCode.__Stloc_S: code = ILCode.Stloc; break; - case ILCode.__Ldc_I4_M1: code = ILCode.Ldc_I4; operand = -1; break; - case ILCode.__Ldc_I4_0: code = ILCode.Ldc_I4; operand = 0; break; - case ILCode.__Ldc_I4_1: code = ILCode.Ldc_I4; operand = 1; break; - case ILCode.__Ldc_I4_2: code = ILCode.Ldc_I4; operand = 2; break; - case ILCode.__Ldc_I4_3: code = ILCode.Ldc_I4; operand = 3; break; - case ILCode.__Ldc_I4_4: code = ILCode.Ldc_I4; operand = 4; break; - case ILCode.__Ldc_I4_5: code = ILCode.Ldc_I4; operand = 5; break; - case ILCode.__Ldc_I4_6: code = ILCode.Ldc_I4; operand = 6; break; - case ILCode.__Ldc_I4_7: code = ILCode.Ldc_I4; operand = 7; break; - case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break; - case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break; - case ILCode.__Br_S: code = ILCode.Br; break; - case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break; - case ILCode.__Brtrue_S: code = ILCode.Brtrue; break; - case ILCode.__Beq_S: code = ILCode.__Beq; break; - case ILCode.__Bge_S: code = ILCode.__Bge; break; - case ILCode.__Bgt_S: code = ILCode.__Bgt; break; - case ILCode.__Ble_S: code = ILCode.__Ble; break; - case ILCode.__Blt_S: code = ILCode.__Blt; break; - case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break; - case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break; - case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break; - case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break; - case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break; - case ILCode.__Leave_S: code = ILCode.Leave; break; + case ILCode.__Ldarg_0: code = ILCode.__Ldarg; operand = methodBody.GetParameter(0); break; + case ILCode.__Ldarg_1: code = ILCode.__Ldarg; operand = methodBody.GetParameter(1); break; + case ILCode.__Ldarg_2: code = ILCode.__Ldarg; operand = methodBody.GetParameter(2); break; + case ILCode.__Ldarg_3: code = ILCode.__Ldarg; operand = methodBody.GetParameter(3); break; + case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break; + case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break; + case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break; + case ILCode.__Ldloc_3: code = ILCode.Ldloc; operand = methodBody.Variables[3]; break; + case ILCode.__Stloc_0: code = ILCode.Stloc; operand = methodBody.Variables[0]; break; + case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break; + case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break; + case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break; + case ILCode.__Ldarg_S: code = ILCode.__Ldarg; break; + case ILCode.__Ldarga_S: code = ILCode.__Ldarga; break; + case ILCode.__Starg_S: code = ILCode.__Starg; break; + case ILCode.__Ldloc_S: code = ILCode.Ldloc; break; + case ILCode.__Ldloca_S: code = ILCode.Ldloca; break; + case ILCode.__Stloc_S: code = ILCode.Stloc; break; + case ILCode.__Ldc_I4_M1: code = ILCode.Ldc_I4; operand = -1; break; + case ILCode.__Ldc_I4_0: code = ILCode.Ldc_I4; operand = 0; break; + case ILCode.__Ldc_I4_1: code = ILCode.Ldc_I4; operand = 1; break; + case ILCode.__Ldc_I4_2: code = ILCode.Ldc_I4; operand = 2; break; + case ILCode.__Ldc_I4_3: code = ILCode.Ldc_I4; operand = 3; break; + case ILCode.__Ldc_I4_4: code = ILCode.Ldc_I4; operand = 4; break; + case ILCode.__Ldc_I4_5: code = ILCode.Ldc_I4; operand = 5; break; + case ILCode.__Ldc_I4_6: code = ILCode.Ldc_I4; operand = 6; break; + case ILCode.__Ldc_I4_7: code = ILCode.Ldc_I4; operand = 7; break; + case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break; + case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break; + case ILCode.__Br_S: code = ILCode.Br; break; + case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break; + case ILCode.__Brtrue_S: code = ILCode.Brtrue; break; + case ILCode.__Beq_S: code = ILCode.__Beq; break; + case ILCode.__Bge_S: code = ILCode.__Bge; break; + case ILCode.__Bgt_S: code = ILCode.__Bgt; break; + case ILCode.__Ble_S: code = ILCode.__Ble; break; + case ILCode.__Blt_S: code = ILCode.__Blt; break; + case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break; + case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break; + case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break; + case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break; + case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break; + case ILCode.__Leave_S: code = ILCode.Leave; break; + case ILCode.__Ldind_I: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.IntPtr; break; + case ILCode.__Ldind_I1: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.SByte; break; + case ILCode.__Ldind_I2: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int16; break; + case ILCode.__Ldind_I4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int32; break; + case ILCode.__Ldind_I8: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int64; break; + case ILCode.__Ldind_U1: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Byte; break; + case ILCode.__Ldind_U2: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.UInt16; break; + case ILCode.__Ldind_U4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.UInt32; break; + case ILCode.__Ldind_R4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Single; break; + case ILCode.__Ldind_R8: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Double; break; + case ILCode.__Stind_I: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.IntPtr; break; + case ILCode.__Stind_I1: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Byte; break; + case ILCode.__Stind_I2: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int16; break; + case ILCode.__Stind_I4: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int32; break; + case ILCode.__Stind_I8: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int64; break; } } diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index 37caf86c8..2b0947484 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -108,7 +108,10 @@ namespace ICSharpCode.Decompiler.ILAst /// The inferred type TypeReference InferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false) { - expr.ExpectedType = expectedType; + if (expectedType != null && expr.ExpectedType != expectedType) { + expr.ExpectedType = expectedType; + forceInferChildren = true; + } if (forceInferChildren || expr.InferredType == null) expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren); return expr.InferredType; @@ -235,25 +238,8 @@ namespace ICSharpCode.Decompiler.ILAst return GetFieldType((FieldReference)expr.Operand); #endregion #region Reference/Pointer instructions - case ILCode.Ldind_I: - case ILCode.Ldind_I1: - case ILCode.Ldind_I2: - case ILCode.Ldind_I4: - case ILCode.Ldind_I8: - case ILCode.Ldind_U1: - case ILCode.Ldind_U2: - case ILCode.Ldind_U4: - case ILCode.Ldind_R4: - case ILCode.Ldind_R8: case ILCode.Ldind_Ref: return UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); - case ILCode.Stind_I1: - case ILCode.Stind_I2: - case ILCode.Stind_I4: - case ILCode.Stind_I8: - case ILCode.Stind_R4: - case ILCode.Stind_R8: - case ILCode.Stind_I: case ILCode.Stind_Ref: if (forceInferChildren) { TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); @@ -261,12 +247,18 @@ namespace ICSharpCode.Decompiler.ILAst } return null; case ILCode.Ldobj: + if (forceInferChildren) { + if (InferTypeForExpression(expr.Arguments[0], new ByReferenceType((TypeReference)expr.Operand)) is PointerType) + InferTypeForExpression(expr.Arguments[0], new PointerType((TypeReference)expr.Operand)); + } return (TypeReference)expr.Operand; case ILCode.Stobj: if (forceInferChildren) { + if (InferTypeForExpression(expr.Arguments[0], new ByReferenceType((TypeReference)expr.Operand)) is PointerType) + InferTypeForExpression(expr.Arguments[0], new PointerType((TypeReference)expr.Operand)); InferTypeForExpression(expr.Arguments[1], (TypeReference)expr.Operand); } - return null; + return (TypeReference)expr.Operand; case ILCode.Initobj: return null; case ILCode.DefaultValue: @@ -326,9 +318,9 @@ namespace ICSharpCode.Decompiler.ILAst case ILCode.Ldc_I4: if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1)) return typeSystem.Boolean; - return IsIntegerOrEnum(expectedType) ? expectedType : typeSystem.Int32; + return (IsIntegerOrEnum(expectedType) || expectedType is PointerType) ? expectedType : typeSystem.Int32; case ILCode.Ldc_I8: - return (IsIntegerOrEnum(expectedType)) ? expectedType : typeSystem.Int64; + return (IsIntegerOrEnum(expectedType) || expectedType is PointerType) ? expectedType : typeSystem.Int64; case ILCode.Ldc_R4: return typeSystem.Single; case ILCode.Ldc_R8: @@ -411,43 +403,43 @@ namespace ICSharpCode.Decompiler.ILAst case ILCode.Conv_I1: case ILCode.Conv_Ovf_I1: case ILCode.Conv_Ovf_I1_Un: - return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == true) ? expectedType : typeSystem.SByte; + return HandleConversion(8, true, expr.Arguments[0], expectedType, typeSystem.Byte); case ILCode.Conv_I2: case ILCode.Conv_Ovf_I2: case ILCode.Conv_Ovf_I2_Un: - return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int16; + return HandleConversion(16, true, expr.Arguments[0], expectedType, typeSystem.UInt16); case ILCode.Conv_I4: case ILCode.Conv_Ovf_I4: case ILCode.Conv_Ovf_I4_Un: - return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int32; + return HandleConversion(32, true, expr.Arguments[0], expectedType, typeSystem.UInt32); case ILCode.Conv_I8: case ILCode.Conv_Ovf_I8: case ILCode.Conv_Ovf_I8_Un: - return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int64; + return HandleConversion(64, true, expr.Arguments[0], expectedType, typeSystem.UInt64); case ILCode.Conv_U1: case ILCode.Conv_Ovf_U1: case ILCode.Conv_Ovf_U1_Un: - return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == false) ? expectedType : typeSystem.Byte; + return HandleConversion(8, false, expr.Arguments[0], expectedType, typeSystem.SByte); case ILCode.Conv_U2: case ILCode.Conv_Ovf_U2: case ILCode.Conv_Ovf_U2_Un: - return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt16; + return HandleConversion(16, false, expr.Arguments[0], expectedType, typeSystem.Int16); case ILCode.Conv_U4: case ILCode.Conv_Ovf_U4: case ILCode.Conv_Ovf_U4_Un: - return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt32; + return HandleConversion(32, false, expr.Arguments[0], expectedType, typeSystem.Int32); case ILCode.Conv_U8: case ILCode.Conv_Ovf_U8: case ILCode.Conv_Ovf_U8_Un: - return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt64; + return HandleConversion(64, false, expr.Arguments[0], expectedType, typeSystem.UInt64); case ILCode.Conv_I: case ILCode.Conv_Ovf_I: case ILCode.Conv_Ovf_I_Un: - return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == true) ? expectedType : typeSystem.IntPtr; + return HandleConversion(nativeInt, true, expr.Arguments[0], expectedType, typeSystem.IntPtr); case ILCode.Conv_U: case ILCode.Conv_Ovf_U: case ILCode.Conv_Ovf_U_Un: - return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == false) ? expectedType : typeSystem.UIntPtr; + return HandleConversion(nativeInt, false, expr.Arguments[0], expectedType, typeSystem.UIntPtr); case ILCode.Conv_R4: return typeSystem.Single; case ILCode.Conv_R8: @@ -519,6 +511,24 @@ namespace ICSharpCode.Decompiler.ILAst } } + TypeReference HandleConversion(int targetBitSize, bool targetSigned, ILExpression arg, TypeReference expectedType, TypeReference targetType) + { + if (targetBitSize >= nativeInt && expectedType is PointerType) { + InferTypeForExpression(arg, expectedType); + return expectedType; + } + TypeReference argType = InferTypeForExpression(arg, null); + if (targetBitSize >= nativeInt && argType is ByReferenceType) { + // conv instructions on managed references mean that the GC should stop tracking them, so they become pointers: + PointerType ptrType = new PointerType(((ByReferenceType)argType).ElementType); + InferTypeForExpression(arg, ptrType); + return ptrType; + } else if (targetBitSize >= nativeInt && argType is PointerType) { + return argType; + } + return (GetInformationAmount(expectedType) == targetBitSize && IsSigned(expectedType) == targetSigned) ? expectedType : targetType; + } + static TypeReference GetFieldType(FieldReference fieldReference) { return SubstituteTypeArgs(UnpackModifiers(fieldReference.FieldType), fieldReference); diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 556c24fef..70b2eb55c 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -9,7 +9,7 @@ ICSharpCode.Decompiler.Tests v4.0 Properties - False + True False 4 false @@ -54,6 +54,7 @@ + diff --git a/ICSharpCode.Decompiler/Tests/UnsafeCode.cs b/ICSharpCode.Decompiler/Tests/UnsafeCode.cs new file mode 100644 index 000000000..e44bdc3ac --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/UnsafeCode.cs @@ -0,0 +1,29 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +public class UnsafeCode +{ + public unsafe long ConvertDoubleToLong(double d) + { + return *(long*)&d; + } + + public unsafe int* NullPointer { + get { + return null; + } + } + + public unsafe void PassRefParameterAsPointer(ref int p) + { + fixed (int* ptr = &p) + PassPointerAsRefParameter(ptr); + } + + public unsafe void PassPointerAsRefParameter(int* p) + { + PassRefParameterAsPointer(ref *p); + } +}