diff --git a/src/Transforms/Ast/RemoveGotos.cs b/src/Transforms/Ast/RemoveGotos.cs index 442823f7b..5ce66bfb4 100644 --- a/src/Transforms/Ast/RemoveGotos.cs +++ b/src/Transforms/Ast/RemoveGotos.cs @@ -64,24 +64,11 @@ namespace Decompiler.Transforms.Ast lastStmt.Remove(); return null; } - // End of if body - if (lastStmt is GotoStatement && - blockStatement.Parent is IfElseStatement) - { - LabelStatement nextNodeAsLabel = blockStatement.Parent.Next() as LabelStatement; - if (nextNodeAsLabel != null) { - if (nextNodeAsLabel.Label == ((GotoStatement)lastStmt).Label) { - lastStmt.Remove(); - return null; - } - } - } return null; } - // Gets a next fall though statement, entering and exiting code blocks - // It does not matter what the current statement is + // Get the next statement that will be executed after this one // May return null public static INode GetNextStatement(Statement statement) { @@ -89,48 +76,65 @@ namespace Decompiler.Transforms.Ast Statement next = (Statement)statement.Next(); - // Exit a block of code - if (next == null) { - // When an 'if' body is finished the execution continues with the - // next statement after the 'if' statement - if (statement.Parent is BlockStatement && - statement.Parent.Parent is IfElseStatement) { - return GetNextStatement((Statement)statement.Parent.Parent); + if (next != null) { + return EnterBlockStatement(next); + } else { + if (statement.Parent is BlockStatement) { + return ExitBlockStatement((Statement)statement.Parent.Parent); + } else { + return null; } - - // When a 'for' body is finished the execution continues by: - // Iterator; Condition; Body - if (statement.Parent is BlockStatement && - statement.Parent.Parent is ForStatement) { - ForStatement forLoop = statement.Parent.Parent as ForStatement; - if (forLoop.Iterator.Count > 0) { - return forLoop.Iterator[0]; - } else if (!forLoop.Condition.IsNull) { - return forLoop.Condition; - } else { - return forLoop.EmbeddedStatement.Children.First; - } + } + } + + // Get the statement that will be executed once the given block exits by the end brace + // May return null + public static INode ExitBlockStatement(Statement statement) + { + if (statement == null) throw new ArgumentNullException(); + + // When an 'if' body is finished the execution continues with the + // next statement after the 'if' statement + if (statement is IfElseStatement) { + return GetNextStatement((IfElseStatement)statement); + } + + // When a 'for' body is finished the execution continues by: + // Iterator; Condition; Body + if (statement is ForStatement) { + ForStatement forLoop = statement as ForStatement; + if (forLoop.Iterator.Count > 0) { + return forLoop.Iterator[0]; + } else if (!forLoop.Condition.IsNull) { + return forLoop.Condition; + } else { + return EnterBlockStatement((Statement)forLoop.EmbeddedStatement.Children.First); } - - return null; } - // Enter a block of code - while(true) { - // If a 'for' loop does not have initializers and condition, - // the next statement is the entry point - ForStatement nextAsForStmt = next as ForStatement; - if (nextAsForStmt != null && - nextAsForStmt.Initializers.Count == 0 && - nextAsForStmt.Condition.IsNull && - nextAsForStmt.EmbeddedStatement is BlockStatement && - nextAsForStmt.EmbeddedStatement.Children.Count > 0) { - next = (Statement)nextAsForStmt.EmbeddedStatement.Children.First; - continue; // Restart + return null; + } + + // Get the first statement that will be executed in the given block + public static INode EnterBlockStatement(Statement statement) + { + if (statement == null) throw new ArgumentNullException(); + + // For loop starts as follows: Initializers; Condition; Body + if (statement is ForStatement) { + ForStatement forLoop = statement as ForStatement; + if (forLoop.Initializers.Count > 0) { + return forLoop.Initializers[0]; + } else if (!forLoop.Condition.IsNull) { + return forLoop.Condition; + } else if (forLoop.EmbeddedStatement is BlockStatement && + forLoop.EmbeddedStatement.Children.Count > 0) { + statement = (Statement)forLoop.EmbeddedStatement.Children.First; + return EnterBlockStatement(statement); // Simplify again } - - return next; } + + return statement; // Can not simplify } public override object VisitGotoStatement(GotoStatement gotoStatement, object data) @@ -165,15 +169,14 @@ namespace Decompiler.Transforms.Ast } // Replace goto with 'continue' - // Continue statement which moves at the very start of for loop if there is no contition and iteration - if ((CurrentLoop is ForStatement) && - (CurrentLoop as ForStatement).Condition.IsNull && - (CurrentLoop as ForStatement).Iterator.Count == 0 && - (CurrentLoop.EmbeddedStatement as BlockStatement) != null && - ((CurrentLoop.EmbeddedStatement as BlockStatement).Children.First as LabelStatement) != null && - ((CurrentLoop.EmbeddedStatement as BlockStatement).Children.First as LabelStatement).Label == gotoStatement.Label) { - ReplaceCurrentNode(new ContinueStatement()); - return null; + // Continue statement which moves at the very start of for loop + if (CurrentLoop != null) { + INode continueTarget = ExitBlockStatement(CurrentLoop); // The start of the loop + if ((continueTarget is LabelStatement) && + (continueTarget as LabelStatement).Label == gotoStatement.Label) { + ReplaceCurrentNode(new ContinueStatement()); + return null; + } } return null;