Browse Source

Add support for array initializers.

pull/70/head
Daniel Grunwald 14 years ago
parent
commit
7de3cf9bc4
  1. 8
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 61
      ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs
  4. 4
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  5. 21
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  6. 161
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  7. 102
      ICSharpCode.Decompiler/ILAst/Pattern.cs
  8. 6
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  9. 36
      ICSharpCode.Decompiler/Tests/ArrayInitializers.cs
  10. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  11. 4
      ILSpy/ILAstLanguage.cs

8
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -334,6 +334,14 @@ namespace Decompiler
ace.Arguments.Add(arg1); ace.Arguments.Add(arg1);
return ace; return ace;
} }
case (Code)ILCode.InitArray:
{
var ace = new Ast.ArrayCreateExpression();
ace.Type = operandAsTypeRef;
ace.Initializer = new ArrayInitializerExpression();
ace.Initializer.Elements.AddRange(args);
return ace;
}
case Code.Ldlen: case Code.Ldlen:
return arg1.Member("Length"); return arg1.Member("Length");
case Code.Ldelem_I: case Code.Ldelem_I:

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -89,10 +89,12 @@
<Compile Include="FlowAnalysis\SsaVariable.cs" /> <Compile Include="FlowAnalysis\SsaVariable.cs" />
<Compile Include="FlowAnalysis\TransformToSsa.cs" /> <Compile Include="FlowAnalysis\TransformToSsa.cs" />
<Compile Include="GraphVizGraph.cs" /> <Compile Include="GraphVizGraph.cs" />
<Compile Include="ILAst\ArrayInitializers.cs" />
<Compile Include="ILAst\ILAstBuilder.cs" /> <Compile Include="ILAst\ILAstBuilder.cs" />
<Compile Include="ILAst\ILAstOptimizer.cs" /> <Compile Include="ILAst\ILAstOptimizer.cs" />
<Compile Include="ILAst\ILAstTypes.cs" /> <Compile Include="ILAst\ILAstTypes.cs" />
<Compile Include="ILAst\ILCodes.cs" /> <Compile Include="ILAst\ILCodes.cs" />
<Compile Include="ILAst\Pattern.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" /> <Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ITextOutput.cs" /> <Compile Include="ITextOutput.cs" />
<Compile Include="Options.cs" /> <Compile Include="Options.cs" />

61
ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs

@ -0,0 +1,61 @@
// 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 System.Linq;
using Mono.Cecil;
namespace Decompiler
{
/// <summary>
/// IL AST transformation that introduces array initializers.
/// </summary>
public class ArrayInitializers
{
public static void Transform(ILBlock method)
{
var newArrPattern = new StoreToGenerated(new ILExpression(
ILCode.Dup, null,
new ILExpression(ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand))
));
var arg1 = new StoreToGenerated(new LoadFromVariable(newArrPattern));
var arg2 = new StoreToGenerated(new LoadFromVariable(newArrPattern));
var initializeArrayPattern = new ILCall(
"System.Runtime.CompilerServices.RuntimeHelpers", "InitializeArray",
new LoadFromVariable(arg1), new ILExpression(ILCode.Ldtoken, ILExpression.AnyOperand));
foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = block.Body.Count - 4; i >= 0; i--) {
if (!newArrPattern.Match(block.Body[i]))
continue;
ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0].Arguments[0];
int arrayLength = (int)newArrInst.Arguments[0].Operand;
if (!arg1.Match(block.Body[i + 1]))
continue;
if (!arg2.Match(block.Body[i + 2]))
continue;
if (initializeArrayPattern.Match(block.Body[i + 3])) {
FieldDefinition field = ((ILExpression)block.Body[i+3]).Arguments[1].Operand as FieldDefinition;
if (field == null || field.InitialValue == null)
continue;
switch (TypeAnalysis.GetTypeCode(newArrInst.Operand as TypeReference)) {
case TypeCode.Int32:
case TypeCode.UInt32:
if (field.InitialValue.Length == arrayLength * 4) {
ILExpression[] newArr = new ILExpression[arrayLength];
for (int j = 0; j < newArr.Length; j++) {
newArr[j] = new ILExpression(ILCode.Ldc_I4, BitConverter.ToInt32(field.InitialValue, j * 4));
}
block.Body[i] = new ILExpression(ILCode.Stloc, arg1.LastVariable, new ILExpression(ILCode.InitArray, newArrInst.Operand, newArr));
block.Body.RemoveRange(i + 1, 3);
}
continue;
default:
continue;
}
}
}
}
}
}
}

