Browse Source

add TransformArrayInitializers

pull/728/head
Siegfried Pammer 10 years ago
parent
commit
bf990f8f41
  1. 3
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 17
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 35
      ICSharpCode.Decompiler/IL/ILReader.cs
  5. 156
      ICSharpCode.Decompiler/IL/Instructions.cs
  6. 101
      ICSharpCode.Decompiler/IL/Instructions.tt
  7. 41
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  8. 325
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs
  9. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  10. 9
      ICSharpCode.Decompiler/Tests/InitializerTests.cs
  11. 3
      ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs
  12. 10
      ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs

3
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -45,7 +45,8 @@ namespace ICSharpCode.Decompiler.CSharp
new LoopDetection(), new LoopDetection(),
new ControlFlowSimplification(), new ControlFlowSimplification(),
new ILInlining(), new ILInlining(),
new TransformingVisitor() new TransformingVisitor(),
new TransformArrayInitializers()
}; };
List<IAstTransform> astTransforms = new List<IAstTransform> { List<IAstTransform> astTransforms = new List<IAstTransform> {

17
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -135,15 +135,12 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitNewArr(NewArr inst) protected internal override TranslatedExpression VisitNewArr(NewArr inst)
{ {
var arg = Translate(inst.Size); var dimensions = inst.Indices.Count;
return new ArrayCreateExpression { var args = inst.Indices.Select(arg => Translate(arg)).ToArray();
Type = ConvertType(inst.Type), var expr = new ArrayCreateExpression { Type = ConvertType(inst.Type) };
Arguments = { expr.Arguments.AddRange(args.Select(arg => arg.Expression));
arg return expr.WithILInstruction(inst)
} .WithRR(new ArrayCreateResolveResult(new ArrayType(compilation, inst.Type, dimensions), args.Select(a => a.ResolveResult).ToList(), new ResolveResult[0]));
}
.WithILInstruction(inst)
.WithRR(new ArrayCreateResolveResult(new ArrayType(compilation, inst.Type, 1), new [] { arg.ResolveResult }, new ResolveResult[0]));
} }
protected internal override TranslatedExpression VisitLocAlloc(LocAlloc inst) protected internal override TranslatedExpression VisitLocAlloc(LocAlloc inst)
@ -696,7 +693,7 @@ namespace ICSharpCode.Decompiler.CSharp
var arrayType = arrayExpr.Type as ArrayType; var arrayType = arrayExpr.Type as ArrayType;
// TODO: what if arrayExpr is not an array type? // TODO: what if arrayExpr is not an array type?
// TODO: what if the type of the ldelema instruction does not match the array type? // TODO: what if the type of the ldelema instruction does not match the array type?
TranslatedExpression expr = new IndexerExpression(arrayExpr, Translate(inst.Index)) TranslatedExpression expr = new IndexerExpression(arrayExpr, inst.Indices.Select(i => Translate(i).Expression))
.WithILInstruction(inst).WithRR(new ResolveResult(arrayType != null ? arrayType.ElementType : SpecialType.UnknownType)); .WithILInstruction(inst).WithRR(new ResolveResult(arrayType != null ? arrayType.ElementType : SpecialType.UnknownType));
return new DirectionExpression(FieldDirection.Ref, expr) return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ResolveResult(new ByReferenceType(expr.Type))); .WithoutILInstruction().WithRR(new ResolveResult(new ByReferenceType(expr.Type)));

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -111,6 +111,7 @@
<Compile Include="IL\Transforms\ILInlining.cs" /> <Compile Include="IL\Transforms\ILInlining.cs" />
<Compile Include="IL\Transforms\LoopDetection.cs" /> <Compile Include="IL\Transforms\LoopDetection.cs" />
<Compile Include="IL\Transforms\OptimizingTransform.cs" /> <Compile Include="IL\Transforms\OptimizingTransform.cs" />
<Compile Include="IL\Transforms\TransformArrayInitializers.cs" />
<Compile Include="IL\Transforms\TransformingVisitor.cs" /> <Compile Include="IL\Transforms\TransformingVisitor.cs" />
<Compile Include="CecilExtensions.cs" /> <Compile Include="CecilExtensions.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" /> <Compile Include="Disassembler\DisassemblerHelpers.cs" />

35
ICSharpCode.Decompiler/IL/ILReader.cs

@ -669,7 +669,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldelem_Ref: case ILOpCode.Ldelem_Ref:
return LdElem(compilation.FindType(KnownTypeCode.Object)); return LdElem(compilation.FindType(KnownTypeCode.Object));
case ILOpCode.Ldelema: case ILOpCode.Ldelema:
return Push(new LdElema(index: Pop(), array: Pop(), type: ReadAndDecodeTypeReference())); return Push(new LdElema(indices: Pop(), array: Pop(), type: ReadAndDecodeTypeReference()));
case ILOpCode.Ldfld: case ILOpCode.Ldfld:
return Push(new LdFld(Pop(), ReadAndDecodeFieldReference())); return Push(new LdFld(Pop(), ReadAndDecodeFieldReference()));
case ILOpCode.Ldflda: case ILOpCode.Ldflda:
@ -858,7 +858,7 @@ namespace ICSharpCode.Decompiler.IL
private ILInstruction LdElem(IType type) private ILInstruction LdElem(IType type)
{ {
return Push(new LdObj(new LdElema(index: Pop(), array: Pop(), type: type), type)); return Push(new LdObj(new LdElema(indices: Pop(), array: Pop(), type: type), type));
} }
private ILInstruction StElem(IType type) private ILInstruction StElem(IType type)
@ -866,7 +866,7 @@ namespace ICSharpCode.Decompiler.IL
var value = Pop(); var value = Pop();
var index = Pop(); var index = Pop();
var array = Pop(); var array = Pop();
return new StObj(new LdElema(array, index, type), value, type); return new StObj(new LdElema(type, array, index), value, type);
} }
ILInstruction InitObj(ILInstruction target, IType type) ILInstruction InitObj(ILInstruction target, IType type)
@ -938,12 +938,31 @@ namespace ICSharpCode.Decompiler.IL
for (int i = arguments.Length - 1; i >= 0; i--) { for (int i = arguments.Length - 1; i >= 0; i--) {
arguments[i] = Pop(); arguments[i] = Pop();
} }
var call = CallInstruction.Create(opCode, method); ILInstruction result;
call.Arguments.AddRange(arguments); if (method.DeclaringType.Kind == TypeKind.Array) {
if (call.ResultType != StackType.Void) var type = ((ICSharpCode.NRefactory.TypeSystem.ArrayType)method.DeclaringType).ElementType;
return Push(call); if (opCode == OpCode.NewObj) {
result = new NewArr(type, arguments);
} else if (method.Name == "Set") {
var target = arguments[0].Clone();
var value = arguments.Last().Clone();
var indices = arguments.Skip(1).Take(arguments.Length - 2).ToArray();
result = new StObj(new LdElema(type, target, indices), value, type);
} else if (method.Name == "Get") {
var target = arguments[0].Clone();
var indices = arguments.Skip(1).ToArray();
result = new LdObj(new LdElema(type, target, indices), type);
} else
throw new NotImplementedException();
} else {
var call = CallInstruction.Create(opCode, method);
call.Arguments.AddRange(arguments);
result = call;
}
if (result.ResultType != StackType.Void)
return Push(result);
else else
return call; return result;
} }
static int GetPopCount(OpCode callCode, MethodReference methodReference) static int GetPopCount(OpCode callCode, MethodReference methodReference)

