private bool EliminateGotoPair(GotoStatement gotoStatement, Statement labeledStatement) { if (TryRemoveChainedGoto(labeledStatement, gotoStatement)) { return true; } if (TryRemoveGoto(labeledStatement, gotoStatement)) { return true; } if (TryCopyTargetedBlock(labeledStatement, gotoStatement)) { return true; } //TODO: Add more steps return false; }
public override void VisitGotoStatement(GotoStatement node) { WriteKeyword(KeyWordWriter.GoTo); WriteSpace(); Write(node.TargetLabel); WriteEndOfStatement(); }
public override Statement CloneStatementOnly() { GotoStatement result = new GotoStatement(TargetLabel, null); CopyParentAndLabel(result); return result; }
public override Statement Clone() { GotoStatement result = new GotoStatement(TargetLabel, jumps); CopyParentAndLabel(result); return result; }
/// <summary> /// Checks if a GotoStatement is surrounded by an if statement. /// </summary> /// <param name="jump">The GotoStatement to be checked.</param> /// <returns>Returns true, if the goto is unconditional.</returns> private bool IsUnconditionalJump(GotoStatement jump) { /// Only gotos from the type /// If(condition) /// { /// goto Label; /// } /// are considered conditional. BlockStatement directParent = jump.Parent as BlockStatement; if (directParent == null) { ///Dummy check. throw new ArgumentOutOfRangeException("Goto statement outside of block."); } if (directParent.Parent == null) { ///The goto is in the outermost block statement. return true; } if (directParent.Parent is IfStatement == false) { ///The goto is not inside if statement at all. return true; } IfStatement parentIfStatement = directParent.Parent as IfStatement; if (parentIfStatement.Then == directParent && directParent.Statements.Count == 1 && parentIfStatement.Else == null) { ///Only case where goto is conditional - inside an if without else, and the only statement in the then block. return false; } return true; }
/// <summary> /// Embeds unconditional goto into <code> if(true){} </code> statement /// </summary> /// <param name="jump">The unconditional goto.</param> private void EmbedIntoDefaultIf(GotoStatement jump) { BlockStatement parentBlock = jump.Parent as BlockStatement; BlockStatement thenBlock = new BlockStatement(); thenBlock.AddStatement(jump); Expression condition = GetLiteralExpression(true); IfStatement embeddingStatement = new IfStatement(condition, thenBlock, null); ///Should be initialized by the statements themselves, but just in case. thenBlock.Parent = embeddingStatement; ///Replace the old goto statement with the new embedding If int jumpIndex = parentBlock.Statements.IndexOf(jump); parentBlock.Statements.RemoveAt(jumpIndex); parentBlock.AddStatementAt(jumpIndex, embeddingStatement); if (parentBlock.Parent is ConditionCase) { ///If the goto was the last statement in case add break after the embedding if. int embeddingStatementIndex = parentBlock.Statements.IndexOf(embeddingStatement); if (embeddingStatementIndex == parentBlock.Statements.Count) { parentBlock.AddStatement(new BreakStatement(null)); } } }
public CaseGotoStatement(GotoStatement transformedGoto, SwitchCase targetedCase) : base(transformedGoto.Label, transformedGoto.UnderlyingSameMethodInstructions) { this.TargetedSwitchCase = targetedCase; }
/// <summary> /// Replaces the goto statement with its target, if the target is goto statement. /// </summary> /// <param name="labeledStatement"></param> /// <param name="gotoStatement"></param> /// <returns></returns> private bool TryRemoveChainedGoto(Statement labeledStatement, GotoStatement gotoStatement) { if (!(labeledStatement is GotoStatement)) { return false; } BlockStatement parent = gotoStatement.Parent as BlockStatement; int index = parent.Statements.IndexOf(gotoStatement); /// Clone of labeled statement needed here Statement clone = labeledStatement.CloneStatementOnly(); clone.Label = string.Empty; parent.Statements.RemoveAt(index); parent.AddStatementAt(index, clone); methodContext.GotoStatements.Remove(gotoStatement); methodContext.GotoStatements.Add(clone as GotoStatement); if (!Targeted(labeledStatement.Label)) { UpdateUntargetedStatement(labeledStatement, new Statement[] { labeledStatement }); } return true; }
/// <summary> /// Moves the statements inside <paramref name="toMove"/> right after the goto statement adn removes the goto statement. /// </summary> /// <param name="gotoStatement">The goto statement, jumping to the block to be moved.</param> /// <param name="toMove">The collection of statements to be moved. This should already contain cloned statements.</param> private void MoveStatements(GotoStatement gotoStatement, IEnumerable<Statement> toMove) { BlockStatement gotoParent = gotoStatement.Parent as BlockStatement; if (gotoParent == null) { throw new DecompilationException("Goto statement not inside a block."); } int gotoIndex = gotoParent.Statements.IndexOf(gotoStatement); gotoParent.Statements.RemoveAt(gotoIndex); methodContext.GotoStatements.Remove(gotoStatement); int startIndex = gotoIndex; foreach (Statement st in toMove) { gotoParent.AddStatementAt(startIndex, st); startIndex++; } if (!string.IsNullOrEmpty(gotoStatement.Label)) { /// If the goto was target of another goto, update the label to point to the first statement of the coppied block. string theLabel = gotoStatement.Label; Statement newLabelCarrier = gotoParent.Statements[gotoIndex]; methodContext.GotoLabels[theLabel] = newLabelCarrier; newLabelCarrier.Label = gotoStatement.Label; } }
/// <summary> /// Coppies the block that is targeted from the goto if it matches the case /// /// ... some code /// goto: label0; /// /// ... /// ... /// label0: statement1 /// *statements* /// return; /// ... /// </summary> /// <param name="labeledStatement">The targeted statement.</param> /// <param name="gotoStatement">The goto statement.</param> /// <returns>Returns True if the targeted block was coppied.</returns> private bool TryCopyTargetedBlock(Statement labeledStatement, GotoStatement gotoStatement) { StatementCollection toCopy = new StatementCollection(); StatementCollection originalStatements = new StatementCollection(); BlockStatement targetParent = labeledStatement.Parent as BlockStatement; if (targetParent == null) { return false; } int targetIndex = targetParent.Statements.IndexOf(labeledStatement); originalStatements.Add(labeledStatement); Statement labeledClone = labeledStatement.CloneStatementOnly(); labeledClone.Label = string.Empty; toCopy.Add(labeledClone); int maxStatementsToCopy = MaximumStatementsToCopy; if (ContainsLabel(labeledClone)) { return false; } maxStatementsToCopy -= GetStatementsCount(labeledClone); if (maxStatementsToCopy < 0) { return false; } if (!IsReturnStatement(labeledClone) && !IsThrowStatement(labeledClone)) { ///Collect all statements, until a return is reached. int index; for (index = targetIndex + 1; index < targetParent.Statements.Count; index++) { Statement nextStatement = targetParent.Statements[index]; if (ContainsLabel(nextStatement)) { return false; } maxStatementsToCopy -= GetStatementsCount(nextStatement); if (maxStatementsToCopy < 0) { return false; } originalStatements.Add(nextStatement); Statement clone = nextStatement.CloneStatementOnly(); toCopy.Add(clone); if (IsReturnStatement(nextStatement) || IsThrowStatement(nextStatement)) { break; } } if (index == targetParent.Statements.Count) { ///all the statements were traversed and no 'return' statement was found return false; } } ///Move the coppied statements on the place of the goto statement. MoveStatements(gotoStatement, toCopy); ///Clean up the label from the targeted statement if possible, and remove the targeted statement if it cannot be reached anymore if (!Targeted(labeledStatement.Label)) { UpdateUntargetedStatement(labeledStatement, originalStatements); } return true; }
/// <summary> /// Removes the goto statement if it targets directly the statement afterwards /// </summary> /// <param name="labeledStatement">The targeted statement.</param> /// <param name="gotoStatement">The goto statement.</param> /// <returns></returns> private bool TryRemoveGoto(Statement labeledStatement, GotoStatement gotoStatement) { BlockStatement gotoParent = gotoStatement.Parent as BlockStatement; if (gotoParent == null) { throw new DecompilationException("Goto statement not inside a block."); } int gotoIndex = gotoParent.Statements.IndexOf(gotoStatement); if (labeledStatement.Parent == gotoParent && gotoParent.Statements.IndexOf(labeledStatement) == gotoIndex + 1) { ///then goto and label are consecutive gotoParent.Statements.RemoveAt(gotoIndex); methodContext.GotoStatements.Remove(gotoStatement); ///Clean up the label from the targeted statement if possible, and remove the targeted statement if it cannot be reached anymore if (!Targeted(labeledStatement.Label)) { UpdateUntargetedStatement(labeledStatement, new List<Statement>()); } return true; } if (gotoIndex == gotoParent.Statements.Count - 1) { ///then the goto is the last statement in the block ///it can potentially point to the next statement from the outer block Statement parent = gotoParent.Parent; if (parent == null) { ///the goto is in the outermost block return false; } if (parent.CodeNodeType == CodeNodeType.ConditionCase || parent.CodeNodeType == CodeNodeType.DefaultCase) { parent = parent.Parent; } if (parent.CodeNodeType == CodeNodeType.SwitchStatement || parent.CodeNodeType == CodeNodeType.ForEachStatement || parent.CodeNodeType == CodeNodeType.WhileStatement || parent.CodeNodeType == CodeNodeType.ForStatement || parent.CodeNodeType == CodeNodeType.DoWhileStatement || parent.CodeNodeType == CodeNodeType.IfStatement || parent.CodeNodeType == CodeNodeType.IfElseIfStatement) { BlockStatement outerBlock = parent.Parent as BlockStatement; if (labeledStatement.Parent != outerBlock) { return false; } if (outerBlock.Statements.IndexOf(parent) == outerBlock.Statements.IndexOf(labeledStatement) - 1) { ///Then the goto is to the next statement in the natural flow of the program gotoParent.Statements.RemoveAt(gotoIndex); methodContext.GotoStatements.Remove(gotoStatement); if (parent.CodeNodeType != CodeNodeType.IfStatement && parent.CodeNodeType != CodeNodeType.IfElseIfStatement) { ///then the goto must be replaced by break; gotoParent.AddStatementAt(gotoIndex, new BreakStatement(gotoStatement.UnderlyingSameMethodInstructions)); } ///Clean up the label from the targeted statement if possible, and remove the targeted statement if it cannot be reached anymore if (!Targeted(labeledStatement.Label)) { UpdateUntargetedStatement(labeledStatement, new List<Statement>()); } return true; } } } return false; }
public virtual void VisitGotoStatement(GotoStatement node) { }
public CaseGotoStatement(GotoStatement transformedGoto, SwitchCase targetedCase) { base(transformedGoto.get_Label(), transformedGoto.get_UnderlyingSameMethodInstructions()); this.set_TargetedSwitchCase(targetedCase); return; }