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); }