156
ICSharpCode.Decompiler/IL/Instructions.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
@ -366,6 +367,55 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
/// <summary>Instruction with a list of arguments.</summary>
public abstract partial class CallInstruction : ILInstruction
{
protected CallInstruction(OpCode opCode, params ILInstruction[] arguments) : base(opCode)
{
this.Arguments = new InstructionCollection<ILInstruction>(this, 0);
this.Arguments.AddRange(arguments);
}
public static readonly SlotInfo ArgumentsSlot = new SlotInfo("Arguments", canInlineInto: true);
public InstructionCollection<ILInstruction> Arguments { get; private set; }
protected sealed override int GetChildCount()
{
return Arguments.Count;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
default:
return this.Arguments[index - 0];
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
default:
this.Arguments[index - 0] = value;
break;
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
default:
return ArgumentsSlot;
}
}
public sealed override ILInstruction Clone()
{
var clone = (CallInstruction)ShallowClone();
clone.Arguments = new InstructionCollection<ILInstruction>(this, 0);
clone.Arguments.AddRange(this.Arguments.Select(arg => arg.Clone()));
return clone;
}
protected override InstructionFlags ComputeFlags()
{
return Arguments.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | InstructionFlags.MayThrow | InstructionFlags.SideEffect;
}
}
/// <summary>No operation. Takes 0 arguments and returns void.</summary> /// <summary>No operation. Takes 0 arguments and returns void.</summary>
public sealed partial class Nop : SimpleInstruction public sealed partial class Nop : SimpleInstruction
{ {
@ -2508,65 +2558,54 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Creates an array instance.</summary> /// <summary>Creates an array instance.</summary>
public sealed partial class NewArr : ILInstruction public sealed partial class NewArr : ILInstruction
{ {
public NewArr(IType type, ILInstruction size) : base(OpCode.NewArr) public NewArr(IType type, params ILInstruction[] indices) : base(OpCode.NewArr)
{ {
this.type = type; this.type = type;
this.Size = size; this.Indices = new InstructionCollection<ILInstruction>(this, 0);
this.Indices.AddRange(indices);
} }
readonly IType type; readonly IType type;
/// <summary>Returns the type operand.</summary> /// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } } public IType Type { get { return type; } }
public static readonly SlotInfo SizeSlot = new SlotInfo("Size", canInlineInto: true); public static readonly SlotInfo IndicesSlot = new SlotInfo("Indices", canInlineInto: true);
ILInstruction size; public InstructionCollection<ILInstruction> Indices { get; private set; }
public ILInstruction Size {
get { return this.size; }
set {
ValidateChild(value);
SetChildInstruction(ref this.size, value, 0);
}
}
protected sealed override int GetChildCount() protected sealed override int GetChildCount()
{ {
return 1; return Indices.Count;
} }
protected sealed override ILInstruction GetChild(int index) protected sealed override ILInstruction GetChild(int index)
{ {
switch (index) { switch (index) {
case 0:
return this.size;
default: default:
throw new IndexOutOfRangeException(); return this.Indices[index - 0];
} }
} }
protected sealed override void SetChild(int index, ILInstruction value) protected sealed override void SetChild(int index, ILInstruction value)
{ {
switch (index) { switch (index) {
case 0:
this.Size = value;
break;
default: default:
throw new IndexOutOfRangeException(); this.Indices[index - 0] = value;
break;
} }
} }
protected sealed override SlotInfo GetChildSlot(int index) protected sealed override SlotInfo GetChildSlot(int index)
{ {
switch (index) { switch (index) {
case 0:
return SizeSlot;
default: default:
throw new IndexOutOfRangeException(); return IndicesSlot;
} }
} }
public sealed override ILInstruction Clone() public sealed override ILInstruction Clone()
{ {
var clone = (NewArr)ShallowClone(); var clone = (NewArr)ShallowClone();
clone.Size = this.size.Clone(); clone.Indices = new InstructionCollection<ILInstruction>(this, 0);
clone.Indices.AddRange(this.Indices.Select(arg => arg.Clone()));
return clone; return clone;
} }
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return size.Flags | InstructionFlags.MayThrow; return Indices.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | InstructionFlags.MayThrow;
} }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
@ -2574,7 +2613,11 @@ namespace ICSharpCode.Decompiler.IL
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type); Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('('); output.Write('(');
this.size.WriteTo(output); bool first = true;
foreach (var indices in Indices) {
if (!first) output.Write(", "); else first = false;
indices.WriteTo(output);
}
output.Write(')'); output.Write(')');
} }
public override void AcceptVisitor(ILVisitor visitor) public override void AcceptVisitor(ILVisitor visitor)
@ -2762,12 +2805,16 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Load address of array element.</summary> /// <summary>Load address of array element.</summary>
public sealed partial class LdElema : ILInstruction public sealed partial class LdElema : ILInstruction
{ {
public LdElema(ILInstruction array, ILInstruction index, IType type) : base(OpCode.LdElema) public LdElema(IType type, ILInstruction array, params ILInstruction[] indices) : base(OpCode.LdElema)
{ {
this.Array = array;
this.Index = index;
this.type = type; this.type = type;
this.Array = array;
this.Indices = new InstructionCollection<ILInstruction>(this, 1);
this.Indices.AddRange(indices);
} }
readonly IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public static readonly SlotInfo ArraySlot = new SlotInfo("Array", canInlineInto: true); public static readonly SlotInfo ArraySlot = new SlotInfo("Array", canInlineInto: true);
ILInstruction array; ILInstruction array;
public ILInstruction Array { public ILInstruction Array {
@ -2777,28 +2824,19 @@ namespace ICSharpCode.Decompiler.IL
SetChildInstruction(ref this.array, value, 0); SetChildInstruction(ref this.array, value, 0);
} }
} }
public static readonly SlotInfo IndexSlot = new SlotInfo("Index", canInlineInto: true); public static readonly SlotInfo IndicesSlot = new SlotInfo("Indices", canInlineInto: true);
ILInstruction index; public InstructionCollection<ILInstruction> Indices { get; private set; }
public ILInstruction Index {
get { return this.index; }
set {
ValidateChild(value);
SetChildInstruction(ref this.index, value, 1);
}
}
protected sealed override int GetChildCount() protected sealed override int GetChildCount()
{ {
return 2; return 1 + Indices.Count;
} }
protected sealed override ILInstruction GetChild(int index) protected sealed override ILInstruction GetChild(int index)
{ {
switch (index) { switch (index) {
case 0: case 0:
return this.array; return this.array;
case 1:
return this.index;
default: default:
throw new IndexOutOfRangeException(); return this.Indices[index - 1];
} }
} }
protected sealed override void SetChild(int index, ILInstruction value) protected sealed override void SetChild(int index, ILInstruction value)
@ -2807,11 +2845,9 @@ namespace ICSharpCode.Decompiler.IL
case 0: case 0:
this.Array = value; this.Array = value;
break; break;
case 1:
this.Index = value;
break;
default: default:
throw new IndexOutOfRangeException(); this.Indices[index - 1] = value;
break;
} }
} }
protected sealed override SlotInfo GetChildSlot(int index) protected sealed override SlotInfo GetChildSlot(int index)
@ -2819,28 +2855,24 @@ namespace ICSharpCode.Decompiler.IL
switch (index) { switch (index) {
case 0: case 0:
return ArraySlot; return ArraySlot;
case 1:
return IndexSlot;
default: default:
throw new IndexOutOfRangeException(); return IndicesSlot;
} }
} }
public sealed override ILInstruction Clone() public sealed override ILInstruction Clone()
{ {
var clone = (LdElema)ShallowClone(); var clone = (LdElema)ShallowClone();
clone.Array = this.array.Clone(); clone.Array = this.array.Clone();
clone.Index = this.index.Clone(); clone.Indices = new InstructionCollection<ILInstruction>(this, 1);
clone.Indices.AddRange(this.Indices.Select(arg => arg.Clone()));
return clone; return clone;
} }
readonly IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public override StackType ResultType { get { return StackType.Ref; } } public override StackType ResultType { get { return StackType.Ref; } }
/// <summary>Gets whether the 'readonly' prefix was applied to this instruction.</summary> /// <summary>Gets whether the 'readonly' prefix was applied to this instruction.</summary>
public bool IsReadOnly { get; set; } public bool IsReadOnly { get; set; }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return array.Flags | index.Flags | InstructionFlags.MayThrow; return array.Flags | Indices.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | InstructionFlags.MayThrow;
} }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
@ -2851,8 +2883,10 @@ namespace ICSharpCode.Decompiler.IL
Disassembler.DisassemblerHelpers.WriteOperand(output, type); Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('('); output.Write('(');
this.array.WriteTo(output); this.array.WriteTo(output);
output.Write(", "); foreach (var indices in Indices) {
this.index.WriteTo(output); output.Write(", ");
indices.WriteTo(output);
}
output.Write(')'); output.Write(')');
} }
public override void AcceptVisitor(ILVisitor visitor) public override void AcceptVisitor(ILVisitor visitor)
@ -4140,16 +4174,14 @@ namespace ICSharpCode.Decompiler.IL
type = default(IType); type = default(IType);
return false; return false;
} }
public bool MatchNewArr(out IType type, out ILInstruction size) public bool MatchNewArr(out IType type)
{ {
var inst = this as NewArr; var inst = this as NewArr;
if (inst != null) { if (inst != null) {
type = inst.Type; type = inst.Type;
size = inst.Size;
return true; return true;
} }
type = default(IType); type = default(IType);
size = default(ILInstruction);
return false; return false;
} }
public bool MatchDefaultValue(out IType type) public bool MatchDefaultValue(out IType type)
@ -4200,18 +4232,16 @@ namespace ICSharpCode.Decompiler.IL
array = default(ILInstruction); array = default(ILInstruction);
return false; return false;
} }
public bool MatchLdElema(out ILInstruction array, out ILInstruction index, out IType type) public bool MatchLdElema(out IType type, out ILInstruction array)
{ {
var inst = this as LdElema; var inst = this as LdElema;
if (inst != null) { if (inst != null) {
array = inst.Array;
index = inst.Index;
type = inst.Type; type = inst.Type;
array = inst.Array;
return true; return true;
} }
array = default(ILInstruction);
index = default(ILInstruction);
type = default(IType); type = default(IType);
array = default(ILInstruction);
return false; return false;
} }
} }

