Browse Source

Implement detection of for loops in StatementBuilder

pull/728/merge
Siegfried Pammer 9 years ago
parent
commit
f555ec7704
  1. 50
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  2. 41
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

50
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -279,26 +279,34 @@ namespace ICSharpCode.Decompiler.CSharp @@ -279,26 +279,34 @@ namespace ICSharpCode.Decompiler.CSharp
&& container.EntryPoint.Instructions[0].MatchIfInstruction(out var conditionInst, out var trueInst)
&& container.EntryPoint.Instructions[1].MatchLeave(container)) {
// detected while(condition)-loop or for-loop
// we have to check if there's an increment block before converting the loop body using ConvertAsBlock(trueInst)
// and set the continueTarget to correctly convert 'br incrementBlock' instructions to continue;
Block incrementBlock = null;
if (container.EntryPoint.IncomingEdgeCount == 2) {
incrementBlock = container.Blocks.SingleOrDefault(b => b.Instructions.Last().MatchBranch(container.EntryPoint) && b.Instructions.All(IsSimpleStatement));
if (incrementBlock != null)
continueTarget = incrementBlock;
}
conditionExpr = exprBuilder.TranslateCondition(conditionInst);
blockStatement = ConvertAsBlock(trueInst);
if (!trueInst.HasFlag(InstructionFlags.EndPointUnreachable))
blockStatement.Add(new BreakStatement());
if (container.EntryPoint.IncomingEdgeCount == 2) {
var incrementBlock = container.Blocks.SingleOrDefault(b => b.Instructions.Last().MatchBranch(container.EntryPoint));
if (incrementBlock != null) {
// for-loop
/* continueTarget = incrementBlock;
var forStmt = new ForStatement() {
Condition = conditionExpr,
EmbeddedStatement = ConvertBlockContainer(blockStatement, container, container.Blocks.Skip(1).Where(b => b != incrementBlock), true)
};
for (int i = 0; i < incrementBlock.Instructions.Count - 1; i++) {
forStmt.Iterators.Add(Convert(incrementBlock.Instructions[i]));
}
return forStmt;*/
if (incrementBlock != null) {
// for-loop
var forBody = ConvertBlockContainer(blockStatement, container, container.Blocks.Skip(1).Where(b => b != incrementBlock), true);
var forStmt = new ForStatement() {
Condition = conditionExpr,
EmbeddedStatement = forBody
};
for (int i = 0; i < incrementBlock.Instructions.Count - 1; i++) {
forStmt.Iterators.Add(Convert(incrementBlock.Instructions[i]));
}
if (incrementBlock.IncomingEdgeCount > continueCount)
forBody.Add(new LabelStatement { Label = incrementBlock.Label });
if (forBody.LastOrDefault() is ContinueStatement continueStmt)
continueStmt.Remove();
return forStmt;
}
blockStatement = ConvertBlockContainer(blockStatement, container, container.Blocks.Skip(1), true);
} else {
// do-while or while(true)-loop
@ -325,6 +333,20 @@ namespace ICSharpCode.Decompiler.CSharp @@ -325,6 +333,20 @@ namespace ICSharpCode.Decompiler.CSharp
return new WhileStatement(conditionExpr, blockStatement);
}
private static bool IsSimpleStatement(ILInstruction inst)
{
switch (inst) {
case IfInstruction i:
case SwitchInstruction s:
case TryCatch t:
case TryFault fa:
case TryFinally fi:
return false;
default:
return true;
}
}
private static Block FindDoWhileConditionBlock(BlockContainer container, out ILInstruction condition)
{
var conditionGroup = new CaptureGroup();

41
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -595,26 +595,53 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -595,26 +595,53 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}))
}
}};
static readonly ForStatement forLoopWithoutInitializer = new ForStatement {
Condition = new BinaryOperatorExpression {
Left = new NamedNode("ident", new IdentifierExpression(Pattern.AnyString)),
Operator = BinaryOperatorType.Any,
Right = new AnyNode("endExpr")
},
Iterators = {
new NamedNode(
"increment",
new ExpressionStatement(
new AssignmentExpression {
Left = new Backreference("ident"),
Operator = AssignmentOperatorType.Any,
Right = new AnyNode()
}))
},
EmbeddedStatement = new AnyNode()
};
public ForStatement TransformFor(ExpressionStatement node)
{
Match m1 = variableAssignPattern.Match(node);
if (!m1.Success) return null;
AstNode next = node.NextSibling;
Match m2 = forPattern.Match(next);
if (!m2.Success) return null;
Match m2 = forLoopWithoutInitializer.Match(next);
ForStatement forStatement;
if (m2.Success) {
node.Remove();
forStatement = (ForStatement)next;
forStatement.InsertChildAfter(null, node, ForStatement.InitializerRole);
return forStatement;
}
Match m3 = forPattern.Match(next);
if (!m3.Success) return null;
// ensure the variable in the for pattern is the same as in the declaration
if (m1.Get<IdentifierExpression>("variable").Single().Identifier != m2.Get<IdentifierExpression>("ident").Single().Identifier)
if (m1.Get<IdentifierExpression>("variable").Single().Identifier != m3.Get<IdentifierExpression>("ident").Single().Identifier)
return null;
WhileStatement loop = (WhileStatement)next;
node.Remove();
BlockStatement newBody = new BlockStatement();
foreach (Statement stmt in m2.Get<Statement>("statement"))
foreach (Statement stmt in m3.Get<Statement>("statement"))
newBody.Add(stmt.Detach());
ForStatement forStatement = new ForStatement();
forStatement = new ForStatement();
forStatement.Initializers.Add(node);
forStatement.Condition = loop.Condition.Detach();
forStatement.Iterators.Add(m2.Get<Statement>("increment").Single().Detach());
forStatement.Iterators.Add(m3.Get<Statement>("increment").Single().Detach());
forStatement.EmbeddedStatement = newBody;
loop.ReplaceWith(forStatement);
return forStatement;

Loading…
Cancel
Save