4
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -17,6 +17,7 @@ namespace Decompiler.ControlFlow
FlattenNestedMovableBlocks, FlattenNestedMovableBlocks,
SimpleGotoRemoval, SimpleGotoRemoval,
RemoveDeadLabels, RemoveDeadLabels,
HandleArrayInitializers,
TypeInference, TypeInference,
None None
} }
@ -64,6 +65,9 @@ namespace Decompiler.ControlFlow
if (abortBeforeStep == ILAstOptimizationStep.RemoveDeadLabels) return; if (abortBeforeStep == ILAstOptimizationStep.RemoveDeadLabels) return;
RemoveDeadLabels(method); RemoveDeadLabels(method);
if (abortBeforeStep == ILAstOptimizationStep.HandleArrayInitializers) return;
ArrayInitializers.Transform(method);
if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return; if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
TypeAnalysis.Run(context, method); TypeAnalysis.Run(context, method);
} }

21
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -207,6 +207,8 @@ namespace Decompiler
public TypeReference ExpectedType { get; set; } public TypeReference ExpectedType { get; set; }
public TypeReference InferredType { get; set; } public TypeReference InferredType { get; set; }
public static readonly object AnyOperand = new object();
public ILExpression(ILCode code, object operand, params ILExpression[] args) public ILExpression(ILCode code, object operand, params ILExpression[] args)
{ {
this.Code = code; this.Code = code;
@ -269,6 +271,25 @@ namespace Decompiler
return ranges; return ranges;
} }
public virtual bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
return expr != null && this.Code == expr.Code
&& (this.Operand == AnyOperand || object.Equals(this.Operand, expr.Operand))
&& Match(this.Arguments, expr.Arguments);
}
protected static bool Match(IList<ILExpression> a, IList<ILExpression> b)
{
if (a.Count != b.Count)
return false;
for (int i = 0; i < a.Count; i++) {
if (!a[i].Match(b[i]))
return false;
}
return true;
}
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) { if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) {

161
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -257,7 +257,10 @@ namespace Decompiler
Ldexception, // Operand holds the CatchType for catch handler, null for filter Ldexception, // Operand holds the CatchType for catch handler, null for filter
LogicNot, LogicNot,
BrLogicAnd, BrLogicAnd,
BrLogicOr BrLogicOr,
InitArray, // Array Initializer
Pattern // used for ILAst pattern nodes
} }
public static class ILCodeUtil public static class ILCodeUtil
@ -288,26 +291,26 @@ namespace Decompiler
public static int? GetPopCount(this Instruction inst) public static int? GetPopCount(this Instruction inst)
{ {
switch(inst.OpCode.StackBehaviourPop) { switch(inst.OpCode.StackBehaviourPop) {
case StackBehaviour.Pop0: return 0; case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1; case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1; case StackBehaviour.Popi: return 1;
case StackBehaviour.Popref: return 1; case StackBehaviour.Popref: return 1;
case StackBehaviour.Pop1_pop1: return 2; case StackBehaviour.Pop1_pop1: return 2;
case StackBehaviour.Popi_pop1: return 2; case StackBehaviour.Popi_pop1: return 2;
case StackBehaviour.Popi_popi: return 2; case StackBehaviour.Popi_popi: return 2;
case StackBehaviour.Popi_popi8: return 2; case StackBehaviour.Popi_popi8: return 2;
case StackBehaviour.Popi_popr4: return 2; case StackBehaviour.Popi_popr4: return 2;
case StackBehaviour.Popi_popr8: return 2; case StackBehaviour.Popi_popr8: return 2;
case StackBehaviour.Popref_pop1: return 2; case StackBehaviour.Popref_pop1: return 2;
case StackBehaviour.Popref_popi: return 2; case StackBehaviour.Popref_popi: return 2;
case StackBehaviour.Popi_popi_popi: return 3; case StackBehaviour.Popi_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi: return 3; case StackBehaviour.Popref_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi8: return 3; case StackBehaviour.Popref_popi_popi8: return 3;
case StackBehaviour.Popref_popi_popr4: return 3; case StackBehaviour.Popref_popi_popr4: return 3;
case StackBehaviour.Popref_popi_popr8: return 3; case StackBehaviour.Popref_popi_popr8: return 3;
case StackBehaviour.Popref_popi_popref: return 3; case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: return null; case StackBehaviour.PopAll: return null;
case StackBehaviour.Varpop: case StackBehaviour.Varpop:
switch(inst.OpCode.Code) { switch(inst.OpCode.Code) {
case Code.Call: case Code.Call:
case Code.Callvirt: case Code.Callvirt:
@ -317,28 +320,28 @@ namespace Decompiler
} else { } else {
return cecilMethod.Parameters.Count; return cecilMethod.Parameters.Count;
} }
case Code.Calli: throw new NotImplementedException(); case Code.Calli: throw new NotImplementedException();
case Code.Ret: return null; case Code.Ret: return null;
case Code.Newobj: case Code.Newobj:
MethodReference ctorMethod = ((MethodReference)inst.Operand); MethodReference ctorMethod = ((MethodReference)inst.Operand);
return ctorMethod.Parameters.Count; return ctorMethod.Parameters.Count;
default: throw new Exception("Unknown Varpop opcode"); default: throw new Exception("Unknown Varpop opcode");
} }
default: throw new Exception("Unknown pop behaviour: " + inst.OpCode.StackBehaviourPop); default: throw new Exception("Unknown pop behaviour: " + inst.OpCode.StackBehaviourPop);
} }
} }
public static int GetPushCount(this Instruction inst) public static int GetPushCount(this Instruction inst)
{ {
switch(inst.OpCode.StackBehaviourPush) { switch(inst.OpCode.StackBehaviourPush) {
case StackBehaviour.Push0: return 0; case StackBehaviour.Push0: return 0;
case StackBehaviour.Push1: return 1; case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2; case StackBehaviour.Push1_push1: return 2;
case StackBehaviour.Pushi: return 1; case StackBehaviour.Pushi: return 1;
case StackBehaviour.Pushi8: return 1; case StackBehaviour.Pushi8: return 1;
case StackBehaviour.Pushr4: return 1; case StackBehaviour.Pushr4: return 1;
case StackBehaviour.Pushr8: return 1; case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1; case StackBehaviour.Pushref: return 1;
case StackBehaviour.Varpush: // Happens only for calls case StackBehaviour.Varpush: // Happens only for calls
switch(inst.OpCode.Code) { switch(inst.OpCode.Code) {
case Code.Call: case Code.Call:
@ -349,59 +352,59 @@ namespace Decompiler
} else { } else {
return 1; return 1;
} }
case Code.Calli: throw new NotImplementedException(); case Code.Calli: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode"); default: throw new Exception("Unknown Varpush opcode");
} }
default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush); default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush);
} }
} }
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;
} }
} }

