diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index a143d8e73..da7ad22af 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -316,7 +316,7 @@ namespace ICSharpCode.Decompiler.Ast new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name) } }; - case ILCode.LoopBreak: return new Ast.BreakStatement(); + case ILCode.LoopOrSwitchBreak: return new Ast.BreakStatement(); case ILCode.LoopContinue: return new Ast.ContinueStatement(); #endregion #region Conversions diff --git a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs index 1c083389d..16b2c48b8 100644 --- a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs +++ b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs @@ -56,6 +56,19 @@ namespace ICSharpCode.Decompiler.ILAst } } + // Remove redundant break at the end of case + foreach(ILSwitch ilSwitch in method.GetSelfAndChildrenRecursive()) { + foreach(ILBlock ilCase in ilSwitch.CaseBlocks) { + int count = ilCase.Body.Count; + if (count >= 2) { + if (!ilCase.Body[count - 2].CanFallthough() && + ilCase.Body[count - 1].Match(ILCode.LoopOrSwitchBreak)) { + ilCase.Body.RemoveAt(count - 1); + } + } + } + } + // Remove redundant return if (method.Body.Count > 0 && method.Body.Last().Match(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0) { method.Body.RemoveAt(method.Body.Count - 1); @@ -98,21 +111,15 @@ namespace ICSharpCode.Decompiler.ILAst return true; } - // TODO: Swich also qualifies for break; - ILWhileLoop loop = null; - ILNode current = gotoExpr; - while(loop == null && current != null) { - current = parent[current]; - loop = current as ILWhileLoop; - } - - if (loop != null && target == Exit(loop, new HashSet() { gotoExpr })) { - gotoExpr.Code = ILCode.LoopBreak; + ILNode breakBlock = GetParents(gotoExpr).Where(n => n is ILWhileLoop || n is ILSwitch).FirstOrDefault(); + if (breakBlock != null && target == Exit(breakBlock, new HashSet() { gotoExpr })) { + gotoExpr.Code = ILCode.LoopOrSwitchBreak; gotoExpr.Operand = null; return true; } - if (loop != null && target == Enter(loop, new HashSet() { gotoExpr })) { + ILNode continueBlock = GetParents(gotoExpr).Where(n => n is ILWhileLoop).FirstOrDefault(); + if (continueBlock != null && target == Enter(continueBlock, new HashSet() { gotoExpr })) { gotoExpr.Code = ILCode.LoopContinue; gotoExpr.Operand = null; return true; @@ -172,6 +179,12 @@ namespace ICSharpCode.Decompiler.ILAst } } else if (expr.Code == ILCode.Nop) { return Exit(expr, visitedNodes); + } else if (expr.Code == ILCode.LoopOrSwitchBreak) { + ILNode breakBlock = GetParents(expr).Where(n => n is ILWhileLoop || n is ILSwitch).First(); + return Exit(breakBlock, new HashSet() { expr }); + } else if (expr.Code == ILCode.LoopContinue) { + ILNode continueBlock = GetParents(expr).Where(n => n is ILWhileLoop).First(); + return Enter(continueBlock, new HashSet() { expr }); } else { return expr; } diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index 36c0756c4..ece71a1e9 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -622,6 +622,8 @@ namespace ICSharpCode.Decompiler.ILAst HashSet content = FindDominatedNodes(scope, condTarget); scope.ExceptWith(content); caseBlock.Body.AddRange(FindConditions(content, condTarget)); + // Add explicit break which should not be used by default, but the goto removal might decide to use it + caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILExpression(ILCode.LoopOrSwitchBreak, null) } }); } ilSwitch.CaseBlocks.Add(caseBlock); } @@ -863,7 +865,7 @@ namespace ICSharpCode.Decompiler.ILAst case ILCode.Throw: case ILCode.Rethrow: case ILCode.LoopContinue: - case ILCode.LoopBreak: + case ILCode.LoopOrSwitchBreak: return false; } } diff --git a/ICSharpCode.Decompiler/ILAst/ILCodes.cs b/ICSharpCode.Decompiler/ILAst/ILCodes.cs index 1d3201d3b..43acc361e 100644 --- a/ICSharpCode.Decompiler/ILAst/ILCodes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILCodes.cs @@ -260,7 +260,7 @@ namespace ICSharpCode.Decompiler.ILAst LogicOr, InitArray, // Array Initializer TernaryOp, // ?: - LoopBreak, + LoopOrSwitchBreak, LoopContinue, Ldc_Decimal, diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index bed175b19..b7afed8d4 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -456,6 +456,8 @@ namespace ICSharpCode.Decompiler.ILAst case ILCode.Switch: case ILCode.Throw: case ILCode.Rethrow: + case ILCode.LoopOrSwitchBreak: + case ILCode.LoopContinue: return null; case ILCode.Ret: if (forceInferChildren && expr.Arguments.Count == 1)