diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 3a00ea9ee..574b18ddc 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -234,9 +234,8 @@ namespace ICSharpCode.Decompiler.CSharp ConvertedExpression Assignment(ConvertedExpression left, ConvertedExpression right) { - return new ConvertedExpression( - new AssignmentExpression(left.Expression, right.ConvertTo(left.Type, this)), - left.Type); + return new AssignmentExpression(left.Expression, right.ConvertTo(left.Type, this)) + .WithTypeInfo(left.Type); } protected internal override ConvertedExpression VisitAdd(Add inst) diff --git a/ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs b/ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs index 04487ec2b..e057b18ca 100644 --- a/ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs +++ b/ICSharpCode.Decompiler/CSharp/NRefactoryExtensions.cs @@ -19,11 +19,17 @@ using System; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.PatternMatching; +using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.Decompiler.CSharp { static class NRefactoryExtensions { + public static ConvertedExpression WithTypeInfo(this Expression expr, IType type) + { + return new ConvertedExpression(expr, type); + } + public static T WithAnnotation(this T node, object annotation) where T : AstNode { if (annotation != null) diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index c75d9b2e8..9f59ee57e 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -150,7 +150,10 @@ namespace ICSharpCode.Decompiler.CSharp { BlockStatement blockStatement = new BlockStatement(); foreach (var block in container.Blocks) { - blockStatement.Add(new LabelStatement { Label = block.Label }); + if (block.IncomingEdgeCount > 1 || block != container.EntryPoint) { + // If there are any incoming branches to this block, add a label: + blockStatement.Add(new LabelStatement { Label = block.Label }); + } foreach (var inst in block.Instructions) { blockStatement.Add(Convert(inst)); } diff --git a/ICSharpCode.Decompiler/IL/BlockBuilder.cs b/ICSharpCode.Decompiler/IL/BlockBuilder.cs index 57857727e..cfa5f0f8e 100644 --- a/ICSharpCode.Decompiler/IL/BlockBuilder.cs +++ b/ICSharpCode.Decompiler/IL/BlockBuilder.cs @@ -69,6 +69,7 @@ namespace ICSharpCode.Decompiler.IL } var variable = new ILVariable(VariableKind.Exception, eh.CatchType, handlerBlock.ILRange.Start); + variable.Name = "ex"; handlerBlock.EntryPoint.Instructions.Add(new LdLoc(variable)); ILInstruction filter; diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index ed2024a53..c182dbc4f 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -493,21 +493,21 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Starg_S: return Starg(reader.ReadByte()); case ILOpCode.Stind_I1: - return new StObj(value: Pop(), target: Pop(), type: typeSystem.SByte); + return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.SByte)); case ILOpCode.Stind_I2: - return new StObj(value: Pop(), target: Pop(), type: typeSystem.Int16); + return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Int16)); case ILOpCode.Stind_I4: - return new StObj(value: Pop(), target: Pop(), type: typeSystem.Int32); + return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Int32)); case ILOpCode.Stind_I8: - return new StObj(value: Pop(), target: Pop(), type: typeSystem.Int64); + return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Int64)); case ILOpCode.Stind_R4: - return new StObj(value: Pop(), target: Pop(), type: typeSystem.Single); + return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Single)); case ILOpCode.Stind_R8: - return new StObj(value: Pop(), target: Pop(), type: typeSystem.Double); + return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Double)); case ILOpCode.Stind_I: - return new StObj(value: Pop(), target: Pop(), type: typeSystem.IntPtr); + return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.IntPtr)); case ILOpCode.Stind_Ref: - return new StObj(value: Pop(), target: Pop(), type: typeSystem.Object); + return new Void(new StObj(value: Pop(), target: Pop(), type: typeSystem.Object)); case ILOpCode.Stloc: return Stloc(reader.ReadUInt16()); case ILOpCode.Stloc_S: @@ -535,7 +535,7 @@ namespace ICSharpCode.Decompiler.IL { var type = (TypeReference)ReadAndDecodeMetadataToken(); var ld = new LdObj(Pop(), type); - return new StObj(Pop(), ld, type); + return new Void(new StObj(Pop(), ld, type)); } case ILOpCode.Initobj: return new InitObj(Pop(), (TypeReference)ReadAndDecodeMetadataToken()); @@ -561,7 +561,7 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Ldflda: return new LdFlda(Pop(), (FieldReference)ReadAndDecodeMetadataToken()); case ILOpCode.Stfld: - return new StFld(value: Pop(), target: Pop(), field: (FieldReference)ReadAndDecodeMetadataToken()); + return new Void(new StFld(value: Pop(), target: Pop(), field: (FieldReference)ReadAndDecodeMetadataToken())); case ILOpCode.Ldlen: return new LdLen(Pop()); case ILOpCode.Ldobj: @@ -571,7 +571,7 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Ldsflda: return new LdsFlda((FieldReference)ReadAndDecodeMetadataToken()); case ILOpCode.Stsfld: - return new StsFld(Pop(), (FieldReference)ReadAndDecodeMetadataToken()); + return new Void(new StsFld(Pop(), (FieldReference)ReadAndDecodeMetadataToken())); case ILOpCode.Ldtoken: return new LdToken((MemberReference)ReadAndDecodeMetadataToken()); case ILOpCode.Ldvirtftn: @@ -599,7 +599,7 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Stelem_Ref: throw new NotImplementedException(); case ILOpCode.Stobj: - return new StObj(value: Pop(), target: Pop(), type: (TypeReference)ReadAndDecodeMetadataToken()); + return new Void(new StObj(value: Pop(), target: Pop(), type: (TypeReference)ReadAndDecodeMetadataToken())); case ILOpCode.Throw: return new Throw(Pop()); case ILOpCode.Unbox: @@ -648,7 +648,7 @@ namespace ICSharpCode.Decompiler.IL private ILInstruction Starg(ushort v) { - return new StLoc(Pop(), parameterVariables[v]); + return new Void(new StLoc(Pop(), parameterVariables[v])); } private ILInstruction Ldloc(ushort v) @@ -663,7 +663,7 @@ namespace ICSharpCode.Decompiler.IL private ILInstruction Stloc(ushort v) { - return new StLoc(Pop(), localVariables[v]); + return new Void(new StLoc(Pop(), localVariables[v])); } private ILInstruction DecodeConstrainedCall() diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index 2138a17c3..c9797976a 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using Mono.Cecil; namespace ICSharpCode.Decompiler.IL @@ -622,6 +623,7 @@ namespace ICSharpCode.Decompiler.IL { this.Filter = filter; this.Body = body; + Debug.Assert(variable != null); this.variable = variable; } ILInstruction filter; @@ -825,6 +827,7 @@ namespace ICSharpCode.Decompiler.IL { public LdLoc(ILVariable variable) : base(OpCode.LdLoc) { + Debug.Assert(variable != null); this.variable = variable; } readonly ILVariable variable; @@ -848,6 +851,7 @@ namespace ICSharpCode.Decompiler.IL { public LdLoca(ILVariable variable) : base(OpCode.LdLoca) { + Debug.Assert(variable != null); this.variable = variable; } public override StackType ResultType { get { return StackType.Ref; } } @@ -872,6 +876,7 @@ namespace ICSharpCode.Decompiler.IL public StLoc(ILInstruction value, ILVariable variable) : base(OpCode.StLoc) { this.Value = value; + Debug.Assert(variable != null); this.variable = variable; } ILInstruction value; @@ -896,10 +901,10 @@ namespace ICSharpCode.Decompiler.IL this.Value = this.value.Inline(flagsBefore, instructionStack, out finished); return this; } - public override StackType ResultType { get { return StackType.Void; } } readonly ILVariable variable; /// Returns the variable operand. public ILVariable Variable { get { return variable; } } + public override StackType ResultType { get { return variable.Type.GetStackType(); } } protected override InstructionFlags ComputeFlags() { return value.Flags; @@ -1306,10 +1311,10 @@ namespace ICSharpCode.Decompiler.IL public bool IsVolatile { get; set; } /// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix. public byte UnalignedPrefix { get; set; } - public override StackType ResultType { get { return StackType.Void; } } readonly FieldReference field; /// Returns the field operand. public FieldReference Field { get { return field; } } + public override StackType ResultType { get { return field.FieldType.GetStackType(); } } protected override InstructionFlags ComputeFlags() { return target.Flags | value.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow; @@ -1427,10 +1432,10 @@ namespace ICSharpCode.Decompiler.IL public bool IsVolatile { get; set; } /// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix. public byte UnalignedPrefix { get; set; } - public override StackType ResultType { get { return StackType.Void; } } readonly FieldReference field; /// Returns the field operand. public FieldReference Field { get { return field; } } + public override StackType ResultType { get { return field.FieldType.GetStackType(); } } protected override InstructionFlags ComputeFlags() { return value.Flags | InstructionFlags.SideEffect; diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index ecf1e05a6..e0ba7533d 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -106,7 +106,8 @@ new OpCode("ldloca", "Loads the address of a local variable. (ldarga/ldloca)", CustomClassName("LdLoca"), NoArguments, ResultType("Ref"), HasVariableOperand), new OpCode("stloc", "Stores a value into a local variable. (starg/stloc)", - CustomClassName("StLoc"), CustomArguments("value"), VoidResult, HasVariableOperand), + CustomClassName("StLoc"), CustomArguments("value"), HasVariableOperand, + ResultType("variable.Type.GetStackType()")), new OpCode("ldstr", "Loads a constant string.", CustomClassName("LdStr"), LoadConstant("string"), ResultType("O")), new OpCode("ldc.i4", "Loads a constant 32-bit integer.", @@ -136,14 +137,18 @@ new OpCode("ldflda", "Load address of instance field", CustomClassName("LdFlda"), CustomArguments("target"), MayThrow, HasFieldOperand, ResultType("Ref")), new OpCode("stfld", "Store value to instance field", - CustomClassName("StFld"), CustomArguments("target", "value"), MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, VoidResult, HasFieldOperand), + CustomClassName("StFld"), CustomArguments("target", "value"), + MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, HasFieldOperand, + ResultType("field.FieldType.GetStackType()")), new OpCode("ldsfld", "Load static field", CustomClassName("LdsFld"), NoArguments, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, HasFieldOperand, ResultType("field.FieldType.GetStackType()")), new OpCode("ldsflda", "Load static field address", CustomClassName("LdsFlda"), NoArguments, ResultType("Ref"), HasFieldOperand), new OpCode("stsfld", "Store value to static field", - CustomClassName("StsFld"), CustomArguments("value"), MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, VoidResult, HasFieldOperand), + CustomClassName("StsFld"), CustomArguments("value"), + MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, HasFieldOperand, + ResultType("field.FieldType.GetStackType()")), new OpCode("castclass", "Casts an object to a class.", CustomClassName("CastClass"), Unary, HasTypeOperand, MayThrow, ResultType("type.GetStackType()")), @@ -186,6 +191,7 @@ #> using System; using System.Collections.Generic; +using System.Diagnostics; using Mono.Cecil; namespace ICSharpCode.Decompiler.IL @@ -635,6 +641,7 @@ namespace ICSharpCode.Decompiler.IL static Action HasVariableOperand = opCode => { opCode.ConstructorParameters.Add("ILVariable variable"); opCode.Members.Add("readonly ILVariable variable;"); + opCode.ConstructorBody.Add("Debug.Assert(variable != null);"); opCode.ConstructorBody.Add("this.variable = variable;"); opCode.Members.Add("/// Returns the variable operand." + Environment.NewLine + "public ILVariable Variable { get { return variable; } }"); diff --git a/ICSharpCode.Decompiler/IL/Instructions/Branch.cs b/ICSharpCode.Decompiler/IL/Instructions/Branch.cs index b75462f76..44fb6ec41 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Branch.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Branch.cs @@ -90,9 +90,9 @@ namespace ICSharpCode.Decompiler.IL output.Write(' '); output.WriteReference(TargetLabel, (object)targetBlock ?? TargetILOffset, isLocal: true); if (PopCount != 0) { - output.Write(" (pop "); + output.Write(" (pops "); output.Write(PopCount.ToString()); - output.Write(')'); + output.Write(" element)"); } } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs index 45d9d48de..e5aa14df4 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs @@ -46,10 +46,11 @@ namespace ICSharpCode.Decompiler.IL throw new ArgumentException("Argument must not be of type void", "inst"); } - internal static void ValidateChild(ILInstruction inst) + internal void ValidateChild(ILInstruction inst) { if (inst == null) throw new ArgumentNullException("inst"); + Debug.Assert(!this.IsDescendantOf(inst), "ILAst must form a tree"); } [Conditional("DEBUG")] diff --git a/ICSharpCode.Decompiler/IL/TransformingVisitor.cs b/ICSharpCode.Decompiler/IL/TransformingVisitor.cs index 25c9602bb..1b896442d 100644 --- a/ICSharpCode.Decompiler/IL/TransformingVisitor.cs +++ b/ICSharpCode.Decompiler/IL/TransformingVisitor.cs @@ -79,9 +79,12 @@ namespace ICSharpCode.Decompiler.IL // Wrap the instruction on top of the stack into an inline block, // and append our void-typed instruction to the end of that block. var headInst = stack.Pop(); - var nestedBlock = headInst as Block ?? new Block { Instructions = { headInst } }; + var nestedBlock = headInst as Block ?? new Block { + Instructions = { headInst }, + ILRange = headInst.ILRange + }; nestedBlock.Instructions.Add(inst); - stack.Push(block); + stack.Push(nestedBlock); } else { // We can't move incomplete instructions into a nested block // or the instruction stack was empty