diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
index 3bb3746fe..30867662e 100644
--- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
@@ -108,10 +108,13 @@ namespace ICSharpCode.Decompiler.CSharp
return new ExpressionWithResolveResult(expr, exprRR);
}
- public TranslatedExpression Translate(ILInstruction inst)
+ public TranslatedExpression Translate(ILInstruction inst, IType typeHint = null)
{
Debug.Assert(inst != null);
- var cexpr = inst.AcceptVisitor(this, new TranslationContext());
+ TranslationContext context = new TranslationContext {
+ TypeHint = typeHint ?? SpecialType.UnknownType
+ };
+ var cexpr = inst.AcceptVisitor(this, context);
#if DEBUG
if (inst.ResultType != StackType.Void && cexpr.Type.Kind != TypeKind.Unknown) {
if (inst.ResultType.IsIntegerType()) {
@@ -127,7 +130,7 @@ namespace ICSharpCode.Decompiler.CSharp
public TranslatedExpression TranslateCondition(ILInstruction condition)
{
- var expr = Translate(condition);
+ var expr = Translate(condition, compilation.FindType(KnownTypeCode.Boolean));
return expr.ConvertToBoolean(this);
}
@@ -206,11 +209,51 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLocAlloc(LocAlloc inst, TranslationContext context)
{
- var byteType = compilation.FindType(KnownTypeCode.Byte);
+ IType elementType;
+ TranslatedExpression countExpression = TranslatePointerArgument(inst.Argument, context, out elementType);
+ countExpression = countExpression.ConvertTo(compilation.FindType(KnownTypeCode.Int32), this);
return new StackAllocExpression {
- Type = ConvertType(byteType),
- CountExpression = Translate(inst.Argument)
- }.WithILInstruction(inst).WithRR(new ResolveResult(new PointerType(byteType)));
+ Type = ConvertType(elementType ?? compilation.FindType(KnownTypeCode.Byte)),
+ CountExpression = countExpression
+ }.WithILInstruction(inst).WithRR(new ResolveResult(new PointerType(elementType)));
+ }
+
+ ///
+ /// Translate the argument of an operation that deals with pointers:
+ /// * undoes the implicit multiplication with `sizeof(elementType)` and returns `elementType`
+ /// * on failure, translates the whole expression and returns `elementType = null`.
+ ///
+ TranslatedExpression TranslatePointerArgument(ILInstruction countExpr, TranslationContext context, out IType elementType)
+ {
+ ILInstruction left;
+ ILInstruction right;
+ if (countExpr.MatchBinaryNumericInstruction(BinaryNumericOperator.Mul, out left, out right)
+ && right.UnwrapConv(ConversionKind.SignExtend).UnwrapConv(ConversionKind.ZeroExtend).MatchSizeOf(out elementType))
+ {
+ return Translate(left);
+ }
+
+ var pointerTypeHint = context.TypeHint as PointerType;
+ if (pointerTypeHint == null) {
+ elementType = null;
+ return Translate(countExpr);
+ }
+ ResolveResult sizeofRR = resolver.ResolveSizeOf(pointerTypeHint.ElementType);
+ if (!(sizeofRR.IsCompileTimeConstant && sizeofRR.ConstantValue is int)) {
+ elementType = null;
+ return Translate(countExpr);
+ }
+ int typeSize = (int)sizeofRR.ConstantValue;
+
+ if (countExpr.MatchBinaryNumericInstruction(BinaryNumericOperator.Mul, out left, out right)
+ && right.UnwrapConv(ConversionKind.SignExtend).UnwrapConv(ConversionKind.ZeroExtend).MatchLdcI4(typeSize))
+ {
+ elementType = pointerTypeHint.ElementType;
+ return Translate(left);
+ }
+
+ elementType = null;
+ return Translate(countExpr);
}
protected internal override TranslatedExpression VisitLdcI4(LdcI4 inst, TranslationContext context)
@@ -346,7 +389,7 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitStLoc(StLoc inst, TranslationContext context)
{
- var translatedValue = Translate(inst.Value);
+ var translatedValue = Translate(inst.Value, typeHint: inst.Variable.Type);
if (inst.Variable.Kind == VariableKind.StackSlot && inst.Variable.IsSingleDefinition
&& inst.Variable.StackType == translatedValue.Type.GetStackType()
&& translatedValue.Type.Kind != TypeKind.Null && !loadedVariablesSet.Contains(inst.Variable)) {
@@ -1167,7 +1210,6 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitStObj(StObj inst, TranslationContext context)
{
var target = Translate(inst.Target);
- var value = Translate(inst.Value);
TranslatedExpression result;
if (target.Expression is DirectionExpression && TypeUtils.IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
// we can deference the managed reference by stripping away the 'ref'
@@ -1181,6 +1223,7 @@ namespace ICSharpCode.Decompiler.CSharp
.WithoutILInstruction()
.WithRR(new ResolveResult(((TypeWithElementType)target.Type).ElementType));
}
+ var value = Translate(inst.Value, typeHint: result.Type);
return Assignment(result, value).WithILInstruction(inst);
}
@@ -1261,7 +1304,7 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitBox(Box inst, TranslationContext context)
{
var obj = compilation.FindType(KnownTypeCode.Object);
- var arg = Translate(inst.Argument).ConvertTo(inst.Type, this);
+ 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));
diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs
index 0ccd6fdb9..01514aa0b 100644
--- a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs
+++ b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs
@@ -99,6 +99,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
pre.CopyAnnotationsFrom(memberReferenceExpression);
memberReferenceExpression.ReplaceWith(pre);
}
+ var rr = memberReferenceExpression.GetResolveResult();
+ if (rr != null && rr.Type is PointerType)
+ return true;
return result;
}
diff --git a/ICSharpCode.Decompiler/CSharp/TranslationContext.cs b/ICSharpCode.Decompiler/CSharp/TranslationContext.cs
index 58d901ffc..87a8ee3f9 100644
--- a/ICSharpCode.Decompiler/CSharp/TranslationContext.cs
+++ b/ICSharpCode.Decompiler/CSharp/TranslationContext.cs
@@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
+using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp
{
@@ -25,6 +26,10 @@ namespace ICSharpCode.Decompiler.CSharp
///
public struct TranslationContext
{
-
+ ///
+ /// The expected type during ILAst->C# translation; or SpecialType.Unknown
+ /// if no specific type is expected.
+ ///
+ public IType TypeHint;
}
}
diff --git a/ICSharpCode.Decompiler/Tests/CorrectnessTestRunner.cs b/ICSharpCode.Decompiler/Tests/CorrectnessTestRunner.cs
index 24f40be17..8deb5d3f6 100644
--- a/ICSharpCode.Decompiler/Tests/CorrectnessTestRunner.cs
+++ b/ICSharpCode.Decompiler/Tests/CorrectnessTestRunner.cs
@@ -130,7 +130,7 @@ namespace ICSharpCode.Decompiler.Tests
TestAssembleDecompileCompileOutput("BitNot.il", CompilerOptions.UseDebug | CompilerOptions.Force32Bit, AssemblerOptions.Force32Bit);
}
- [Test, Ignore("Fixed statements are broken")]
+ [Test, Ignore("Pointer reference expression is not supported")]
public void UnsafeCode()
{
TestCompileDecompileCompileOutputAll("UnsafeCode.cs");
diff --git a/ICSharpCode.Decompiler/Tests/TestCases/Correctness/UnsafeCode.cs b/ICSharpCode.Decompiler/Tests/TestCases/Correctness/UnsafeCode.cs
index 79d393c1b..477136371 100644
--- a/ICSharpCode.Decompiler/Tests/TestCases/Correctness/UnsafeCode.cs
+++ b/ICSharpCode.Decompiler/Tests/TestCases/Correctness/UnsafeCode.cs
@@ -20,6 +20,12 @@ using System;
public class UnsafeCode
{
+ struct SimpleStruct
+ {
+ public int X;
+ public double Y;
+ }
+
static void Main()
{
// TODO: test behavior, or convert this into a pretty-test
@@ -145,6 +151,7 @@ public class UnsafeCode
public unsafe string StackAlloc(int count)
{
char* ptr = stackalloc char[count];
+ char* ptr2 = stackalloc char[100];
for (int i = 0; i < count; i++)
{
ptr[i] = (char)i;
@@ -152,6 +159,13 @@ public class UnsafeCode
return this.PointerReferenceExpression((double*)ptr);
}
+ public unsafe string StackAllocStruct(int count)
+ {
+ SimpleStruct* s = stackalloc SimpleStruct[checked(count * 2)];
+ SimpleStruct* p = stackalloc SimpleStruct[10];
+ return this.PointerReferenceExpression(&s->Y);
+ }
+
public unsafe int* PointerArithmetic(int* p)
{
return p + 2;
diff --git a/NRefactory b/NRefactory
index 19497cfae..5ca6d4172 160000
--- a/NRefactory
+++ b/NRefactory
@@ -1 +1 @@
-Subproject commit 19497cfae13c3dcebed7dfeb1cba549e4c2deded
+Subproject commit 5ca6d4172c8540d01b65d120f46db416d29740e3