101
ICSharpCode.Decompiler/IL/Instructions.tt

@ -30,6 +30,9 @@
AbstractBaseClass, CustomArguments("argument")), AbstractBaseClass, CustomArguments("argument")),
new OpCode("BinaryInstruction", "Instruction with two arguments: Left and Right", new OpCode("BinaryInstruction", "Instruction with two arguments: Left and Right",
AbstractBaseClass, CustomArguments("left", "right")), AbstractBaseClass, CustomArguments("left", "right")),
new OpCode("CallInstruction", "Instruction with a list of arguments.",
AbstractBaseClass, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}),
CustomWriteTo, MayThrow, SideEffect),
}; };
OpCode[] opCodes = { OpCode[] opCodes = {
@ -175,7 +178,7 @@
new OpCode("newobj", "Creates an object instance and calls the constructor.", new OpCode("newobj", "Creates an object instance and calls the constructor.",
CustomClassName("NewObj"), Call, ResultType("Method.DeclaringType.GetStackType()")), CustomClassName("NewObj"), Call, ResultType("Method.DeclaringType.GetStackType()")),
new OpCode("newarr", "Creates an array instance.", new OpCode("newarr", "Creates an array instance.",
CustomClassName("NewArr"), HasTypeOperand, CustomArguments("size"), MayThrow, ResultType("O")), CustomClassName("NewArr"), HasTypeOperand, CustomChildren(new [] { new ArgumentInfo("indices") { IsCollection = true } }, true), MayThrow, ResultType("O")),
new OpCode("default.value", "Returns the default value for a type.", new OpCode("default.value", "Returns the default value for a type.",
NoArguments, HasTypeOperand, ResultType("type.GetStackType()")), NoArguments, HasTypeOperand, ResultType("type.GetStackType()")),
new OpCode("throw", "Throws an exception.", new OpCode("throw", "Throws an exception.",
@ -188,13 +191,14 @@
new OpCode("ldlen", "Returns the length of an array as 'native unsigned int'.", new OpCode("ldlen", "Returns the length of an array as 'native unsigned int'.",
CustomClassName("LdLen"), CustomArguments("array"), MayThrow, ResultType("I")), CustomClassName("LdLen"), CustomArguments("array"), MayThrow, ResultType("I")),
new OpCode("ldelema", "Load address of array element.", new OpCode("ldelema", "Load address of array element.",
CustomClassName("LdElema"), CustomArguments("array", "index"), HasTypeOperand, CustomClassName("LdElema"), HasTypeOperand, CustomChildren(new [] { new ArgumentInfo("array"), new ArgumentInfo("indices") { IsCollection = true } }, true),
MayThrow, ResultType("Ref"), SupportsReadonlyPrefix) MayThrow, ResultType("Ref"), SupportsReadonlyPrefix)
}; };
#> #>
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
@ -571,6 +575,7 @@ namespace ICSharpCode.Decompiler.IL
public readonly string Name; public readonly string Name;
public readonly string SlotName; public readonly string SlotName;
public bool IsCollection;
public bool CanInlineInto; public bool CanInlineInto;
public ChildInfo(string name) public ChildInfo(string name)
@ -605,32 +610,61 @@ namespace ICSharpCode.Decompiler.IL
opCode.GenerateWriteTo = true; opCode.GenerateWriteTo = true;
opCode.WriteArguments.Add("output.Write('(');"); opCode.WriteArguments.Add("output.Write('(');");
StringBuilder transformChildren = new StringBuilder(); StringBuilder transformChildren = new StringBuilder();
ChildInfo collection = null;
int childCount = children.Length;
for (int i = 0; i < children.Length; i++) { for (int i = 0; i < children.Length; i++) {
string arg = children[i].Name; string arg = children[i].Name;
string argProp = children[i].PropertyName; string argProp = children[i].PropertyName;
opCode.Flags.Add(arg + ".Flags"); if (children[i].IsCollection && i + 1 == children.Length) {
opCode.ConstructorParameters.Add("ILInstruction " + arg); collection = children[i];
opCode.ConstructorBody.Add("this." + argProp + " = " + arg + ";"); childCount = children.Length - 1;
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILInstruction", Name = arg, FieldName = argProp }); opCode.Flags.Add(argProp + ".Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags)");
if (i > 0) opCode.ConstructorParameters.Add("params ILInstruction[] " + arg);
opCode.WriteArguments.Add("output.Write(\", \");"); opCode.ConstructorBody.Add("this." + argProp + " = new InstructionCollection<ILInstruction>(this, " + i + ");");
opCode.WriteArguments.Add("this." + arg + ".WriteTo(output);"); opCode.ConstructorBody.Add("this." + argProp + ".AddRange(" + arg + ");");
opCode.Members.Add("public static readonly SlotInfo " + children[i].SlotName + " = " + children[i].GetSlotInit() + ";"); if (i == 0)
opCode.Members.Add("ILInstruction " + arg + ";"); opCode.WriteArguments.Add("bool first = true;");
opCode.Members.Add("public ILInstruction " + argProp + " {" + Environment.NewLine opCode.WriteArguments.Add("foreach (var " + arg + " in " + argProp + ") {");
+ "\tget { return this." + arg + "; }" + Environment.NewLine if (i > 0)
+ "\tset {" + Environment.NewLine opCode.WriteArguments.Add("\toutput.Write(\", \");");
+ "\t\tValidateChild(value);" + Environment.NewLine else
+ "\t\tSetChildInstruction(ref this." + arg + ", value, " + i + ");" + Environment.NewLine opCode.WriteArguments.Add("\tif (!first) output.Write(\", \"); else first = false;");
+ "\t}" + Environment.NewLine opCode.WriteArguments.Add("\t" + arg + ".WriteTo(output);");
+ "}"); opCode.WriteArguments.Add("}");
opCode.Members.Add("public static readonly SlotInfo " + children[i].SlotName + " = " + children[i].GetSlotInit() + ";");
opCode.Members.Add("public InstructionCollection<ILInstruction> " + argProp + " { get; private set; }");
} else {
opCode.Flags.Add(arg + ".Flags");
opCode.ConstructorParameters.Add("ILInstruction " + arg);
opCode.ConstructorBody.Add("this." + argProp + " = " + arg + ";");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "ILInstruction", Name = arg, FieldName = argProp });
if (i > 0)
opCode.WriteArguments.Add("output.Write(\", \");");
opCode.WriteArguments.Add("this." + arg + ".WriteTo(output);");
opCode.Members.Add("public static readonly SlotInfo " + children[i].SlotName + " = " + children[i].GetSlotInit() + ";");
opCode.Members.Add("ILInstruction " + arg + ";");
opCode.Members.Add("public ILInstruction " + argProp + " {" + Environment.NewLine
+ "\tget { return this." + arg + "; }" + Environment.NewLine
+ "\tset {" + Environment.NewLine
+ "\t\tValidateChild(value);" + Environment.NewLine
+ "\t\tSetChildInstruction(ref this." + arg + ", value, " + i + ");" + Environment.NewLine
+ "\t}" + Environment.NewLine
+ "}");
}
} }
opCode.WriteArguments.Add("output.Write(')');"); opCode.WriteArguments.Add("output.Write(')');");
StringBuilder b; StringBuilder b;
b = new StringBuilder(); b = new StringBuilder();
b.AppendLine("protected sealed override int GetChildCount()"); b.AppendLine("protected sealed override int GetChildCount()");
b.AppendLine("{"); b.AppendLine("{");
b.AppendLine("\treturn " + children.Length + ";"); b.Append("\treturn ");
if (childCount > 0 || collection == null)
b.Append(childCount);
if (collection != null) {
if (childCount > 0) b.Append(" + ");
b.Append(collection.PropertyName + ".Count");
}
b.AppendLine(";");
b.Append("}"); b.Append("}");
opCode.Members.Add(b.ToString()); opCode.Members.Add(b.ToString());
@ -638,12 +672,15 @@ namespace ICSharpCode.Decompiler.IL
b.AppendLine("protected sealed override ILInstruction GetChild(int index)"); b.AppendLine("protected sealed override ILInstruction GetChild(int index)");
b.AppendLine("{"); b.AppendLine("{");
b.AppendLine("\tswitch (index) {"); b.AppendLine("\tswitch (index) {");
for (int i = 0; i < children.Length; i++) { for (int i = 0; i < childCount; i++) {
b.AppendLine("\t\tcase " + i + ":"); b.AppendLine("\t\tcase " + i + ":");
b.AppendLine("\t\t\treturn this." + children[i].Name + ";"); b.AppendLine("\t\t\treturn this." + children[i].Name + ";");
} }
b.AppendLine("\t\tdefault:"); b.AppendLine("\t\tdefault:");
b.AppendLine("\t\t\tthrow new IndexOutOfRangeException();"); if (collection == null)
b.AppendLine("\t\t\tthrow new IndexOutOfRangeException();");
else
b.AppendLine("\t\t\treturn this." + collection.PropertyName + "[index - " + childCount + "];");
b.AppendLine("\t}"); b.AppendLine("\t}");
b.Append("}"); b.Append("}");
opCode.Members.Add(b.ToString()); opCode.Members.Add(b.ToString());
@ -652,13 +689,18 @@ namespace ICSharpCode.Decompiler.IL
b.AppendLine("protected sealed override void SetChild(int index, ILInstruction value)"); b.AppendLine("protected sealed override void SetChild(int index, ILInstruction value)");
b.AppendLine("{"); b.AppendLine("{");
b.AppendLine("\tswitch (index) {"); b.AppendLine("\tswitch (index) {");
for (int i = 0; i < children.Length; i++) { for (int i = 0; i < childCount; i++) {
b.AppendLine("\t\tcase " + i + ":"); b.AppendLine("\t\tcase " + i + ":");
b.AppendLine("\t\t\tthis." + children[i].PropertyName + " = value;"); b.AppendLine("\t\t\tthis." + children[i].PropertyName + " = value;");
b.AppendLine("\t\t\tbreak;"); b.AppendLine("\t\t\tbreak;");
} }
b.AppendLine("\t\tdefault:"); b.AppendLine("\t\tdefault:");
b.AppendLine("\t\t\tthrow new IndexOutOfRangeException();"); if (collection == null)
b.AppendLine("\t\t\tthrow new IndexOutOfRangeException();");
else {
b.AppendLine("\t\t\tthis." + collection.PropertyName + "[index - " + childCount + "] = value;");
b.AppendLine("\t\t\tbreak;");
}
b.AppendLine("\t}"); b.AppendLine("\t}");
b.Append("}"); b.Append("}");
opCode.Members.Add(b.ToString()); opCode.Members.Add(b.ToString());
@ -667,12 +709,15 @@ namespace ICSharpCode.Decompiler.IL
b.AppendLine("protected sealed override SlotInfo GetChildSlot(int index)"); b.AppendLine("protected sealed override SlotInfo GetChildSlot(int index)");
b.AppendLine("{"); b.AppendLine("{");
b.AppendLine("\tswitch (index) {"); b.AppendLine("\tswitch (index) {");
for (int i = 0; i < children.Length; i++) { for (int i = 0; i < childCount; i++) {
b.AppendLine("\t\tcase " + i + ":"); b.AppendLine("\t\tcase " + i + ":");
b.AppendLine("\t\t\treturn " + children[i].SlotName + ";"); b.AppendLine("\t\t\treturn " + children[i].SlotName + ";");
} }
b.AppendLine("\t\tdefault:"); b.AppendLine("\t\tdefault:");
b.AppendLine("\t\t\tthrow new IndexOutOfRangeException();"); if (collection == null)
b.AppendLine("\t\t\tthrow new IndexOutOfRangeException();");
else
b.AppendLine("\t\t\treturn " + collection.SlotName + ";");
b.AppendLine("\t}"); b.AppendLine("\t}");
b.Append("}"); b.Append("}");
opCode.Members.Add(b.ToString()); opCode.Members.Add(b.ToString());
@ -682,7 +727,11 @@ namespace ICSharpCode.Decompiler.IL
b.AppendLine("{"); b.AppendLine("{");
b.AppendLine("\tvar clone = (" + opCode.Name + ")ShallowClone();"); b.AppendLine("\tvar clone = (" + opCode.Name + ")ShallowClone();");
for (int i = 0; i < children.Length; i++) { for (int i = 0; i < children.Length; i++) {
b.AppendLine("\tclone." + children[i].PropertyName + " = this." + children[i].Name + ".Clone();"); if (children[i].IsCollection) {
b.AppendLine("\tclone." + children[i].PropertyName + " = new InstructionCollection<ILInstruction>(this, " + i + ");");
b.AppendLine("\tclone." + children[i].PropertyName + ".AddRange(this." + children[i].PropertyName + ".Select(arg => arg.Clone()));");
} else
b.AppendLine("\tclone." + children[i].PropertyName + " = this." + children[i].Name + ".Clone();");
} }
b.AppendLine("\treturn clone;"); b.AppendLine("\treturn clone;");
b.Append("}"); b.Append("}");