102
ICSharpCode.Decompiler/ILAst/Pattern.cs

@ -0,0 +1,102 @@
// 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 Mono.Cecil;
namespace Decompiler
{
public interface IVariablePattern
{
bool MatchVariable(ILVariable v);
}
public class StoreToGenerated : ILExpression, IVariablePattern
{
public ILExpression LastMatch;
public ILVariable LastVariable {
get {
return LastMatch != null ? LastMatch.Operand as ILVariable : null;
}
}
public StoreToGenerated(ILExpression arg) : base(ILCode.Pattern, null, arg)
{
}
public override bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
if (expr != null && expr.Code == ILCode.Stloc && ((ILVariable)expr.Operand).IsGenerated && Match(this.Arguments, expr.Arguments)) {
this.LastMatch = expr;
return true;
} else {
return false;
}
}
bool IVariablePattern.MatchVariable(ILVariable v)
{
return v == LastMatch.Operand;
}
}
public class LoadFromVariable : ILExpression
{
IVariablePattern v;
public LoadFromVariable(IVariablePattern v) : base(ILCode.Pattern, null)
{
this.v = v;
}
public override bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
return expr != null && expr.Code == ILCode.Ldloc && v.MatchVariable(expr.Operand as ILVariable);
}
}
public class AnyILExpression : ILExpression
{
public ILExpression LastMatch;
public AnyILExpression() : base(ILCode.Pattern, null)
{
}
public override bool Match(ILNode other)
{
if (other is ILExpression) {
LastMatch = (ILExpression)other;
return true;
} else {
return false;
}
}
}
public class ILCall : ILExpression
{
string fullClassName;
string methodName;
public ILCall(string fullClassName, string methodName, params ILExpression[] args) : base(ILCode.Pattern, null, args)
{
this.fullClassName = fullClassName;
this.methodName = methodName;
}
public override bool Match(ILNode other)
{
ILExpression expr = other as ILExpression;
if (expr != null && expr.Code == ILCode.Call) {
MethodReference r = (MethodReference)expr.Operand;
if (r.Name == methodName && r.DeclaringType.FullName == fullClassName)
return Match(this.Arguments, expr.Arguments);
}
return false;
}
}
}

