diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 99c23da2a..f9a7fe6c9 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -161,7 +161,10 @@ namespace ICSharpCode.Decompiler.CSharp if (inst.IsLeavingFunction) { if (currentFunction.IsIterator) return new YieldBreakStatement(); - else + else if (!inst.Value.MatchNop()) { + IType targetType = currentFunction.IsAsync ? currentFunction.AsyncReturnType : currentMethod.ReturnType; + return new ReturnStatement(exprBuilder.Translate(inst.Value).ConvertTo(targetType, exprBuilder, allowImplicitConversion: true)); + } else return new ReturnStatement(); } string label; @@ -181,12 +184,6 @@ namespace ICSharpCode.Decompiler.CSharp { return new ThrowStatement(); } - - protected internal override Statement VisitReturn(Return inst) - { - IType targetType = currentFunction.IsAsync ? currentFunction.AsyncReturnType : currentMethod.ReturnType; - return new ReturnStatement(exprBuilder.Translate(inst.Value).ConvertTo(targetType, exprBuilder, allowImplicitConversion: true)); - } protected internal override Statement VisitYieldReturn(YieldReturn inst) { @@ -420,6 +417,8 @@ namespace ICSharpCode.Decompiler.CSharp static bool IsFinalLeave(Leave leave) { + if (!leave.Value.MatchNop()) + return false; Block block = (Block)leave.Parent; if (leave.ChildIndex != block.Instructions.Count - 1 || block.FinalInstruction.OpCode != OpCode.Nop) return false; diff --git a/ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs b/ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs index 36a6b26d0..defbde9d3 100644 --- a/ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs +++ b/ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs @@ -416,6 +416,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis protected internal override void VisitLeave(Leave inst) { + inst.Value.AcceptVisitor(this); State targetState; if (stateOnLeave.TryGetValue(inst.TargetContainer, out targetState)) { targetState.JoinWith(state); @@ -428,12 +429,6 @@ namespace ICSharpCode.Decompiler.FlowAnalysis MarkUnreachable(); } - protected internal override void VisitReturn(Return inst) - { - inst.Value.AcceptVisitor(this); - MarkUnreachable(); - } - protected internal override void VisitThrow(Throw inst) { inst.Argument.AcceptVisitor(this); diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs index 5f367ccce..020d53fcc 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs @@ -447,10 +447,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow moveNextFunction.ReleaseRef(); foreach (var branch in function.Descendants.OfType()) { if (branch.TargetBlock == setResultAndExitBlock) { - if (resultVar != null) - branch.ReplaceWith(new Return(new LdLoc(resultVar)) { ILRange = branch.ILRange }); - else - branch.ReplaceWith(new Leave((BlockContainer)function.Body) { ILRange = branch.ILRange }); + branch.ReplaceWith(new Leave((BlockContainer)function.Body) { + Value = resultVar == null ? (ILInstruction)new Nop() : new LdLoc(resultVar), + ILRange = branch.ILRange + }); } } function.Variables.AddRange(function.Descendants.OfType().Select(inst => inst.Variable).Distinct()); diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowGraph.cs b/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowGraph.cs index ca40a2029..a5f006100 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowGraph.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowGraph.cs @@ -100,9 +100,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow // Leave instructions (like other exits out of the container) // are ignored for the CFG and dominance, // but is relevant for HasReachableExit(). - // However, a 'leave' that exits the whole function represents a void return, - // and is not considered a reachable exit (just like non-void returns). - if (!(leave.TargetContainer.Parent is ILFunction)) { + // However, a 'leave' that exits the whole function represents a return, + // and is not considered a reachable exit. + if (!leave.IsLeavingFunction) { nodeHasDirectExitOutOfContainer.Set(i); } } @@ -131,20 +131,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow return leaving; } - bool LeavesCurrentBlockContainer(Block block) - { - foreach (var node in block.Descendants) { - if (node is Branch branch && !branch.TargetBlock.IsDescendantOf(container)) { - // control flow that isn't internal to the block container - return true; - } - if (node is Leave leave && !leave.TargetContainer.IsDescendantOf(block)) { - return true; - } - } - return false; - } - /// /// Gets the ControlFlowNode for the block. /// diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs b/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs index f7211e6d3..695af22a4 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs @@ -64,13 +64,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow // (where 'v' has no other uses) // Simplify these to a simple `ret()` so that they match the release build version. // - if (block.Instructions.Count == 2 && block.Instructions[1].OpCode == OpCode.Return) { - Return ret = (Return)block.Instructions[1]; - ILVariable v; - ILInstruction inst; - if (ret.Value.MatchLdLoc(out v) - && v.IsSingleDefinition && v.LoadCount == 1 && block.Instructions[0].MatchStLoc(v, out inst)) - { + if (block.Instructions.Count == 2 && block.Instructions[1].MatchReturn(out ILInstruction value)) { + var ret = (Leave)block.Instructions[1]; + if (value.MatchLdLoc(out ILVariable v) + && v.IsSingleDefinition && v.LoadCount == 1 && block.Instructions[0].MatchStLoc(v, out ILInstruction inst)) { context.Step("Inline variable in return block", block); inst.AddILRange(ret.Value.ILRange); inst.AddILRange(block.Instructions[0].ILRange); @@ -119,11 +116,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow blocksToAdd.Add((localContainer, blockCopy)); branch.TargetBlock = blockCopy; } - } else if (targetBlock.Instructions.Count == 1 && targetBlock.Instructions[0].OpCode == OpCode.Leave) { + } else if (targetBlock.Instructions.Count == 1 && targetBlock.Instructions[0] is Leave leave && leave.Value.MatchNop()) { context.Step("Replace branch to leave with leave", branch); // Replace branches to 'leave' instruction with the leave instruction - Leave leave = (Leave)targetBlock.Instructions[0]; - branch.ReplaceWith(new Leave(leave.TargetContainer) { ILRange = branch.ILRange }); + branch.ReplaceWith(leave.Clone()); } if (targetBlock.IncomingEdgeCount == 0) targetBlock.Instructions.Clear(); // mark the block for deletion @@ -154,7 +150,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow var targetBlock = branch.TargetBlock; if (targetBlock.Instructions.Count != 1 || targetBlock.FinalInstruction.OpCode != OpCode.Nop) return false; - return targetBlock.Instructions[0] is Return ret && ret.Value is LdLoc; + return targetBlock.Instructions[0].MatchReturn(out var value) && value is LdLoc; } static bool CombineBlockWithNextBlock(BlockContainer container, Block block) diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/ExitPoints.cs b/ICSharpCode.Decompiler/IL/ControlFlow/ExitPoints.cs index 54322670f..156feb48d 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/ExitPoints.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/ExitPoints.cs @@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow case OpCode.Leave: Leave leave1 = (Leave)exit1; Leave leave2 = (Leave)exit2; - return leave1.TargetContainer == leave2.TargetContainer; + return leave1.TargetContainer == leave2.TargetContainer && leave1.Value.MatchNop() && leave2.Value.MatchNop(); default: return false; } @@ -192,6 +192,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow protected internal override void VisitLeave(Leave inst) { + base.VisitLeave(inst); + if (!inst.Value.MatchNop()) + return; HandleExit(inst); } } diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs b/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs index 5fc41d39a..3ce46d87f 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs @@ -747,23 +747,22 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow } break; case Leave leave: - if (leave.TargetContainer == oldBody) { - leave.TargetContainer = newBody; - } - break; - case Return ret: - ILInstruction value = ret.Value; - if (value.MatchLdLoc(out var v) && v.IsSingleDefinition - && v.StoreInstructions.SingleOrDefault() is StLoc stloc) - { - returnStores.Add(stloc); - value = stloc.Value; - } - if (value.MatchLdcI4(0)) { - // yield break - ret.ReplaceWith(new Leave(newBody) { ILRange = ret.ILRange }); + if (leave.MatchReturn(out var value)) { + if (value.MatchLdLoc(out var v) && v.IsSingleDefinition + && v.StoreInstructions.SingleOrDefault() is StLoc stloc) { + returnStores.Add(stloc); + value = stloc.Value; + } + if (value.MatchLdcI4(0)) { + // yield break + leave.ReplaceWith(new Leave(newBody) { ILRange = leave.ILRange }); + } else { + leave.ReplaceWith(new InvalidBranch("Unexpected return in MoveNext()") { ILRange = leave.ILRange }); + } } else { - ret.ReplaceWith(new InvalidBranch("Unexpected return in MoveNext()") { ILRange = ret.ILRange }); + if (leave.TargetContainer == oldBody) { + leave.TargetContainer = newBody; + } } break; } diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 832b7ee04..074c82983 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -526,6 +526,7 @@ namespace ICSharpCode.Decompiler.IL case Cil.Code.Dup: return Push(Peek()); case Cil.Code.Endfilter: + return new Leave(null) { Value = Pop() }; case Cil.Code.Endfinally: return new Leave(null); case Cil.Code.Initblk: @@ -942,7 +943,7 @@ namespace ICSharpCode.Decompiler.IL if (methodReturnStackType == StackType.Void) return new IL.Leave(mainContainer); else - return new IL.Return(Pop(methodReturnStackType)); + return new IL.Leave(mainContainer) { Value = Pop(methodReturnStackType) }; } private ILInstruction DecodeLdstr() diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index 1bce7d2e7..cdfdce322 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.IL Arglist, /// Unconditional branch. goto target; Branch, - /// Unconditional branch to end of block container. goto container_end;, often break; + /// Unconditional branch to end of block container. Return is represented using IsLeavingFunction and an (optional) return value. The block container evaluates to the value produced by the argument of the leave instruction. Leave, /// If statement / conditional expression. if (condition) trueExpr else falseExpr IfInstruction, @@ -115,8 +115,6 @@ namespace ICSharpCode.Decompiler.IL LdMemberToken, /// Allocates space in the stack frame LocAlloc, - /// Returns from the current method or lambda. Only used when returning a value; void returns are represented using a 'leave' instruction. - Return, /// Load address of instance field LdFlda, /// Load static field address @@ -1060,9 +1058,56 @@ namespace ICSharpCode.Decompiler.IL } namespace ICSharpCode.Decompiler.IL { - /// Unconditional branch to end of block container. goto container_end;, often break; - public sealed partial class Leave : SimpleInstruction + /// Unconditional branch to end of block container. Return is represented using IsLeavingFunction and an (optional) return value. The block container evaluates to the value produced by the argument of the leave instruction. + public sealed partial class Leave : ILInstruction { + public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true); + ILInstruction value; + public ILInstruction Value { + get { return this.value; } + set { + ValidateChild(value); + SetChildInstruction(ref this.value, value, 0); + } + } + protected sealed override int GetChildCount() + { + return 1; + } + protected sealed override ILInstruction GetChild(int index) + { + switch (index) { + case 0: + return this.value; + default: + throw new IndexOutOfRangeException(); + } + } + protected sealed override void SetChild(int index, ILInstruction value) + { + switch (index) { + case 0: + this.Value = value; + break; + default: + throw new IndexOutOfRangeException(); + } + } + protected sealed override SlotInfo GetChildSlot(int index) + { + switch (index) { + case 0: + return ValueSlot; + default: + throw new IndexOutOfRangeException(); + } + } + public sealed override ILInstruction Clone() + { + var clone = (Leave)ShallowClone(); + clone.Value = this.value.Clone(); + return clone; + } public override StackType ResultType { get { return StackType.Void; } } public override void AcceptVisitor(ILVisitor visitor) { @@ -1079,7 +1124,7 @@ namespace ICSharpCode.Decompiler.IL protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) { var o = other as Leave; - return o != null && this.TargetContainer == o.TargetContainer; + return o != null && this.value.PerformMatch(o.value, ref match) && this.TargetContainer == o.TargetContainer; } } } @@ -2538,98 +2583,6 @@ namespace ICSharpCode.Decompiler.IL } } namespace ICSharpCode.Decompiler.IL -{ - /// Returns from the current method or lambda. Only used when returning a value; void returns are represented using a 'leave' instruction. - public sealed partial class Return : ILInstruction - { - public Return(ILInstruction value) : base(OpCode.Return) - { - this.Value = value; - } - public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true); - ILInstruction value; - public ILInstruction Value { - get { return this.value; } - set { - ValidateChild(value); - SetChildInstruction(ref this.value, value, 0); - } - } - protected sealed override int GetChildCount() - { - return 1; - } - protected sealed override ILInstruction GetChild(int index) - { - switch (index) { - case 0: - return this.value; - default: - throw new IndexOutOfRangeException(); - } - } - protected sealed override void SetChild(int index, ILInstruction value) - { - switch (index) { - case 0: - this.Value = value; - break; - default: - throw new IndexOutOfRangeException(); - } - } - protected sealed override SlotInfo GetChildSlot(int index) - { - switch (index) { - case 0: - return ValueSlot; - default: - throw new IndexOutOfRangeException(); - } - } - public sealed override ILInstruction Clone() - { - var clone = (Return)ShallowClone(); - clone.Value = this.value.Clone(); - return clone; - } - public override StackType ResultType { get { return StackType.Void; } } - protected override InstructionFlags ComputeFlags() - { - return value.Flags | InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable; - } - public override InstructionFlags DirectFlags { - get { - return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable; - } - } - public override void WriteTo(ITextOutput output) - { - output.Write(OpCode); - output.Write('('); - this.value.WriteTo(output); - output.Write(')'); - } - public override void AcceptVisitor(ILVisitor visitor) - { - visitor.VisitReturn(this); - } - public override T AcceptVisitor(ILVisitor visitor) - { - return visitor.VisitReturn(this); - } - public override T AcceptVisitor(ILVisitor visitor, C context) - { - return visitor.VisitReturn(this, context); - } - protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) - { - var o = other as Return; - return o != null && this.value.PerformMatch(o.value, ref match); - } - } -} -namespace ICSharpCode.Decompiler.IL { /// Load address of instance field public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand @@ -4319,10 +4272,6 @@ namespace ICSharpCode.Decompiler.IL { Default(inst); } - protected internal virtual void VisitReturn(Return inst) - { - Default(inst); - } protected internal virtual void VisitLdFlda(LdFlda inst) { Default(inst); @@ -4597,10 +4546,6 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst); } - protected internal virtual T VisitReturn(Return inst) - { - return Default(inst); - } protected internal virtual T VisitLdFlda(LdFlda inst) { return Default(inst); @@ -4875,10 +4820,6 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst, context); } - protected internal virtual T VisitReturn(Return inst, C context) - { - return Default(inst, context); - } protected internal virtual T VisitLdFlda(LdFlda inst, C context) { return Default(inst, context); @@ -5019,7 +4960,6 @@ namespace ICSharpCode.Decompiler.IL "ldtypetoken", "ldmembertoken", "localloc", - "ret", "ldflda", "ldsflda", "castclass", @@ -5299,16 +5239,6 @@ namespace ICSharpCode.Decompiler.IL argument = default(ILInstruction); return false; } - public bool MatchReturn(out ILInstruction value) - { - var inst = this as Return; - if (inst != null) { - value = inst.Value; - return true; - } - value = default(ILInstruction); - return false; - } public bool MatchLdFlda(out ILInstruction target, out IField field) { var inst = this as LdFlda; diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index 8bc633ec2..c7932df7e 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -77,8 +77,8 @@ new OpCode("br", "Unconditional branch. goto target;", CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags, MatchCondition("this.TargetBlock == o.TargetBlock")), - new OpCode("leave", "Unconditional branch to end of block container. goto container_end;, often break;", - NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags, + new OpCode("leave", "Unconditional branch to end of block container. Return is represented using IsLeavingFunction and an (optional) return value. The block container evaluates to the value produced by the argument of the leave instruction.", + CustomConstructor, CustomArguments("value"), UnconditionalBranch, MayBranch, CustomWriteTo, CustomComputeFlags, MatchCondition("this.TargetContainer == o.TargetContainer")), new OpCode("if", "If statement / conditional expression. if (condition) trueExpr else falseExpr", CustomClassName("IfInstruction"), @@ -164,8 +164,6 @@ CustomClassName("LdMemberToken"), NoArguments, HasMemberOperand, ResultType("O")), new OpCode("localloc", "Allocates space in the stack frame", CustomClassName("LocAlloc"), Unary, ResultType("I"), MayThrow), - new OpCode("ret", "Returns from the current method or lambda. Only used when returning a value; void returns are represented using a 'leave' instruction.", - CustomClassName("Return"), CustomArguments("value"), MayBranch, UnconditionalBranch), new OpCode("ldflda", "Load address of instance field", CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand, ResultType("Ref")), diff --git a/ICSharpCode.Decompiler/IL/Instructions/Leave.cs b/ICSharpCode.Decompiler/IL/Instructions/Leave.cs index ab9539c11..c865ce0d8 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Leave.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Leave.cs @@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.IL /// Phase-2 execution removes PopCount elements from the evaluation stack /// and jumps to the target block. /// - partial class Leave : SimpleInstruction + partial class Leave : ILInstruction { BlockContainer targetContainer; @@ -39,11 +39,12 @@ namespace ICSharpCode.Decompiler.IL // Note: ILReader will create Leave instructions with targetContainer==null to represent 'endfinally', // the targetContainer will then be filled in by BlockBuilder this.targetContainer = targetContainer; + this.Value = new Nop(); } protected override InstructionFlags ComputeFlags() { - return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable; + return value.Flags | InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable; } public override InstructionFlags DirectFlags { @@ -78,7 +79,7 @@ namespace ICSharpCode.Decompiler.IL } public string TargetLabel { - get { return targetContainer != null ? targetContainer.EntryPoint.Label : string.Empty; } + get { return targetContainer?.EntryPoint != null ? targetContainer.EntryPoint.Label : string.Empty; } } /// @@ -104,6 +105,9 @@ namespace ICSharpCode.Decompiler.IL if (targetContainer != null) { output.Write(' '); output.WriteReference(TargetLabel, targetContainer, isLocal: true); + output.Write(" ("); + value.WriteTo(output); + output.Write(')'); } } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs b/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs index 1ab9fd822..dcbcdf151 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs @@ -120,7 +120,18 @@ namespace ICSharpCode.Decompiler.IL array = null; return false; } - + + public bool MatchReturn(out ILInstruction value) + { + var inst = this as Leave; + if (inst != null && inst.IsLeavingFunction) { + value = inst.Value; + return true; + } + value = default(ILInstruction); + return false; + } + public bool MatchBranch(out Block targetBlock) { var inst = this as Branch; @@ -137,11 +148,24 @@ namespace ICSharpCode.Decompiler.IL var inst = this as Branch; return inst != null && inst.TargetBlock == targetBlock; } + + public bool MatchLeave(out BlockContainer targetContainer, out ILInstruction value) + { + var inst = this as Leave; + if (inst != null) { + targetContainer = inst.TargetContainer; + value = inst.Value; + return true; + } + targetContainer = null; + value = null; + return false; + } public bool MatchLeave(out BlockContainer targetContainer) { var inst = this as Leave; - if (inst != null) { + if (inst != null && inst.Value.MatchNop()) { targetContainer = inst.TargetContainer; return true; } @@ -152,7 +176,7 @@ namespace ICSharpCode.Decompiler.IL public bool MatchLeave(BlockContainer targetContainer) { var inst = this as Leave; - return inst != null && inst.TargetContainer == targetContainer; + return inst != null && inst.TargetContainer == targetContainer && inst.Value.MatchNop(); } public bool MatchIfInstruction(out ILInstruction condition, out ILInstruction trueInst, out ILInstruction falseInst) diff --git a/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs b/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs index 05120f617..08866b8fe 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs @@ -259,7 +259,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (p != null && !string.IsNullOrEmpty(p.Name)) return CleanUpVariableName(p.Name); break; - case Return ret: + case Leave ret: return "result"; } return null; diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs index aa567d713..e8b8b78b4 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs @@ -272,7 +272,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms // decide based on the target into which we are inlining var parent = loadInst.Parent; switch (next.OpCode) { - case OpCode.Return: + case OpCode.Leave: return parent == next; case OpCode.IfInstruction: while (parent.OpCode == OpCode.LogicNot) {