Browse Source

Add support for unsafe code. Closes #48.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
7b2c444181
  1. 2
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 49
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 50
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs
  4. 1
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  5. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  6. 135
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  7. 72
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  8. 3
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  9. 29
      ICSharpCode.Decompiler/Tests/UnsafeCode.cs

2
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -1131,6 +1131,8 @@ namespace ICSharpCode.Decompiler.Ast
return new Ast.PrimitiveExpression(false); return new Ast.PrimitiveExpression(false);
else if (TypeAnalysis.IsBoolean(type) && val == 1) else if (TypeAnalysis.IsBoolean(type) && val == 1)
return new Ast.PrimitiveExpression(true); return new Ast.PrimitiveExpression(true);
else if (val == 0 && type is PointerType)
return new Ast.NullReferenceExpression();
if (type != null) if (type != null)
{ // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs)
TypeDefinition enumDefinition = type.Resolve(); TypeDefinition enumDefinition = type.Resolve();

49
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -318,9 +318,9 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Conv_U2: case ILCode.Conv_U2:
case ILCode.Conv_U4: case ILCode.Conv_U4:
case ILCode.Conv_U8: 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 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_R4: return arg1.CastTo(typeof(float));
case ILCode.Conv_R8: return arg1.CastTo(typeof(double)); case ILCode.Conv_R8: return arg1.CastTo(typeof(double));
case ILCode.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO 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); case ILCode.Unbox: return InlineAssembly(byteCode, args);
#endregion #endregion
#region Indirect #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.Ldind_Ref:
case ILCode.Ldobj: case ILCode.Ldobj:
if (args[0] is DirectionExpression) if (arg1 is DirectionExpression)
return ((DirectionExpression)args[0]).Expression.Detach(); return ((DirectionExpression)arg1).Expression.Detach();
else else
return InlineAssembly(byteCode, args); return new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1);
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:
case ILCode.Stind_Ref: case ILCode.Stind_Ref:
case ILCode.Stobj: case ILCode.Stobj:
if (args[0] is DirectionExpression) if (arg1 is DirectionExpression)
return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), args[1]); return new AssignmentExpression(((DirectionExpression)arg1).Expression.Detach(), arg2);
else else
return InlineAssembly(byteCode, args); return new AssignmentExpression(new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1), arg2);
#endregion #endregion
case ILCode.Arglist: return InlineAssembly(byteCode, args); case ILCode.Arglist: return InlineAssembly(byteCode, args);
case ILCode.Break: return InlineAssembly(byteCode, args); case ILCode.Break: return InlineAssembly(byteCode, args);
@ -769,6 +752,22 @@ namespace ICSharpCode.Decompiler.Ast
{ {
if (reqType == null || actualType == reqType) { if (reqType == null || actualType == reqType) {
return expr; 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 { } else {
bool actualIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(actualType); bool actualIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(actualType);
bool requiredIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(reqType); bool requiredIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(reqType);

50
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<object, bool>, 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);
}
}
}

1
ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs

@ -22,6 +22,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new PatternStatementTransform(context), new PatternStatementTransform(context),
new ConvertConstructorCallIntoInitializer(), new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators(), new ReplaceMethodCallsWithOperators(),
new IntroduceUnsafeModifier(),
}; };
} }

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -60,6 +60,7 @@
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" /> <Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" /> <Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\DelegateConstruction.cs" /> <Compile Include="Ast\Transforms\DelegateConstruction.cs" />
<Compile Include="Ast\Transforms\IntroduceUnsafeModifier.cs" />
<Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" /> <Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" />
<Compile Include="Ast\Transforms\PushNegation.cs" /> <Compile Include="Ast\Transforms\PushNegation.cs" />
<Compile Include="Ast\Transforms\TransformationPipeline.cs" /> <Compile Include="Ast\Transforms\TransformationPipeline.cs" />

