public Statement FixToSwitch(IfStatement node, VariableReferenceExpression stringVariable, VariableReferenceExpression intVariable)
		{
			/// The checks in the matcher ensured that the first statement in <paramref name="node"/> is an if statement, and
			/// that the dictionary is filled inside it's Then body.
			/// 
			this.theIntVariable = intVariable;
			this.theStringVariable = stringVariable;
			if (node.Then.Statements.Count != 2)
			{
				// sanity check;
				return node;
			}
			if (!(node.Then.Statements[0] is IfStatement) || !(node.Then.Statements[1] is IfStatement))
			{
				/// sanity checks
				return node;
			}
			FillValueDictionary((node.Then.Statements[0] as IfStatement).Then);
			BlockStatement result = FixSwitchingIf((node.Then.Statements[1] as IfStatement).Then);

			node.Then.Statements.Clear();
			node.Then = result;

			return node;
		}
 public override void VisitIfStatement(IfStatement node)
 {
     if (node.Then.Statements.Count == 0)
     {
         emptyThenIfs.Add(node);
     }
     base.VisitIfStatement(node);
 }
		public override ICodeNode VisitIfStatement(IfStatement node)
		{
			if (matcher.TryMatch(node))
			{
				Statement result = fixer.FixToSwitch(node, matcher.StringVariable, matcher.IntVariable);
				return base.Visit(result);
			}
			return base.VisitIfStatement(node);
		}
        public override ICodeNode VisitIfStatement(IfStatement node)
        {
            if (CheckIfStatement(node))
            {
                return null;
            }

            return base.VisitIfStatement(node);
        }
        public override Statement CloneStatementOnly()
        {
            BlockStatement clonedThen = then != null ? then.CloneStatementOnly() as BlockStatement : null;
            BlockStatement clonedElse = @else != null ? @else.CloneStatementOnly() as BlockStatement : null;

            IfStatement result = new IfStatement(Condition.CloneExpressionOnly(), clonedThen, clonedElse);
            CopyParentAndLabel(result);
            return result;
        }
		private IfElseIfStatement HandleDirectIfStatement(IfStatement theIf)
		{
			/// At this point we are sure, that if-else-if statement can be created without reverting the condition
			/// Now we need to perform checks if we can create if-else-if statement after reversing and to chose which one to create
			/// 

			if (theIf.Then.Statements.Count != 1)
			{ 
				/// There is only one way in which we can create the if-else-if statement

				IfElseIfStatement result = BuildIfElseIfStatement(theIf);
				return result;
			}
			Statement thenStatement = theIf.Then.Statements[0];
			if (thenStatement.CodeNodeType != CodeNodeType.IfElseIfStatement && thenStatement.CodeNodeType != CodeNodeType.IfStatement)
			{
				/// There is only one way in which we can create the if-else-if statement

				IfElseIfStatement result = BuildIfElseIfStatement(theIf);
				return result;
			}
			Statement elseStatement = theIf.Else.Statements[0];
			if (elseStatement.CodeNodeType == CodeNodeType.IfStatement)
			{
				/// If the else statement is only if-statement, then we invert the code anyways
				/// best case: the then statement was if-else-if, and we get one level nesting less
				/// worst case: the then statemnt was if-statement as well and we get the same level of nesting as if we haven't inverted
				InvertIfStatement(theIf);
				IfElseIfStatement result = BuildIfElseIfStatement(theIf);
				return result;
			}
			/// from this point the else statement is known to be if-else-if statement
			/// 

			if (thenStatement.CodeNodeType == CodeNodeType.IfStatement)
			{
				/// This way we will continue the if-else-if statement in the else block
				IfElseIfStatement result = BuildIfElseIfStatement(theIf);
				return result;
			}

			IfElseIfStatement elseIfElseStatement = (IfElseIfStatement)elseStatement;
			IfElseIfStatement thenIfElseStatement = (IfElseIfStatement)thenStatement;

			if (thenIfElseStatement.ConditionBlocks.Count >= elseIfElseStatement.ConditionBlocks.Count)
			{
				InvertIfStatement(theIf);
			}

			IfElseIfStatement endResult = BuildIfElseIfStatement(theIf);
			return endResult;
		}
		//x = cond ? y : z;
		//
		//==
		//
		//if(cond)
		//{
		//      x = y;
		//}
		//else
		//{
		//      x = z;
		//}
		//
		//x - phi variable
		//y, z - expressions

		public bool TryMatchInternal(IfStatement theIfStatement, out Statement result)
		{
			result = null;

			if (theIfStatement == null)
			{
				return false;
			}

			VariableReference xVariableReference = null;
			VariableReference x1VariableReference = null;
			Expression yExpressionValue;
			Expression zExpressionValue;

			if (theIfStatement.Else == null ||
				theIfStatement.Then.Statements.Count != 1 || theIfStatement.Else.Statements.Count != 1 ||
				theIfStatement.Then.Statements[0].CodeNodeType != CodeNodeType.ExpressionStatement ||
				theIfStatement.Else.Statements[0].CodeNodeType != CodeNodeType.ExpressionStatement)
			{
				return false;
			}

			BinaryExpression thenAssignExpression = (theIfStatement.Then.Statements[0] as ExpressionStatement).Expression as BinaryExpression;
			BinaryExpression elseAssignExpression = (theIfStatement.Else.Statements[0] as ExpressionStatement).Expression as BinaryExpression;
			if (!IsAssignToVariableExpression(thenAssignExpression, out x1VariableReference) || 
				!IsAssignToVariableExpression(elseAssignExpression, out xVariableReference))
			{
				return false;
			}

			if (xVariableReference != x1VariableReference)
			{
				return false;
			}
			if (!ShouldInlineExpressions(thenAssignExpression, elseAssignExpression))
			{
				/// Although correct syntax, nesting ternary expressions makes the code very unreadable.
				return false;
			}

			yExpressionValue = GetRightExpressionMapped(thenAssignExpression);
            zExpressionValue = GetRightExpressionMapped(elseAssignExpression);

			ConditionExpression ternaryConditionExpression = new ConditionExpression(theIfStatement.Condition, yExpressionValue, zExpressionValue, null);
			BinaryExpression ternaryAssign = new BinaryExpression(BinaryOperator.Assign,
				new VariableReferenceExpression(xVariableReference, null), ternaryConditionExpression, this.typeSystem, null);

            result = new ExpressionStatement(ternaryAssign) { Parent = theIfStatement.Parent };
            FixContext(xVariableReference.Resolve(), 1, 0, result as ExpressionStatement);
			return true;
		}
		public bool TryMatch(IfStatement node)
		{
			this.DictionaryField = null;
			this.StringVariable = null;
			this.IntVariable = null;
			if (IsNullCheck(node.Condition) || node.Else == null)
			{
				if (CheckOuterIfBody(node.Then))
				{
					return true;
				}
			}
			return false;
		}
        public override Statement Clone()
        {
            BlockStatement clonedThen = null;
            if (then != null)
            {
                clonedThen = then.Clone() as BlockStatement;
            }

            BlockStatement clonedElse = null;
            if (@else != null)
            {
                clonedElse = @else.Clone() as BlockStatement;
            }

            IfStatement result = new IfStatement(Condition.Clone(), clonedThen, clonedElse);
            CopyParentAndLabel(result);
            return result;
        }
		private bool CheckDictionaryIf(IfStatement dictionaryIf)
		{
			if (dictionaryIf.Else != null)
			{
				return false;
			}
			if(!CheckDictionaryIfCondition(dictionaryIf.Condition))
			{
				return false;
			}
			if (DictionaryField == null)
			{
				// This is sanity check.
				// If the check for the condition succeesd, then the condition field must be set.
				return false;
			}
			return CheckDictionaryIfBody(dictionaryIf.Then);
		}
        private bool CheckIfStatement(IfStatement theIf)
        {
            if (!CheckIfStatementStructure(theIf))
            {
                return false;
            }

            BinaryExpression theCondition = theIf.Condition as BinaryExpression;

            if (theCondition.Left.CodeNodeType == CodeNodeType.FieldReferenceExpression)
            {
                return CheckFieldCaching(theIf);
            }
            else if (theCondition.Left.CodeNodeType == CodeNodeType.VariableReferenceExpression)
            {
                return CheckVariableCaching(theIf);
            }

            return false;
        }
		public override ICodeNode VisitIfStatement(IfStatement node)
		{
			ICodeNode transformedNode = base.VisitIfStatement(node);
			if (transformedNode.CodeNodeType != CodeNodeType.IfStatement)
			{
				return transformedNode;
			}

			IfStatement theIf = (IfStatement)transformedNode;
			if (theIf.Else == null)
			{
				return theIf;
			}

			if (theIf.Else.Statements.Count == 1)
			{
				Statement elseStatement = theIf.Else.Statements[0];
				if (elseStatement.CodeNodeType == CodeNodeType.IfStatement || elseStatement.CodeNodeType == CodeNodeType.IfElseIfStatement)
				{
					IfElseIfStatement resultingIfElseIf = HandleDirectIfStatement(theIf);
					return resultingIfElseIf;
				}				
			}

			if (theIf.Then.Statements.Count != 1)
			{
				return theIf;
			}
			Statement thenStatement = theIf.Then.Statements[0];

			if (thenStatement.CodeNodeType != CodeNodeType.IfStatement && thenStatement.CodeNodeType != CodeNodeType.IfElseIfStatement)
			{
				return theIf;
			}

			InvertIfStatement(theIf);

			IfElseIfStatement result = BuildIfElseIfStatement(theIf);

			return result;
		}
 public override void VisitIfStatement(IfStatement node)
 {
     if(node.Else == null && node.Condition.CodeNodeType == CodeNodeType.BinaryExpression)
     {
         BinaryExpression ifCondition = node.Condition as BinaryExpression;
         if(ifCondition.Operator == BinaryOperator.ValueEquality && ifCondition.Left.CodeNodeType == CodeNodeType.FieldReferenceExpression &&
             ifCondition.Right.CodeNodeType == CodeNodeType.LiteralExpression && (ifCondition.Right as LiteralExpression).Value == null)
         {
             FieldReferenceExpression callSiteField = ifCondition.Left as FieldReferenceExpression;
             FieldDefinition resolvedField = callSiteField.Field.Resolve();
             if (callSiteField.Field.FieldType.GetElementType().GetFriendlyFullName(null) == CallSiteInstanceTypeName &&
                 CheckFieldDefinition(resolvedField))
             {
                 ProcessCallSiteCaching(node, resolvedField);
                 statementsToRemove.Add(node);
                 return;
             }
         }
     }
     base.VisitIfStatement(node);
 }
 /// <summary>
 /// Decides if a check for contained breaks/continues should be performed.
 /// </summary>
 /// <param name="gotoStatement">The goto statement that causes the check.</param>
 /// <returns>Return strue if a check needs to be performed.</returns>
 private bool ShouldCheck(IfStatement gotoStatement)
 {
     Statement parent = gotoStatement.Parent;
     while (parent != null)
     {
         if (parent is SwitchStatement || parent is ForStatement || parent is ForEachStatement || parent is WhileStatement || parent is DoWhileStatement)
         {
             return true;
         }
         parent = parent.Parent;
     }
     return false;
 }
        /// <summary>
        /// Contains the logic for moving a  goto inside the case of switch statement. For more information 
        /// see Chapter "2.2.2 Inward-movement Transformations : Moving a goto into a switch statement" from
        /// <see cref="Taming Control Flow A Structured Approach to Eliminating Goto Statements.pdf"/>.
        /// </summary>
        /// <param name="gotoStatement">The goto statement to be moved in.</param>
        /// <param name="switchCase">The switch case that contains the target of the goto statement.</param>
        /// <param name="label">The label of the target.</param>
        private void MoveInCase(IfStatement gotoStatement, SwitchCase switchCase, string label)
        {
            VariableReferenceExpression conditionVariable = new VariableReferenceExpression(GetLabelVariable(label), null);
            BlockStatement containingBlock = GetOuterBlock(gotoStatement);
            SwitchStatement switchStatement = switchCase.Parent as SwitchStatement;

            int gotoIndex = containingBlock.Statements.IndexOf(gotoStatement);
            int switchIndex = containingBlock.Statements.IndexOf(switchStatement);

            /// Generate variable and extract the switch condition
            string switchVariableName = "switch" + switchStatement.ConditionBlock.First.Offset;
            TypeReference switchVariableType = GetSwitchType(switchStatement);
            VariableDefinition switchVariable = new VariableDefinition(switchVariableName, switchVariableType);
            switchVariables.Add(switchVariable);
            VariableReferenceExpression switchVarEx = new VariableReferenceExpression(switchVariable, null);
            ExtractConditionIntoVariable(switchVarEx, switchStatement, containingBlock);

            BlockStatement thenBlock = CollectStatements(gotoIndex + 1, switchIndex + 1, containingBlock);

            BlockStatement elseBlock = new BlockStatement();

            /// Adds swCond = caseCond; in the last part of else.
            BinaryExpression assignSwitchVariable = new BinaryExpression(BinaryOperator.Assign, switchVarEx.CloneExpressionOnly(), GetCaseConditionExpression(switchCase), typeSystem, null);
            elseBlock.AddStatement(new ExpressionStatement(assignSwitchVariable));

            IfStatement precedingIf = new IfStatement(new UnaryExpression(UnaryOperator.LogicalNot, conditionVariable, null), thenBlock, elseBlock);

            /// Attach new if and move the goto conditional.
            /// Attach it only if the then block is not empty.
            if (precedingIf.Then.Statements.Count != 0)
            {
                containingBlock.AddStatementAt(gotoIndex, precedingIf);
            }
            containingBlock.Statements.Remove(gotoStatement);
            switchCase.Body.AddStatementAt(0, gotoStatement);
        }
		public override void VisitIfStatement(IfStatement node)
		{
            TryProcessConditionStatement(node);

            states.Push(Step.Expression);
            Visit(node.Condition);
            states.Pop();

            Visit(node.Then);
            Visit(node.Else);
		}
 /// <summary>
 /// Adds 
 /// <code>
 /// If(<paramref name="conditionVariable"/>)
 /// {
 ///     <paramref name="statement"/>
 /// }
 /// </code>
 /// statement at <paramref name="index"/> in <paramref name="containingBlock"/>
 /// </summary>
 /// <param name="index">The index at which the generated statement must be inserted.</param>
 /// <param name="containingBlock">The block, in which the new statement is inserted.</param>
 /// <param name="statement">The only statement in the then clause.</param>
 /// <param name="conditionVariable">The condition of the if.</param>
 private void AddBreakContinueConditional(int index, BlockStatement containingBlock, Statement statement, VariableReference conditionVariable)
 {
     BlockStatement thenBlock = new BlockStatement();
     thenBlock.AddStatement(statement);
     VariableReferenceExpression ifCondition = new VariableReferenceExpression(conditionVariable, null);
     IfStatement enclosingIfStatement = new IfStatement(ifCondition, thenBlock, null);
     containingBlock.AddStatementAt(index, enclosingIfStatement);
 }
        protected override ICodeNode GetIfSubstitution(IfStatement node)
        {
            BinaryExpression condition = node.Condition as BinaryExpression;
            if (condition.Left.CodeNodeType != CodeNodeType.FieldReferenceExpression)
            {
                return null;
            }

            FieldReferenceExpression fieldReference = condition.Left as FieldReferenceExpression;
            FieldDefinition fieldDefinition = fieldReference.Field.Resolve();
            if (!this.fieldToReplacingExpressionMap.ContainsKey(fieldDefinition))
            {
                throw new Exception("Caching field not found.");
            }

            VariableDefinition newVariable = new VariableDefinition(fieldDefinition.FieldType);
            VariableReferenceExpression newVariableReference = new VariableReferenceExpression(newVariable, null);
            BinaryExpression newAssignment = new BinaryExpression(BinaryOperator.Assign, newVariableReference, this.fieldToReplacingExpressionMap[fieldDefinition],
                                                                  this.context.MethodContext.Method.Module.TypeSystem, null);
            ExpressionStatement newStatement = new ExpressionStatement(newAssignment);

            this.initializationsToRemove.Add(newVariable, newStatement);

            this.variableToReplacingExpressionMap.Add(newVariable, this.fieldToReplacingExpressionMap[fieldDefinition]);
            this.fieldToReplacingExpressionMap[fieldDefinition] = newVariableReference;

            this.context.MethodContext.Variables.Add(newVariable);
            this.context.MethodContext.VariablesToRename.Add(newVariable);

            return newStatement;
        }
        /// <summary>
        /// The realisation of algorithm for single goto statement.
        /// </summary>
        /// <param name="gotoStatement">The goto statement to be eliminated.</param>
        /// <param name="labeledStatement">The labeled statement corresponding to <paramref name="gotoStatement"/>.</param>
        private void EliminateGotoPair(IfStatement gotoStatement, Statement labeledStatement)
        {
            ///Get the relation between goto and label. For more info about the relations, see Chapter 2.2 of
            ///<see cref="Taming Control Flow A Structured Approach to Eliminating Goto Statements.pdf"/>.
            int gotoLevel = CalculateLevel(gotoStatement);
            int labelLevel = CalculateLevel(labeledStatement);

            bool gotoPrecedesLabel = Precedes(gotoStatement, labeledStatement);
            GotoToLabelRelation relation = ResolveRelation(gotoStatement, labeledStatement);

            ///Perform the movements described in Chapter 2.2, until the goto and the label are in the same BlockStatement.
            while (relation != GotoToLabelRelation.Siblings)
            {
                if (relation == GotoToLabelRelation.IndirectlyRelated)
                {
                    MoveOut(gotoStatement, labeledStatement.Label);
                }
                if (relation == GotoToLabelRelation.DirectlyRelated)
                {
                    if (gotoLevel > labelLevel)
                    {
                        MoveOut(gotoStatement, labeledStatement.Label);
                    }
                    else
                    {
                        if (!gotoPrecedesLabel)
                        {
                            Statement labelContainer = GetSameLevelParent(labeledStatement, gotoStatement);
                            LiftGoto(gotoStatement, labelContainer, labeledStatement.Label);
                        }

                        Statement labeledStatementSameLevelParent = GetSameLevelParent(labeledStatement, gotoStatement);
                        MoveIn(gotoStatement, labeledStatementSameLevelParent, labeledStatement.Label);
                    }
                }

                ///Update the relation info between the goto statement and the labeled target statement
                gotoLevel = CalculateLevel(gotoStatement);
                labelLevel = CalculateLevel(labeledStatement);
                relation = ResolveRelation(gotoStatement, labeledStatement);
                gotoPrecedesLabel = Precedes(gotoStatement, labeledStatement);
            }

            ///Perform the appropriate goto-elimination transformation, as described in Chapter 2.1
            if (gotoPrecedesLabel)
            {
                EliminateViaIf(gotoStatement, labeledStatement);
            }
            else
            {
                EliminateViaDoWhile(gotoStatement, labeledStatement);
            }
        }
        /// <summary>
        /// Eliminates the goto statement via introducing do-while. Should be used when the goto comes after the label.
        /// </summary>
        /// <param name="gotoStatement">The goto statement.</param>
        /// <param name="labeledStatement">The labeled statement.</param>
        private void EliminateViaDoWhile(IfStatement gotoStatement, Statement labeledStatement)
        {
            ICollection<BreakStatement> breaks = new List<BreakStatement>();
            ICollection<ContinueStatement> continues = new List<ContinueStatement>();
            BlockStatement containingBlock = GetOuterBlock(labeledStatement);

            int labelIndex = containingBlock.Statements.IndexOf(labeledStatement);
            int gotoIndex = containingBlock.Statements.IndexOf(gotoStatement);
            BlockStatement loopBody = CollectStatements(labelIndex, gotoIndex, containingBlock);

            /// Checks if the gotoStatement is inside a loop/switch statement.
            /// If so, then some breaks might be enclosed in the new do-while. Additional breaks need to be included in this case
            if (ShouldCheck(gotoStatement))
            {
                ContinueAndBreakFinder finder = new ContinueAndBreakFinder();
                finder.Visit(loopBody);
                breaks = finder.Breaks;
                continues = finder.Continues;
            }

            /// Add condition = true before each enclosed break statement.
            foreach (BreakStatement statement in breaks)
            {
                BlockStatement breakBlock = GetOuterBlock(statement);
                int breakIndex = breakBlock.Statements.IndexOf(statement);
                BinaryExpression assign =
                    new BinaryExpression(BinaryOperator.Assign, new VariableReferenceExpression(breakVariable, null), GetLiteralExpression(true), typeSystem, null);
                usedBreakVariable = true;
                ExpressionStatement assignment = new ExpressionStatement(assign);
                breakBlock.AddStatementAt(breakIndex, assignment);
            }

            /// Add condition = true before each enclosed continue statement
            /// and replace the continue statement with break statement
            foreach (ContinueStatement statement in continues)
            {
                BlockStatement continueBlock = GetOuterBlock(statement);
                int continueIndex = continueBlock.Statements.IndexOf(statement);
                BinaryExpression assign =
                    new BinaryExpression(BinaryOperator.Assign, new VariableReferenceExpression(continueVariable, null), GetLiteralExpression(true), typeSystem, null);
                usedContinueVariable = true;
                ExpressionStatement assignment = new ExpressionStatement(assign);
                continueBlock.Statements.RemoveAt(continueIndex);
                continueBlock.AddStatementAt(continueIndex, new BreakStatement(null));
                continueBlock.AddStatementAt(continueIndex, assignment);
            }

            /// Replace the goto with do-while loop.
            DoWhileStatement doWhileLoop = new DoWhileStatement(gotoStatement.Condition, loopBody);
            gotoIndex = containingBlock.Statements.IndexOf(gotoStatement);
            containingBlock.AddStatementAt(gotoIndex, doWhileLoop);
            containingBlock.Statements.Remove(gotoStatement);

            if (breaks.Count > 0)
            {
                /// Add condition for the outer break, accounting for the enclosed breaks.
                AddBreakContinueConditional(gotoIndex + 1, containingBlock, new BreakStatement(null), breakVariable);//gotoindex + 1 should be the place after the newly inserted do-while loop
            }
            if (continues.Count > 0)
            {
                /// Add condition for the outer break, accounting for the enclosed continues.
                AddBreakContinueConditional(gotoIndex + 1, containingBlock, new ContinueStatement(null), continueVariable);
            }
        }
        private bool CheckIfStatementStructure(IfStatement theIf)
        {
            if (theIf.Else == null && theIf.Condition.CodeNodeType == CodeNodeType.BinaryExpression)
            {
                if (theIf.Then.Statements.Count == 1 && theIf.Then.Statements[0].CodeNodeType == CodeNodeType.ExpressionStatement)
                {
                    this.cachingVersion = DelegateCachingVersion.V1;
                    return true;
                }
                else if (theIf.Then.Statements.Count == 3)
                {
                    ExpressionStatement first = theIf.Then.Statements[0] as ExpressionStatement;
                    if (first == null)
                    {
                        return false;
                    }

                    BinaryExpression firstBinary = first.Expression as BinaryExpression;
                    if (firstBinary == null)
                    {
                        return false;
                    }

                    if (!firstBinary.IsAssignmentExpression ||
                        firstBinary.Left.CodeNodeType != CodeNodeType.VariableReferenceExpression ||
                        firstBinary.Right.CodeNodeType != CodeNodeType.VariableReferenceExpression ||
                        !initializationsToRemove.ContainsKey((firstBinary.Right as VariableReferenceExpression).Variable))
                    {
                        return false;
                    }

                    if (theIf.Then.Statements[1].CodeNodeType != CodeNodeType.ExpressionStatement)
                    {
                        return false;
                    }

                    ExpressionStatement third = theIf.Then.Statements[2] as ExpressionStatement;
                    if (third == null)
                    {
                        return false;
                    }

                    BinaryExpression thirdBinary = third.Expression as BinaryExpression;
                    if (thirdBinary == null)
                    {
                        return false;
                    }

                    if (!thirdBinary.IsAssignmentExpression ||
                        thirdBinary.Left.CodeNodeType != CodeNodeType.FieldReferenceExpression ||
                        thirdBinary.Right.CodeNodeType != CodeNodeType.VariableReferenceExpression ||
                        !initializationsToRemove.ContainsKey((thirdBinary.Right as VariableReferenceExpression).Variable))
                    {
                        return false;
                    }

                    this.cachingVersion = DelegateCachingVersion.V2;
                    return true;
                }
            }

            return false;
        }
        private bool CheckVariableCaching(IfStatement theIf)
        {
            BinaryExpression theCondition = theIf.Condition as BinaryExpression;

            if (theCondition.Operator != BinaryOperator.ValueEquality || theCondition.Right.CodeNodeType != CodeNodeType.LiteralExpression ||
                (theCondition.Right as LiteralExpression).Value != null)
            {
                return false;
            }

            VariableReference theVariable = (theCondition.Left as VariableReferenceExpression).Variable;
            if (!initializationsToRemove.ContainsKey(theVariable))
            {
                return false;
            }

            int theAssignExpressionIndex = this.cachingVersion == DelegateCachingVersion.V1 ? 0 : 1;
            BinaryExpression theAssignExpression = (theIf.Then.Statements[theAssignExpressionIndex] as ExpressionStatement).Expression as BinaryExpression;
            if (theAssignExpression == null || !theAssignExpression.IsAssignmentExpression ||
                theAssignExpression.Left.CodeNodeType != CodeNodeType.VariableReferenceExpression ||
                (theAssignExpression.Left as VariableReferenceExpression).Variable != theVariable)
            {
                return false;
            }

            if (variablesToRemove.ContainsKey(theVariable))
            {
                throw new Exception("A caching variable cannot be assigned more than once.");
            }

            //Slow checks
            TypeDefinition variableTypeDef = theVariable.VariableType.Resolve();
            if (variableTypeDef == null || variableTypeDef.BaseType == null || variableTypeDef.BaseType.FullName != "System.MulticastDelegate")
            {
                return false;
            }

            variablesToRemove[theVariable] = theAssignExpression.Right;
            return true;
        }
        /// <summary>
        /// Eliminates the goto statement by inserting if statement. For more details, see "Chapter 2.1 - Goto statement is before label statement" in
        /// <see cref="Taming Control Flow A Structured Approach to Eliminating Goto Statements.pdf"/>.
        /// </summary>
        /// <param name="gotoStatement">The goto statement to be removed.</param>
        /// <param name="labeledStatement">The corresponding labeled statement.</param>
        private void EliminateViaIf(IfStatement gotoStatement, Statement labeledStatement)
        {
            BlockStatement containingBlock = labeledStatement.Parent as BlockStatement;//should not be null at this point

            int startingIndex = containingBlock.Statements.IndexOf(gotoStatement);
            int endingIndex = containingBlock.Statements.IndexOf(labeledStatement);
            if (startingIndex == endingIndex - 1)
            {
                //case:                 changed to:
                //if(condition)         -----
                //{                     -----
                //  goto: label1;       -----
                //}                     -----
                //label1: stmt1;        label1: stmt1;
                containingBlock.Statements.RemoveAt(startingIndex);
                return;
            }

            BlockStatement newThenBlock = CollectStatements(startingIndex + 1, endingIndex, containingBlock);
            Expression condition = Negator.Negate(gotoStatement.Condition, typeSystem);
            while (newThenBlock.Statements[0] is IfStatement)
            {
                //flattens ifs , for instance
                //case:                     to:
                //if (a)                    if(a)
                //{                         {
                //    if (a)                    statement1;
                //    {                         stuff
                //        statement1;           statement2;
                //        stuff                 ...
                //    }                     }
                //    statement2
                //    ...
                //}
                IfStatement firstStatement = newThenBlock.Statements[0] as IfStatement;
                if (AreEqual(firstStatement.Condition, condition) && firstStatement.Else == null)
                {
                    newThenBlock.Statements.RemoveAt(0); //remove the if

                    for (int i = 0; i < firstStatement.Then.Statements.Count; i++)
                    {
                        newThenBlock.AddStatement(firstStatement.Then.Statements[i]);
                    }
                }
                else
                {
                    break;
                }
            }
            gotoStatement.Then = newThenBlock;
            gotoStatement.Condition = condition;
        }
        private bool CheckFieldCaching(IfStatement theIf)
        {
            BinaryExpression theCondition = theIf.Condition as BinaryExpression;

            if (theCondition.Operator != BinaryOperator.ValueEquality || theCondition.Right.CodeNodeType != CodeNodeType.LiteralExpression ||
                (theCondition.Right as LiteralExpression).Value != null)
            {
                return false;
            }

            FieldDefinition theFieldDef = (theCondition.Left as FieldReferenceExpression).Field.Resolve();
            if (theFieldDef == null || !theFieldDef.IsStatic || !theFieldDef.IsPrivate)
            {
                return false;
            }

            BinaryExpression theAssignExpression = (theIf.Then.Statements[0] as ExpressionStatement).Expression as BinaryExpression;
            if (theAssignExpression == null || !theAssignExpression.IsAssignmentExpression ||
                theAssignExpression.Left.CodeNodeType != CodeNodeType.FieldReferenceExpression ||
                (theAssignExpression.Left as FieldReferenceExpression).Field.Resolve() != theFieldDef)
            {
                return false;
            }

            if (fieldsToRemove.ContainsKey(theFieldDef))
            {
                throw new Exception("A caching field cannot be assigned more than once.");
            }

            //Slow checks
            if (!theFieldDef.IsCompilerGenerated())
            {
                return false;
            }

            TypeDefinition fieldTypeDef = theFieldDef.FieldType.Resolve();
            if (fieldTypeDef == null || fieldTypeDef.BaseType == null || fieldTypeDef.BaseType.FullName != "System.MulticastDelegate")
            {
                return false;
            }

            fieldsToRemove[theFieldDef] = theAssignExpression.Right;
            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));
                }
            }
        }
 /// <summary>
 /// Gets the parent of the <paramref name="labeledStatement"/>, that is on the same level as the <paramref name="gotoStatement"/>.
 /// </summary>
 /// <param name="labeledStatement">The labeled statement.</param>
 /// <param name="gotoStatement">The goto statement.</param>
 /// <returns>Returns the parent of the labeled statement that is on the same level as the goto statement.</returns>
 private Statement GetSameLevelParent(Statement labeledStatement, IfStatement gotoStatement)
 {
     ///This method must be used only when the goto statement is in the same block with a construct on the parent chain of the labeled statement.
     Stack<Statement> stack = GetParentsChain(labeledStatement);
     BlockStatement gotoParent = gotoStatement.Parent as BlockStatement;
     while (!gotoParent.Statements.Contains(stack.Peek()))
     {
         stack.Pop();
     }
     return stack.Peek();
 }
        /// <summary>
        /// Performs lifting operation on the goto statement. For more information, see
        /// Chapter "2.2.3 Goto-lifting Transformation" in <see cref="Taming Control Flow A Structured Approach to Eliminating Goto Statements.pdf"/>.
        /// </summary>
        /// <param name="gotoStatement">The goto to be lifted.</param>
        /// <param name="labelContainingStatement">The statement, containing the target of the goto.</param>
        /// <param name="label">The label of the target.</param>
        private void LiftGoto(IfStatement gotoStatement, Statement labelContainingStatement, string label)
        {
            BlockStatement containingBlock = GetOuterBlock(gotoStatement);
            VariableReferenceExpression variableEx = new VariableReferenceExpression(GetLabelVariable(label), null);

            ExtractConditionIntoVariable(variableEx, gotoStatement, containingBlock);

            /// Extract the do-while loop body from the current block
            int gotoIndex = containingBlock.Statements.IndexOf(gotoStatement);
            int labelIndex = containingBlock.Statements.IndexOf(labelContainingStatement);
            BlockStatement loopBody = CollectStatements(labelIndex, gotoIndex, containingBlock);

            /// Add the goto statement as the first one in the new do-while loop
            loopBody.AddStatementAt(0, gotoStatement);

            /// Remove the goto from its old parent block and attach the do-while loop on its place
            gotoIndex = containingBlock.Statements.IndexOf(gotoStatement);
            containingBlock.Statements.Remove(gotoStatement);
            DoWhileStatement doWhileLoop = new DoWhileStatement(gotoStatement.Condition.CloneExpressionOnly(), loopBody);
            containingBlock.AddStatementAt(gotoIndex, doWhileLoop);
        }
        /// <summary>
        /// Performs a move-in transformation as described in Chapter 2.2.2 in <see cref="Taming Control Flow A Structured Approach to Eliminating Goto Statements.pdf"/>.
        /// </summary>
        /// <param name="gotoStatement">The goto statement to be moved in.</param>
        /// <param name="targetStatement">The statement that the goto will move in.</param>
        /// <param name="label">The target label.</param>
        private void MoveIn(IfStatement gotoStatement, Statement targetStatement, string label)
        {
            /// Preprocessing.
            BlockStatement containingBlock = gotoStatement.Parent as BlockStatement;
            VariableReferenceExpression conditionVar = new VariableReferenceExpression(GetLabelVariable(label), null);

            /// Create the statement conditionVariable = originalCondition;
            /// Add the assigning statement before gotoStatement and replace originalCondition with conditionVariable
            ExtractConditionIntoVariable(conditionVar.CloneExpressionOnly() as VariableReferenceExpression, gotoStatement, containingBlock);

            /// Collect the statements between the goto jump and the target statement.
            int gotoIndex = containingBlock.Statements.IndexOf(gotoStatement);
            int targetIndex = containingBlock.Statements.IndexOf(targetStatement);
            BlockStatement thenBlock = CollectStatements(gotoIndex + 1, targetIndex, containingBlock);

            /// Create the new if.
            IfStatement outerIfStatement =
                new IfStatement(new UnaryExpression(UnaryOperator.LogicalNot, conditionVar.CloneExpressionOnly(), null), thenBlock, null);

            /// Replace the old goto with the new if statement.
            if (outerIfStatement.Then.Statements.Count > 0)
            {
                containingBlock.AddStatementAt(gotoIndex, outerIfStatement);
            }
            containingBlock.Statements.Remove(gotoStatement);

            /// At this point the original goto statement is completely detached from the AST. It must be reattached as the first statement in the target.
            if (targetStatement is DoWhileStatement)
            {
                /// Loops with more than one entry can be created only by this step, so the do-while loops is the only one
                /// that must be considered.
                (targetStatement as DoWhileStatement).Body.AddStatementAt(0, gotoStatement);
            }
            else if (targetStatement is IfStatement)
            {
                /// If statements with more than one entry to then/else blocks can be created only by this step, so that's why
                /// the only case that must be considered is the case when the target is in the then block.
                IfStatement targetIf = targetStatement as IfStatement;
                targetIf.Condition = UpdateCondition(targetIf.Condition, conditionVar.CloneExpressionOnly() as VariableReferenceExpression); /// This greatly depends on the short-circut evaluation.
                targetIf.Then.AddStatementAt(0, gotoStatement);
            }
            else if (targetStatement is SwitchCase)
            {
                MoveInCase(gotoStatement, targetStatement as SwitchCase, label);
            }
            else if (targetStatement is WhileStatement)
            {
                /// This case should not be reachable.
                WhileStatement @while = targetStatement as WhileStatement;
                @while.Body.AddStatementAt(0, gotoStatement);
                @while.Condition = UpdateCondition(@while.Condition, conditionVar.CloneExpressionOnly() as VariableReferenceExpression);
            }
            else
            {
                throw new NotSupportedException("Unsupported target statement for goto jump.");
            }
        }
		public override void VisitIfStatement(IfStatement node)
		{
			WriteKeyword(KeyWordWriter.If);
			WriteSpace();
			WriteBetweenParenthesis(node.Condition);
			if (KeyWordWriter.Then != null)
			{
				WriteSpace();
				WriteKeyword(KeyWordWriter.Then);
			}
			WriteLine();

			Visit(node.Then);

			if (node.Else == null)
			{
				WriteSpecialEndBlock(KeyWordWriter.If);
				return;
			}

			WriteLine();
			WriteKeyword(KeyWordWriter.Else);
			WriteLine();

			Visit(node.Else);
			WriteSpecialEndBlock(KeyWordWriter.If);
		}
        /// <summary>
        /// Performs a move out operation on the goto statement. For more information see
        /// Chapter 2.2.1 "Outward-movement Transformations"
        /// </summary>
        /// <param name="gotoStatement"></param>
        /// <param name="label"></param>
        private void MoveOut(IfStatement gotoStatement, string label)
        {
            /// Preprocessing.
            BlockStatement containingBlock = gotoStatement.Parent as BlockStatement;
            BlockStatement outerBlock = GetOuterBlock(containingBlock);
            VariableReferenceExpression conditionVar = new VariableReferenceExpression(GetLabelVariable(label), null);

            ExtractConditionIntoVariable(conditionVar.CloneExpressionOnly() as VariableReferenceExpression, gotoStatement, containingBlock);

            Statement oldEnclosingStatement = containingBlock.Parent;
            if (oldEnclosingStatement is SwitchCase)
            {
                oldEnclosingStatement = oldEnclosingStatement.Parent;
            }
            if (containingBlock.Parent is SwitchCase || containingBlock.Parent is WhileStatement || containingBlock.Parent is DoWhileStatement || containingBlock.Parent is ForStatement
                || containingBlock.Parent is ForEachStatement)
            {
                /// Then we can exit using break.
                /// Create the if - break.
                BlockStatement thenBlock = new BlockStatement();
                thenBlock.AddStatement(new BreakStatement(null));  //might have to keep track of brakes
                IfStatement breakIf = new IfStatement(conditionVar.CloneExpressionOnly(), thenBlock, null);

                /// Replace the original goto
                int gotoIndex = containingBlock.Statements.IndexOf(gotoStatement);
                containingBlock.Statements.Remove(gotoStatement);
                containingBlock.AddStatementAt(gotoIndex, breakIf);
            }
            else if (containingBlock.Parent is IfStatement || containingBlock.Parent is TryStatement || containingBlock.Parent is IfElseIfStatement)
            {
                /// Then we can exit via introducing another condition.
                int gotoIndex = containingBlock.Statements.IndexOf(gotoStatement);
                int index = gotoIndex + 1;
                BlockStatement thenBlock = new BlockStatement();
                while (index < containingBlock.Statements.Count)
                {
                    thenBlock.AddStatement(containingBlock.Statements[index]);
                    containingBlock.Statements.RemoveAt(index);
                }
                UnaryExpression condition = new UnaryExpression(UnaryOperator.LogicalNot, conditionVar.CloneExpressionOnly(), null);
                IfStatement innerIf = new IfStatement(condition, thenBlock, null);

                /// At this point the goto statement should be the last one in the block.
                /// Simply replace it with the new if.
                containingBlock.Statements.Remove(gotoStatement);
                /// If the then block is empty, the if should not be added.
                if (innerIf.Then.Statements.Count != 0)
                {
                    containingBlock.AddStatement(innerIf);
                }
            }
            else
            {
                throw new ArgumentOutOfRangeException("Goto statement can not leave this parent construct.");
            }

            /// Add the goto statement after the construct.
            /// The goto statement shoud be detached from the AST at this point.
            outerBlock.AddStatementAt(outerBlock.Statements.IndexOf(oldEnclosingStatement) + 1, gotoStatement);
        }