diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 4f7b94ea8..3c5a8f2b5 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -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 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(); diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs index 48035868c..4029711a1 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs @@ -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("variable").Single().Identifier != m2.Get("ident").Single().Identifier) + if (m1.Get("variable").Single().Identifier != m3.Get("ident").Single().Identifier) return null; WhileStatement loop = (WhileStatement)next; node.Remove(); BlockStatement newBody = new BlockStatement(); - foreach (Statement stmt in m2.Get("statement")) + foreach (Statement stmt in m3.Get("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("increment").Single().Detach()); + forStatement.Iterators.Add(m3.Get("increment").Single().Detach()); forStatement.EmbeddedStatement = newBody; loop.ReplaceWith(forStatement); return forStatement;