41
ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs

@ -27,7 +27,7 @@ using ICSharpCode.Decompiler.Disassembler;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
public abstract class CallInstruction : ILInstruction public abstract partial class CallInstruction : ILInstruction
{ {
public static readonly SlotInfo ArgumentSlot = new SlotInfo("Argument", canInlineInto: true, isCollection: true); public static readonly SlotInfo ArgumentSlot = new SlotInfo("Argument", canInlineInto: true, isCollection: true);
@ -45,7 +45,6 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
public readonly InstructionCollection<ILInstruction> Arguments;
public readonly IMethod Method; public readonly IMethod Method;
/// <summary> /// <summary>
@ -66,16 +65,6 @@ namespace ICSharpCode.Decompiler.IL
this.Arguments = new InstructionCollection<ILInstruction>(this, 0); this.Arguments = new InstructionCollection<ILInstruction>(this, 0);
} }
public sealed override ILInstruction Clone()
{
var clone = Create(this.OpCode, this.Method);
clone.Arguments.AddRange(this.Arguments.Select(arg => arg.Clone()));
clone.ILRange = this.ILRange;
clone.IsTail = this.IsTail;
clone.ConstrainedTo = this.ConstrainedTo;
return clone;
}
public override StackType ResultType { public override StackType ResultType {
get { get {
if (OpCode == OpCode.NewObj) if (OpCode == OpCode.NewObj)
@ -85,34 +74,6 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
protected sealed override int GetChildCount()
{
return Arguments.Count;
}
protected sealed override ILInstruction GetChild(int index)
{
return Arguments[index];
}
protected sealed override void SetChild(int index, ILInstruction value)
{
Arguments[index] = value;
}
protected override SlotInfo GetChildSlot(int index)
{
return ArgumentSlot;
}
protected override InstructionFlags ComputeFlags()
{
var flags = InstructionFlags.MayThrow | InstructionFlags.SideEffect;
foreach (var op in Arguments)
flags |= op.Flags;
return flags;
}
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
if (ConstrainedTo != null) { if (ConstrainedTo != null) {

325
ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

@ -0,0 +1,325 @@
// Copyright (c) 2015 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler.IL
{
public class TransformArrayInitializers : IILTransform
{
ILTransformContext context;
void IILTransform.Run(ILFunction function, ILTransformContext context)
{
this.context = context;
foreach (var block in function.Descendants.OfType<Block>()) {
for (int i = block.Instructions.Count - 1; i >= 0; i--) {
try {
if (!DoTransform(block, i))
DoTransformMultiDim(block, i);
} catch (Exception ex) {
Console.WriteLine(ex);
throw;
}
}
}
}
bool DoTransform(Block body, int pos)
{
if (pos >= body.Instructions.Count - 2)
return false;
ILInstruction inst = body.Instructions[pos];
ILVariable v;
ILInstruction newarrExpr;
IType elementType;
int[] arrayLength;
if (inst.MatchStLoc(out v, out newarrExpr) && MatchNewArr(newarrExpr, out elementType, out arrayLength)) {
ILInstruction[] values;
int initArrayPos;
if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out values, out initArrayPos)) {
var block = BlockFromInitializer(v, elementType, arrayLength, values);
body.Instructions[pos].ReplaceWith(new StLoc(v, block));
body.Instructions.RemoveAt(initArrayPos);
new ILInlining().InlineIfPossible(body, ref pos);
return true;
}
// Put in a limit so that we don't consume too much memory if the code allocates a huge array
// and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler!
// const int maxConsecutiveDefaultValueExpressions = 300;
// var operands = new List<ILInstruction>();
// int numberOfInstructionsToRemove = 0;
// for (int j = pos + 1; j < body.Instructions.Count; j++) {
// var nextExpr = body.Instructions[j] as Void;
// int arrayPos;
// if (nextExpr != null && nextExpr is a.IsStoreToArray() &&
// nextExpr.Arguments[0].Match(ILCode.Ldloc, out v3) &&
// v == v3 &&
// nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) &&
// arrayPos >= operands.Count &&
// arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions &&
// !nextExpr.Arguments[2].ContainsReferenceTo(v3))
// {
// while (operands.Count < arrayPos)
// operands.Add(new ILExpression(ILCode.DefaultValue, elementType));
// operands.Add(nextExpr.Arguments[2]);
// numberOfInstructionsToRemove++;
// } else {
// break;
// }
// }
}
return false;
}
bool DoTransformMultiDim(Block body, int pos)
{
if (pos >= body.Instructions.Count - 2)
return false;
ILVariable v;
ILInstruction newarrExpr;
IType arrayType;
int[] length;
ILInstruction instr = body.Instructions[pos];
if (instr.MatchStLoc(out v, out newarrExpr) && MatchNewArr(newarrExpr, out arrayType, out length)) {
ILInstruction[] values;
int initArrayPos;
if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, arrayType, length, out values, out initArrayPos)) {
var block = BlockFromInitializer(v, arrayType, length, values);
body.Instructions[pos].ReplaceWith(new StLoc(v, block));
body.Instructions.RemoveAt(initArrayPos);
new ILInlining().InlineIfPossible(body, ref pos);
return true;
}
}
return false;
}
Block BlockFromInitializer(ILVariable v, IType elementType, int[] arrayLength, ILInstruction[] values)
{
var block = new Block();
block.Instructions.Add(new StLoc(v, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray())));
int step = arrayLength.Length + 1;
for (int i = 0; i < values.Length / step; i++) {
// values array is filled backwards
var value = values[step * i];
var indices = new List<ILInstruction>();
for (int j = step - 1; j >= 1; j--) {
indices.Add(values[step * i + j]);
}
block.Instructions.Add(StElem(new LdLoc(v), indices.ToArray(), value, elementType));
}
block.FinalInstruction = new LdLoc(v);
return block;
}
static bool CompareTypes(IType a, IType b)
{
IType type1 = DummyTypeParameter.NormalizeAllTypeParameters(a);
IType type2 = DummyTypeParameter.NormalizeAllTypeParameters(b);
return type1.Equals(type2);
}
static bool CompareSignatures(IList<IParameter> parameters, IList<IParameter> otherParameters)
{
if (otherParameters.Count != parameters.Count)
return false;
for (int i = 0; i < otherParameters.Count; i++) {
if (!CompareTypes(otherParameters[i].Type, parameters[i].Type))
return false;
}
return true;
}
bool MatchNewArr(ILInstruction instruction, out IType arrayType, out int[] length)
{
NewArr newArr = instruction as NewArr;
length = null;
arrayType = null;
if (newArr == null)
return false;
arrayType = newArr.Type;
var args = newArr.Indices;
length = new int[args.Count];
for (int i = 0; i < args.Count; i++) {
int value;
if (!args[i].MatchLdcI4(out value) || value <= 0) return false;
length[i] = value;
}
return true;
}
bool MatchInitializeArrayCall(ILInstruction instruction, out IMethod method, out ILVariable array, out Mono.Cecil.FieldReference field)
{
method = null;
array = null;
field = null;
Call call = instruction as Call;
if (call == null || call.Arguments.Count != 2)
return false;
method = call.Method;
if (method.DeclaringTypeDefinition == null || method.DeclaringTypeDefinition.FullName != "System.Runtime.CompilerServices.RuntimeHelpers")
return false;
if (method.Name != "InitializeArray")
return false;
if (!call.Arguments[0].MatchLdLoc(out array))
return false;
IMember member;
if (!call.Arguments[1].MatchLdMemberToken(out member))
return false;
field = context.TypeSystem.GetCecil(member) as Mono.Cecil.FieldReference;
if (field == null)
return false;
return true;
}
bool ForwardScanInitializeArrayRuntimeHelper(Block body, int pos, ILVariable array, IType arrayType, int[] arrayLength, out ILInstruction[] values, out int foundPos)
{
ILVariable v2;
IMethod method;
Mono.Cecil.FieldReference field;
if (MatchInitializeArrayCall(body.Instructions[pos], out method, out v2, out field) && array == v2) {
var fieldDef = field.ResolveWithinSameModule();
if (fieldDef != null && fieldDef.InitialValue != null) {
var valuesList = new List<ILInstruction>();
if (DecodeArrayInitializer(arrayType, array, fieldDef.InitialValue, arrayLength, valuesList)) {
values = valuesList.ToArray();
foundPos = pos;
return true;
}
}
}
values = null;
foundPos = -1;
return false;
}
static bool DecodeArrayInitializer(IType type, ILVariable array, byte[] initialValue, int[] arrayLength, List<ILInstruction> output)
{
TypeCode typeCode = ReflectionHelper.GetTypeCode(type);
switch (typeCode) {
case TypeCode.Boolean:
case TypeCode.Byte:
return DecodeArrayInitializer(initialValue, array, arrayLength, output, typeCode, type, (d, i) => (int)d[i]);
case TypeCode.SByte:
return DecodeArrayInitializer(initialValue, array, arrayLength, output, typeCode, type, (d, i) => (int)unchecked((sbyte)d[i]));
case TypeCode.Int16:
return DecodeArrayInitializer(initialValue, array, arrayLength, output, typeCode, type, (d, i) => (int)BitConverter.ToInt16(d, i));
case TypeCode.Char:
case TypeCode.UInt16:
return DecodeArrayInitializer(initialValue, array, arrayLength, output, typeCode, type, (d, i) => (int)BitConverter.ToUInt16(d, i));
case TypeCode.Int32:
case TypeCode.UInt32:
return DecodeArrayInitializer(initialValue, array, arrayLength, output, typeCode, type, BitConverter.ToInt32);
case TypeCode.Int64:
case TypeCode.UInt64:
return DecodeArrayInitializer(initialValue, array, arrayLength, output, typeCode, type, BitConverter.ToInt64);
case TypeCode.Single:
return DecodeArrayInitializer(initialValue, array, arrayLength, output, typeCode, type, BitConverter.ToSingle);
case TypeCode.Double:
return DecodeArrayInitializer(initialValue, array, arrayLength, output, typeCode, type, BitConverter.ToDouble);
case TypeCode.Object:
var typeDef = type.GetDefinition();
if (typeDef != null && typeDef.Kind == TypeKind.Enum)
return DecodeArrayInitializer(typeDef.EnumUnderlyingType, array, initialValue, arrayLength, output);
return false;
default:
return false;
}
}
static bool DecodeArrayInitializer<T>(byte[] initialValue, ILVariable array, int[] arrayLength, List<ILInstruction> output, TypeCode elementType, IType type, Func<byte[], int, T> decoder)
{
int elementSize = ElementSizeOf(elementType);
var totalLength = arrayLength.Aggregate(1, (t, l) => t * l);
if (initialValue.Length < (totalLength * elementSize))
return false;
for (int i = 0; i < totalLength; i++) {
object value = (object)decoder(initialValue, i * elementSize);
if (!0.Equals(value)) {
output.Add(LoadInstructionFor(elementType, value));
int next = i;
for (int j = arrayLength.Length - 1; j >= 0; j--) {
output.Add(new LdcI4(next % arrayLength[j]));
next = next / arrayLength[j];
}
}
}
return true;
}
static ILInstruction LoadInstructionFor(TypeCode elementType, object value)
{
switch (elementType) {
case TypeCode.Boolean:
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Char:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
return new LdcI4((int)value);
case TypeCode.Int64:
case TypeCode.UInt64:
return new LdcI8((long)value);
case TypeCode.Single:
case TypeCode.Double:
return new LdcF((double)value);
default:
throw new ArgumentOutOfRangeException("elementType");
}
}
static ILInstruction StElem(ILInstruction array, ILInstruction[] indices, ILInstruction value, IType type)
{
return new StObj(new LdElema(type, array, indices), value, type);
}
static int ElementSizeOf(TypeCode elementType)
{
switch (elementType) {
case TypeCode.Boolean:
case TypeCode.Byte:
case TypeCode.SByte:
return 1;
case TypeCode.Char:
case TypeCode.Int16:
case TypeCode.UInt16:
return 2;
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Single:
return 4;
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Double:
return 8;
default:
throw new ArgumentOutOfRangeException("elementType");
}
}
}
}

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

@ -101,6 +101,7 @@
<Compile Include="Helpers\Tester.cs" /> <Compile Include="Helpers\Tester.cs" />
<Compile Include="Helpers\TypeSystemHelper.cs" /> <Compile Include="Helpers\TypeSystemHelper.cs" />
<Compile Include="ILTransforms\InliningTests.cs" /> <Compile Include="ILTransforms\InliningTests.cs" />
<Compile Include="InitializerTests.cs" />
<Compile Include="Loops.cs" /> <Compile Include="Loops.cs" />
<Compile Include="TestCases\CompoundAssignment.cs" /> <Compile Include="TestCases\CompoundAssignment.cs" />
<Compile Include="TestCases\ControlFlow.cs" /> <Compile Include="TestCases\ControlFlow.cs" />

9
ICSharpCode.Decompiler/Tests/InitializerTests.cs

@ -21,6 +21,15 @@ using System.Collections.Generic;
public class InitializerTests public class InitializerTests
{ {
public static int Main()
{
int[,] test = new int[2,3];
test[0,0] = 0;
test[0,1] = 1;
test[0,2] = 2;
return test.Length + test[0, 0] + test[0, 2];
}
private enum MyEnum private enum MyEnum
{ {
a, a,

3
ICSharpCode.Decompiler/TypeSystem/IDecompilerTypeSystem.cs

@ -28,6 +28,9 @@ namespace ICSharpCode.Decompiler
{ {
ICompilation Compilation { get; } ICompilation Compilation { get; }
TypeDefinition GetCecil(ITypeDefinition typeDefinition);
MemberReference GetCecil(IMember member);
IType Resolve(TypeReference typeReference); IType Resolve(TypeReference typeReference);
IField Resolve(FieldReference fieldReference); IField Resolve(FieldReference fieldReference);
IMethod Resolve(MethodReference methodReference); IMethod Resolve(MethodReference methodReference);

10
ICSharpCode.Decompiler/TypeSystem/SpecializingDecompilerTypeSystem.cs

@ -63,5 +63,15 @@ namespace ICSharpCode.Decompiler
method = (IMethod)method.Specialize(substitution); method = (IMethod)method.Specialize(substitution);
return method; return method;
} }
public Mono.Cecil.TypeDefinition GetCecil(ITypeDefinition typeDefinition)
{
return context.GetCecil(typeDefinition);
}
public Mono.Cecil.MemberReference GetCecil(IMember member)
{
return context.GetCecil(member);
}
} }
} }

Loading…
Cancel
Save