135
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -102,24 +102,24 @@ namespace ICSharpCode.Decompiler.ILAst
__Ble_Un, __Ble_Un,
__Blt_Un, __Blt_Un,
Switch, Switch,
Ldind_I1, __Ldind_I1,
Ldind_U1, __Ldind_U1,
Ldind_I2, __Ldind_I2,
Ldind_U2, __Ldind_U2,
Ldind_I4, __Ldind_I4,
Ldind_U4, __Ldind_U4,
Ldind_I8, __Ldind_I8,
Ldind_I, __Ldind_I,
Ldind_R4, __Ldind_R4,
Ldind_R8, __Ldind_R8,
Ldind_Ref, Ldind_Ref,
Stind_Ref, Stind_Ref,
Stind_I1, __Stind_I1,
Stind_I2, __Stind_I2,
Stind_I4, __Stind_I4,
Stind_I8, __Stind_I8,
Stind_R4, __Stind_R4,
Stind_R8, __Stind_R8,
Add, Add,
Sub, Sub,
Mul, Mul,
@ -222,7 +222,7 @@ namespace ICSharpCode.Decompiler.ILAst
Endfinally, Endfinally,
Leave, Leave,
__Leave_S, __Leave_S,
Stind_I, __Stind_I,
Conv_U, Conv_U,
Arglist, Arglist,
Ceq, Ceq,
@ -375,49 +375,64 @@ namespace ICSharpCode.Decompiler.ILAst
public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody) public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody)
{ {
switch (code) { switch (code) {
case ILCode.__Ldarg_0: code = ILCode.__Ldarg; operand = methodBody.GetParameter(0); 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_1: code = ILCode.__Ldarg; operand = methodBody.GetParameter(1); break;
case ILCode.__Ldarg_2: code = ILCode.__Ldarg; operand = methodBody.GetParameter(2); 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.__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_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break;
case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; 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_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break;
case ILCode.__Ldloc_3: code = ILCode.Ldloc; operand = methodBody.Variables[3]; 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_0: code = ILCode.Stloc; operand = methodBody.Variables[0]; break;
case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; 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_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break;
case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break; case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break;
case ILCode.__Ldarg_S: code = ILCode.__Ldarg; break; case ILCode.__Ldarg_S: code = ILCode.__Ldarg; break;
case ILCode.__Ldarga_S: code = ILCode.__Ldarga; break; case ILCode.__Ldarga_S: code = ILCode.__Ldarga; break;
case ILCode.__Starg_S: code = ILCode.__Starg; break; case ILCode.__Starg_S: code = ILCode.__Starg; break;
case ILCode.__Ldloc_S: code = ILCode.Ldloc; break; case ILCode.__Ldloc_S: code = ILCode.Ldloc; break;
case ILCode.__Ldloca_S: code = ILCode.Ldloca; break; case ILCode.__Ldloca_S: code = ILCode.Ldloca; break;
case ILCode.__Stloc_S: code = ILCode.Stloc; 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_M1: code = ILCode.Ldc_I4; operand = -1; break;
case ILCode.__Ldc_I4_0: code = ILCode.Ldc_I4; operand = 0; 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_1: code = ILCode.Ldc_I4; operand = 1; break;
case ILCode.__Ldc_I4_2: code = ILCode.Ldc_I4; operand = 2; 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_3: code = ILCode.Ldc_I4; operand = 3; break;
case ILCode.__Ldc_I4_4: code = ILCode.Ldc_I4; operand = 4; 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_5: code = ILCode.Ldc_I4; operand = 5; break;
case ILCode.__Ldc_I4_6: code = ILCode.Ldc_I4; operand = 6; 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_7: code = ILCode.Ldc_I4; operand = 7; break;
case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; 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.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break;
case ILCode.__Br_S: code = ILCode.Br; break; case ILCode.__Br_S: code = ILCode.Br; break;
case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break; case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break;
case ILCode.__Brtrue_S: code = ILCode.Brtrue; break; case ILCode.__Brtrue_S: code = ILCode.Brtrue; break;
case ILCode.__Beq_S: code = ILCode.__Beq; break; case ILCode.__Beq_S: code = ILCode.__Beq; break;
case ILCode.__Bge_S: code = ILCode.__Bge; break; case ILCode.__Bge_S: code = ILCode.__Bge; break;
case ILCode.__Bgt_S: code = ILCode.__Bgt; break; case ILCode.__Bgt_S: code = ILCode.__Bgt; break;
case ILCode.__Ble_S: code = ILCode.__Ble; break; case ILCode.__Ble_S: code = ILCode.__Ble; break;
case ILCode.__Blt_S: code = ILCode.__Blt; break; case ILCode.__Blt_S: code = ILCode.__Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break; case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break; case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break; case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break; case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break; case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break;
case ILCode.__Leave_S: code = ILCode.Leave; 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;
} }
} }

