Browse Source

Support for "break" in switch statements

pull/70/head
David Srbecký 15 years ago
parent
commit
fd1594996b
  1. 2
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 35
      ICSharpCode.Decompiler/ILAst/GotoRemoval.cs
  3. 4
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  4. 2
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  5. 2
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

2
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -316,7 +316,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -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

35
ICSharpCode.Decompiler/ILAst/GotoRemoval.cs

@ -56,6 +56,19 @@ namespace ICSharpCode.Decompiler.ILAst @@ -56,6 +56,19 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
// Remove redundant break at the end of case
foreach(ILSwitch ilSwitch in method.GetSelfAndChildrenRecursive<ILSwitch>()) {
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 @@ -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<ILNode>() { 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<ILNode>() { gotoExpr })) {
gotoExpr.Code = ILCode.LoopOrSwitchBreak;
gotoExpr.Operand = null;
return true;
}
if (loop != null && target == Enter(loop, new HashSet<ILNode>() { gotoExpr })) {
ILNode continueBlock = GetParents(gotoExpr).Where(n => n is ILWhileLoop).FirstOrDefault();
if (continueBlock != null && target == Enter(continueBlock, new HashSet<ILNode>() { gotoExpr })) {
gotoExpr.Code = ILCode.LoopContinue;
gotoExpr.Operand = null;
return true;
@ -172,6 +179,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -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<ILNode>() { expr });
} else if (expr.Code == ILCode.LoopContinue) {
ILNode continueBlock = GetParents(expr).Where(n => n is ILWhileLoop).First();
return Enter(continueBlock, new HashSet<ILNode>() { expr });
} else {
return expr;
}

4
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -622,6 +622,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -622,6 +622,8 @@ namespace ICSharpCode.Decompiler.ILAst
HashSet<ControlFlowNode> 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 @@ -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;
}
}

2
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -260,7 +260,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -260,7 +260,7 @@ namespace ICSharpCode.Decompiler.ILAst
LogicOr,
InitArray, // Array Initializer
TernaryOp, // ?:
LoopBreak,
LoopOrSwitchBreak,
LoopContinue,
Ldc_Decimal,

2
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -456,6 +456,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -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)

Loading…
Cancel
Save