6
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -310,6 +310,12 @@ namespace Decompiler
if (forceInferChildren) if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Int32); InferTypeForExpression(expr.Arguments.Single(), typeSystem.Int32);
return new ArrayType((TypeReference)expr.Operand); return new ArrayType((TypeReference)expr.Operand);
case ILCode.InitArray:
if (forceInferChildren) {
foreach (ILExpression arg in expr.Arguments)
InferTypeForExpression(arg, (TypeReference)expr.Operand);
}
return new ArrayType((TypeReference)expr.Operand);
case ILCode.Ldlen: case ILCode.Ldlen:
return typeSystem.Int32; return typeSystem.Int32;
case ILCode.Ldelem_U1: case ILCode.Ldelem_U1:

36
ICSharpCode.Decompiler/Tests/ArrayInitializers.cs

@ -0,0 +1,36 @@
// 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 ArrayInitializers
{
// Helper methods used to ensure array initializers used within expressions work correctly
static void X(object a, object b)
{
}
static object Y()
{
return null;
}
public static void Array1()
{
X(Y(), new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
}
public static void Array2(int a, int b, int c)
{
X(Y(), new int[] { a, b, c });
}
public static void NestedArray(int a, int b, int c)
{
X(Y(), new int[][] {
new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
new int[] { a, b, c },
new int[] { 1, 2, 3, 4, 5, 6 }
});
}
}

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -48,6 +48,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ArrayInitializers.cs" />
<Compile Include="DelegateConstruction.cs" /> <Compile Include="DelegateConstruction.cs" />
<Compile Include="ExceptionHandling.cs" /> <Compile Include="ExceptionHandling.cs" />
<Compile Include="MultidimensionalArray.cs" /> <Compile Include="MultidimensionalArray.cs" />

4
ILSpy/ILAstLanguage.cs

@ -47,6 +47,10 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
if (!method.HasBody) {
return;
}
ILAstBuilder astBuilder = new ILAstBuilder(); ILAstBuilder astBuilder = new ILAstBuilder();
ILBlock ilMethod = new ILBlock(); ILBlock ilMethod = new ILBlock();
ilMethod.Body = astBuilder.Build(method, inlineVariables); ilMethod.Body = astBuilder.Build(method, inlineVariables);

Loading…
Cancel
Save