72
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -108,7 +108,10 @@ namespace ICSharpCode.Decompiler.ILAst
/// <returns>The inferred type</returns> /// <returns>The inferred type</returns>
TypeReference InferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false) 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) if (forceInferChildren || expr.InferredType == null)
expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren); expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren);
return expr.InferredType; return expr.InferredType;
@ -235,25 +238,8 @@ namespace ICSharpCode.Decompiler.ILAst
return GetFieldType((FieldReference)expr.Operand); return GetFieldType((FieldReference)expr.Operand);
#endregion #endregion
#region Reference/Pointer instructions #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: case ILCode.Ldind_Ref:
return UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); 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: case ILCode.Stind_Ref:
if (forceInferChildren) { if (forceInferChildren) {
TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
@ -261,12 +247,18 @@ namespace ICSharpCode.Decompiler.ILAst
} }
return null; return null;
case ILCode.Ldobj: 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; return (TypeReference)expr.Operand;
case ILCode.Stobj: case ILCode.Stobj:
if (forceInferChildren) { 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); InferTypeForExpression(expr.Arguments[1], (TypeReference)expr.Operand);
} }
return null; return (TypeReference)expr.Operand;
case ILCode.Initobj: case ILCode.Initobj:
return null; return null;
case ILCode.DefaultValue: case ILCode.DefaultValue:
@ -326,9 +318,9 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_I4: case ILCode.Ldc_I4:
if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1)) if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1))
return typeSystem.Boolean; return typeSystem.Boolean;
return IsIntegerOrEnum(expectedType) ? expectedType : typeSystem.Int32; return (IsIntegerOrEnum(expectedType) || expectedType is PointerType) ? expectedType : typeSystem.Int32;
case ILCode.Ldc_I8: case ILCode.Ldc_I8:
return (IsIntegerOrEnum(expectedType)) ? expectedType : typeSystem.Int64; return (IsIntegerOrEnum(expectedType) || expectedType is PointerType) ? expectedType : typeSystem.Int64;
case ILCode.Ldc_R4: case ILCode.Ldc_R4:
return typeSystem.Single; return typeSystem.Single;
case ILCode.Ldc_R8: case ILCode.Ldc_R8:
@ -411,43 +403,43 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Conv_I1: case ILCode.Conv_I1:
case ILCode.Conv_Ovf_I1: case ILCode.Conv_Ovf_I1:
case ILCode.Conv_Ovf_I1_Un: 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_I2:
case ILCode.Conv_Ovf_I2: case ILCode.Conv_Ovf_I2:
case ILCode.Conv_Ovf_I2_Un: 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_I4:
case ILCode.Conv_Ovf_I4: case ILCode.Conv_Ovf_I4:
case ILCode.Conv_Ovf_I4_Un: 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_I8:
case ILCode.Conv_Ovf_I8: case ILCode.Conv_Ovf_I8:
case ILCode.Conv_Ovf_I8_Un: 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_U1:
case ILCode.Conv_Ovf_U1: case ILCode.Conv_Ovf_U1:
case ILCode.Conv_Ovf_U1_Un: 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_U2:
case ILCode.Conv_Ovf_U2: case ILCode.Conv_Ovf_U2:
case ILCode.Conv_Ovf_U2_Un: 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_U4:
case ILCode.Conv_Ovf_U4: case ILCode.Conv_Ovf_U4:
case ILCode.Conv_Ovf_U4_Un: 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_U8:
case ILCode.Conv_Ovf_U8: case ILCode.Conv_Ovf_U8:
case ILCode.Conv_Ovf_U8_Un: 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_I:
case ILCode.Conv_Ovf_I: case ILCode.Conv_Ovf_I:
case ILCode.Conv_Ovf_I_Un: 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_U:
case ILCode.Conv_Ovf_U: case ILCode.Conv_Ovf_U:
case ILCode.Conv_Ovf_U_Un: 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: case ILCode.Conv_R4:
return typeSystem.Single; return typeSystem.Single;
case ILCode.Conv_R8: 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) static TypeReference GetFieldType(FieldReference fieldReference)
{ {
return SubstituteTypeArgs(UnpackModifiers(fieldReference.FieldType), fieldReference); return SubstituteTypeArgs(UnpackModifiers(fieldReference.FieldType), fieldReference);

3
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -9,7 +9,7 @@
<AssemblyName>ICSharpCode.Decompiler.Tests</AssemblyName> <AssemblyName>ICSharpCode.Decompiler.Tests</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib> <NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
@ -54,6 +54,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Switch.cs" /> <Compile Include="Switch.cs" />
<Compile Include="UnsafeCode.cs" />
<Compile Include="YieldReturn.cs" /> <Compile Include="YieldReturn.cs" />
<None Include="Types\S_EnumSamples.cs" /> <None Include="Types\S_EnumSamples.cs" />
<None Include="CustomAttributes\S_AssemblyCustomAttribute.cs" /> <None Include="CustomAttributes\S_AssemblyCustomAttribute.cs" />

29
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);
}
}
Loading…
Cancel
Save