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();
		}
Пример #3
0
 public override Statement CloneStatementOnly()
 {
     GotoStatement result = new GotoStatement(TargetLabel, null);
     CopyParentAndLabel(result);
     return result;
 }
Пример #4
0
 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;
 }