public IEnumerable <CodeAction> GetActions(RefactoringContext context) { var foreachStatement = GetForeachStatement(context); if (foreachStatement == null) { yield break; } yield return(new CodeAction(context.TranslateString("Convert 'foreach' loop to 'for'"), script => { var result = context.Resolve(foreachStatement.InExpression); var countProperty = GetCountProperty(result.Type); // TODO: use another variable name if 'i' is already in use var initializer = new VariableDeclarationStatement(new PrimitiveType("int"), "i", new PrimitiveExpression(0)); var id1 = new IdentifierExpression("i"); var id2 = id1.Clone(); var id3 = id1.Clone(); var variableDeclarationStatement = new VariableDeclarationStatement( foreachStatement.VariableType.Clone(), foreachStatement.VariableName, new IndexerExpression(foreachStatement.InExpression.Clone(), id3) ); var forStatement = new ForStatement() { Initializers = { initializer }, Condition = new BinaryOperatorExpression(id1, BinaryOperatorType.LessThan, new MemberReferenceExpression(foreachStatement.InExpression.Clone(), countProperty)), Iterators = { new ExpressionStatement(new UnaryOperatorExpression(UnaryOperatorType.PostIncrement, id2)) }, EmbeddedStatement = new BlockStatement { variableDeclarationStatement } }; if (foreachStatement.EmbeddedStatement is BlockStatement) { variableDeclarationStatement.Remove(); var oldBlock = (BlockStatement)foreachStatement.EmbeddedStatement.Clone(); if (oldBlock.Statements.Any()) { oldBlock.Statements.InsertBefore(oldBlock.Statements.First(), variableDeclarationStatement); } else { oldBlock.Statements.Add(variableDeclarationStatement); } forStatement.EmbeddedStatement = oldBlock; } else { forStatement.EmbeddedStatement.AddChild(foreachStatement.EmbeddedStatement.Clone(), BlockStatement.StatementRole); } script.Replace(foreachStatement, forStatement); script.Link(initializer.Variables.First().NameToken, id1, id2, id3); })); }
public override TNode VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, object data) { var variableInitializer = variableDeclarationStatement.Variables.Single(); string name = variableInitializer.Name; var astType = variableDeclarationStatement.Type; variableDeclarationStatement.Remove(); AddVariable(variableDeclarationStatement, name, astType); _block.Add(variableDeclarationStatement); return(base.VisitVariableDeclarationStatement(variableDeclarationStatement, data)); }
public IEnumerable<CodeAction> GetActions(RefactoringContext context) { var foreachStatement = GetForeachStatement(context); if (foreachStatement == null) { yield break; } yield return new CodeAction(context.TranslateString("Convert 'foreach' loop to 'for'"), script => { var result = context.Resolve(foreachStatement.InExpression); var countProperty = GetCountProperty(result.Type); // TODO: use another variable name if 'i' is already in use var initializer = new VariableDeclarationStatement(new PrimitiveType("int"), "i", new PrimitiveExpression(0)); var id1 = new IdentifierExpression("i"); var id2 = id1.Clone(); var id3 = id1.Clone(); var variableDeclarationStatement = new VariableDeclarationStatement( foreachStatement.VariableType.Clone(), foreachStatement.VariableName, new IndexerExpression(foreachStatement.InExpression.Clone(), id3) ); var forStatement = new ForStatement() { Initializers = { initializer }, Condition = new BinaryOperatorExpression (id1, BinaryOperatorType.LessThan, new MemberReferenceExpression (foreachStatement.InExpression.Clone (), countProperty)), Iterators = { new ExpressionStatement (new UnaryOperatorExpression (UnaryOperatorType.PostIncrement, id2)) }, EmbeddedStatement = new BlockStatement { variableDeclarationStatement } }; if (foreachStatement.EmbeddedStatement is BlockStatement) { variableDeclarationStatement.Remove(); var oldBlock = (BlockStatement)foreachStatement.EmbeddedStatement.Clone(); if (oldBlock.Statements.Any()) { oldBlock.Statements.InsertBefore(oldBlock.Statements.First(), variableDeclarationStatement); } else { oldBlock.Statements.Add(variableDeclarationStatement); } forStatement.EmbeddedStatement = oldBlock; } else { forStatement.EmbeddedStatement.AddChild (foreachStatement.EmbeddedStatement.Clone (), BlockStatement.StatementRole); } script.Replace (foreachStatement, forStatement); script.Link (initializer.Variables.First ().NameToken, id1, id2, id3); }); }
public override void VisitVariableDeclarationStatement( VariableDeclarationStatement variableDeclarationStatement) { base.VisitVariableDeclarationStatement(variableDeclarationStatement); if (variableDeclarationStatement.Variables.Count != 1) return; var variable = variableDeclarationStatement.Variables.First(); switch (variable.Name) { case "__cx": case "__cy": case "__cz": case "__cwidth": case "__cheight": case "__cdepth": this.m_CInitializers[variable.Name] = variable.Initializer; variableDeclarationStatement.Remove(); break; } }
public override object VisitBlockStatement(BlockStatement blockStatement, object data) { int numberOfVariablesOutsideBlock = currentlyUsedVariableNames.Count; base.VisitBlockStatement(blockStatement, data); foreach (ExpressionStatement stmt in blockStatement.Statements.OfType <ExpressionStatement>().ToArray()) { Match displayClassAssignmentMatch = displayClassAssignmentPattern.Match(stmt); if (!displayClassAssignmentMatch.Success) { continue; } ILVariable variable = displayClassAssignmentMatch.Get <AstNode>("variable").Single().Annotation <ILVariable>(); if (variable == null) { continue; } TypeDefinition type = variable.Type.ResolveWithinSameModule(); if (!IsPotentialClosure(context, type)) { continue; } if (displayClassAssignmentMatch.Get <AstType>("type").Single().Annotation <TypeReference>().ResolveWithinSameModule() != type) { continue; } // Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses: bool ok = true; foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>()) { if (identExpr.Identifier == variable.Name && identExpr != displayClassAssignmentMatch.Get("variable").Single()) { //check if it a cross reference to another generated delegate class's member if (identExpr.Parent is AssignmentExpression) { if ((identExpr.Parent as AssignmentExpression).Left is MemberReferenceExpression ) { MemberReferenceExpression tleft = (MemberReferenceExpression)(identExpr.Parent as AssignmentExpression).Left; ILVariable v = tleft.Target.Annotation <ILVariable>(); if (v != null) { TypeDefinition vtype = v.Type.ResolveWithinSameModule(); if (vtype.IsNested && IsPotentialClosure(context, vtype)) { Console.WriteLine(identExpr.Parent.ToString() + " cross reference by delegate should be ok"); continue; } } } } if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation <FieldReference>() != null)) { ok = false; break; } } } if (!ok) { continue; } Dictionary <FieldReference, AstNode> dict = new Dictionary <FieldReference, AstNode>(); // Delete the variable declaration statement: VariableDeclarationStatement displayClassVarDecl = PatternStatementTransform.FindVariableDeclaration(stmt, variable.Name); if (displayClassVarDecl != null) { displayClassVarDecl.Remove(); } // Delete the assignment statement: AstNode cur = stmt.NextSibling; stmt.Remove(); // Delete any following statements as long as they assign parameters to the display class BlockStatement rootBlock = blockStatement.Ancestors.OfType <BlockStatement>().LastOrDefault() ?? blockStatement; List <ILVariable> parameterOccurrances = rootBlock.Descendants.OfType <IdentifierExpression>() .Select(n => n.Annotation <ILVariable>()).Where(p => p != null && p.IsParameter).ToList(); AstNode next; for (; cur != null; cur = next) { next = cur.NextSibling; // Test for the pattern: // "variableName.MemberName = right;" ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement( new AssignmentExpression( new NamedNode("left", new MemberReferenceExpression { Target = new IdentifierExpression(variable.Name), MemberName = Pattern.AnyString }), new AnyNode("right") ) ); Match m = closureFieldAssignmentPattern.Match(cur); if (m.Success) { FieldDefinition fieldDef = m.Get <MemberReferenceExpression>("left").Single().Annotation <FieldReference>().ResolveWithinSameModule(); AstNode right = m.Get <AstNode>("right").Single(); bool isParameter = false; bool isDisplayClassParentPointerAssignment = false; if (right is ThisReferenceExpression) { isParameter = true; } else if (right is IdentifierExpression) { // handle parameters only if the whole method contains no other occurrence except for 'right' ILVariable v = right.Annotation <ILVariable>(); isParameter = v.IsParameter && parameterOccurrances.Count(c => c == v) == 1; if (!isParameter && IsPotentialClosure(context, v.Type.ResolveWithinSameModule())) { // parent display class within the same method // (closure2.localsX = closure1;) isDisplayClassParentPointerAssignment = true; } } else if (right is MemberReferenceExpression) { // copy of parent display class reference from an outer lambda // closure2.localsX = this.localsY MemberReferenceExpression mre = m.Get <MemberReferenceExpression>("right").Single(); do { // descend into the targets of the mre as long as the field types are closures FieldDefinition fieldDef2 = mre.Annotation <FieldReference>().ResolveWithinSameModule(); if (fieldDef2 == null || !IsPotentialClosure(context, fieldDef2.FieldType.ResolveWithinSameModule())) { break; } // if we finally get to a this reference, it's copying a display class parent pointer if (mre.Target is ThisReferenceExpression) { isDisplayClassParentPointerAssignment = true; } mre = mre.Target as MemberReferenceExpression; } while (mre != null); } if (isParameter || isDisplayClassParentPointerAssignment) { dict[fieldDef] = right; cur.Remove(); } else { break; } } else { //why need to break? continue to match should be ok //break; } } // Now create variables for all fields of the display class (except for those that we already handled as parameters) List <Tuple <AstType, ILVariable> > variablesToDeclare = new List <Tuple <AstType, ILVariable> >(); foreach (FieldDefinition field in type.Fields) { if (field.IsStatic) { continue; // skip static fields } if (dict.ContainsKey(field)) // skip field if it already was handled as parameter { continue; } string capturedVariableName = field.Name; if (capturedVariableName.StartsWith("$VB$Local_", StringComparison.Ordinal) && capturedVariableName.Length > 10) { capturedVariableName = capturedVariableName.Substring(10); } EnsureVariableNameIsAvailable(blockStatement, capturedVariableName); currentlyUsedVariableNames.Add(capturedVariableName); ILVariable ilVar = new ILVariable { IsGenerated = true, Name = capturedVariableName, Type = field.FieldType, }; variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), ilVar)); dict[field] = new IdentifierExpression(capturedVariableName).WithAnnotation(ilVar); } // Now figure out where the closure was accessed and use the simpler replacement expression there: foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>()) { if (identExpr.Identifier == variable.Name) { if (!(identExpr.Parent is MemberReferenceExpression)) { //will delete by the next round of the cross reference delegate class continue; } MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent; AstNode replacement; if (dict.TryGetValue(mre.Annotation <FieldReference>().ResolveWithinSameModule(), out replacement)) { mre.ReplaceWith(replacement.Clone()); } } } // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works): Statement insertionPoint = blockStatement.Statements.FirstOrDefault(); foreach (var tuple in variablesToDeclare) { var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2.Name); newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation()); newVarDecl.Variables.Single().AddAnnotation(tuple.Item2); blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl); } } currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock); return(null); }
public IEnumerable <CodeAction> GetActions(RefactoringContext context) { var foreachStatement = GetForeachStatement(context); if (foreachStatement == null) { yield break; } var state = context.GetResolverStateBefore(foreachStatement.EmbeddedStatement); string name = GetName(state, VariableNames); if (name == null) // very unlikely, but just in case ... { yield break; } yield return(new CodeAction(context.TranslateString("Convert 'foreach' loop to 'for'"), script => { var result = context.Resolve(foreachStatement.InExpression); var countProperty = GetCountProperty(result.Type); // TODO: use another variable name if 'i' is already in use var initializer = new VariableDeclarationStatement(new PrimitiveType("int"), name, new PrimitiveExpression(0)); var id1 = new IdentifierExpression(name); var id2 = id1.Clone(); var id3 = id1.Clone(); var inExpression = foreachStatement.InExpression; Statement declarationStatement = null; if (inExpression is ObjectCreateExpression || inExpression is ArrayCreateExpression) { string listName = GetName(state, CollectionNames) ?? "col"; declarationStatement = new VariableDeclarationStatement( new PrimitiveType("var"), listName, inExpression.Clone() ); inExpression = new IdentifierExpression(listName); } var variableDeclarationStatement = new VariableDeclarationStatement( foreachStatement.VariableType.Clone(), foreachStatement.VariableName, new IndexerExpression(inExpression.Clone(), id3) ); var forStatement = new ForStatement() { Initializers = { initializer }, Condition = new BinaryOperatorExpression(id1, BinaryOperatorType.LessThan, new MemberReferenceExpression(inExpression.Clone(), countProperty)), Iterators = { new ExpressionStatement(new UnaryOperatorExpression(UnaryOperatorType.PostIncrement, id2)) }, EmbeddedStatement = new BlockStatement { variableDeclarationStatement } }; if (foreachStatement.EmbeddedStatement is BlockStatement) { variableDeclarationStatement.Remove(); var oldBlock = (BlockStatement)foreachStatement.EmbeddedStatement.Clone(); if (oldBlock.Statements.Any()) { oldBlock.Statements.InsertBefore(oldBlock.Statements.First(), variableDeclarationStatement); } else { oldBlock.Statements.Add(variableDeclarationStatement); } forStatement.EmbeddedStatement = oldBlock; } else { forStatement.EmbeddedStatement.AddChild(foreachStatement.EmbeddedStatement.Clone(), BlockStatement.StatementRole); } if (declarationStatement != null) { script.InsertBefore(foreachStatement, declarationStatement); } script.Replace(foreachStatement, forStatement); script.Link(initializer.Variables.First().NameToken, id1, id2, id3); }, foreachStatement)); }
public override IEnumerable <CodeAction> GetActions(RefactoringContext context) { bool hasIndexAccess; var foreachStatement = GetForeachStatement(context, out hasIndexAccess); if (foreachStatement == null || foreachStatement.EmbeddedStatement.IsNull) { yield break; } var state = context.GetResolverStateBefore(foreachStatement.EmbeddedStatement); string name = GetName(state, VariableNames); if (name == null) // very unlikely, but just in case ... { yield break; } yield return(new CodeAction(context.TranslateString("Convert 'foreach' loop to 'for'"), script => { var result = context.Resolve(foreachStatement.InExpression); var countProperty = GetCountProperty(result.Type); var inExpression = foreachStatement.InExpression; var initializer = hasIndexAccess ? new VariableDeclarationStatement(new PrimitiveType("int"), name, new PrimitiveExpression(0)) : new VariableDeclarationStatement(new SimpleType("var"), name, new InvocationExpression(new MemberReferenceExpression(inExpression.Clone(), "GetEnumerator"))); var id1 = new IdentifierExpression(name); var id2 = id1.Clone(); var id3 = id1.Clone(); Statement declarationStatement = null; if (inExpression is ObjectCreateExpression || inExpression is ArrayCreateExpression) { string listName = GetName(state, CollectionNames) ?? "col"; declarationStatement = new VariableDeclarationStatement( new PrimitiveType("var"), listName, inExpression.Clone() ); inExpression = new IdentifierExpression(listName); } var variableDeclarationStatement = new VariableDeclarationStatement( foreachStatement.VariableType.Clone(), foreachStatement.VariableName, hasIndexAccess ? (Expression) new IndexerExpression(inExpression.Clone(), id3) : new MemberReferenceExpression(id1, "Current") ); var forStatement = new ForStatement { Initializers = { initializer }, Condition = hasIndexAccess ? (Expression) new BinaryOperatorExpression(id1, BinaryOperatorType.LessThan, new MemberReferenceExpression(inExpression.Clone(), countProperty)) : new InvocationExpression(new MemberReferenceExpression(id2, "MoveNext")), EmbeddedStatement = new BlockStatement { variableDeclarationStatement } }; if (hasIndexAccess) { forStatement.Iterators.Add(new UnaryOperatorExpression(UnaryOperatorType.PostIncrement, id2)); } if (foreachStatement.EmbeddedStatement is BlockStatement) { variableDeclarationStatement.Remove(); var oldBlock = (BlockStatement)foreachStatement.EmbeddedStatement.Clone(); if (oldBlock.Statements.Any()) { oldBlock.Statements.InsertBefore(oldBlock.Statements.First(), variableDeclarationStatement); } else { oldBlock.Statements.Add(variableDeclarationStatement); } forStatement.EmbeddedStatement = oldBlock; } else { forStatement.EmbeddedStatement.AddChild(foreachStatement.EmbeddedStatement.Clone(), BlockStatement.StatementRole); } if (declarationStatement != null) { script.InsertBefore(foreachStatement, declarationStatement); } script.Replace(foreachStatement, forStatement); if (hasIndexAccess) { script.Link(initializer.Variables.First().NameToken, id1, id2, id3); } else { script.Link(initializer.Variables.First().NameToken, id1, id2); } }, foreachStatement)); if (!hasIndexAccess) { yield break; } yield return(new CodeAction(context.TranslateString("Convert 'foreach' loop to optimized 'for'"), script => { var result = context.Resolve(foreachStatement.InExpression); var countProperty = GetCountProperty(result.Type); var initializer = new VariableDeclarationStatement(new PrimitiveType("int"), name, new PrimitiveExpression(0)); var id1 = new IdentifierExpression(name); var id2 = id1.Clone(); var id3 = id1.Clone(); var inExpression = foreachStatement.InExpression; Statement declarationStatement = null; if (inExpression is ObjectCreateExpression || inExpression is ArrayCreateExpression) { string listName = GetName(state, CollectionNames) ?? "col"; declarationStatement = new VariableDeclarationStatement( new PrimitiveType("var"), listName, inExpression.Clone() ); inExpression = new IdentifierExpression(listName); } var variableDeclarationStatement = new VariableDeclarationStatement( foreachStatement.VariableType.Clone(), foreachStatement.VariableName, new IndexerExpression(inExpression.Clone(), id3) ); string optimizedUpperBound = GetBoundName(inExpression) + countProperty; initializer.Variables.Add(new VariableInitializer(optimizedUpperBound, new MemberReferenceExpression(inExpression.Clone(), countProperty))); var forStatement = new ForStatement { Initializers = { initializer }, Condition = new BinaryOperatorExpression(id1, BinaryOperatorType.LessThan, new IdentifierExpression(optimizedUpperBound)), Iterators = { new UnaryOperatorExpression(UnaryOperatorType.PostIncrement, id2) }, EmbeddedStatement = new BlockStatement { variableDeclarationStatement } }; if (foreachStatement.EmbeddedStatement is BlockStatement) { variableDeclarationStatement.Remove(); var oldBlock = (BlockStatement)foreachStatement.EmbeddedStatement.Clone(); if (oldBlock.Statements.Any()) { oldBlock.Statements.InsertBefore(oldBlock.Statements.First(), variableDeclarationStatement); } else { oldBlock.Statements.Add(variableDeclarationStatement); } forStatement.EmbeddedStatement = oldBlock; } else { forStatement.EmbeddedStatement.AddChild(foreachStatement.EmbeddedStatement.Clone(), BlockStatement.StatementRole); } if (declarationStatement != null) { script.InsertBefore(foreachStatement, declarationStatement); } script.Replace(foreachStatement, forStatement); script.Link(initializer.Variables.First().NameToken, id1, id2, id3); }, foreachStatement)); }
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) { bool hasIndexAccess; var foreachStatement = GetForeachStatement(context, out hasIndexAccess); if (foreachStatement == null || foreachStatement.EmbeddedStatement == null) yield break; var state = context.GetResolverStateBefore (foreachStatement.EmbeddedStatement); string name = GetName(state, VariableNames); if (name == null) // very unlikely, but just in case ... yield break; yield return new CodeAction(context.TranslateString("Convert 'foreach' loop to 'for'"), script => { var result = context.Resolve(foreachStatement.InExpression); var countProperty = GetCountProperty(result.Type); var inExpression = foreachStatement.InExpression; var initializer = hasIndexAccess ? new VariableDeclarationStatement(new PrimitiveType("int"), name, new PrimitiveExpression(0)) : new VariableDeclarationStatement(new SimpleType("var"), name, new InvocationExpression(new MemberReferenceExpression (inExpression.Clone (), "GetEnumerator"))); var id1 = new IdentifierExpression(name); var id2 = id1.Clone(); var id3 = id1.Clone(); Statement declarationStatement = null; if (inExpression is ObjectCreateExpression || inExpression is ArrayCreateExpression) { string listName = GetName(state, CollectionNames) ?? "col"; declarationStatement = new VariableDeclarationStatement ( new PrimitiveType ("var"), listName, inExpression.Clone () ); inExpression = new IdentifierExpression (listName); } var variableDeclarationStatement = new VariableDeclarationStatement( foreachStatement.VariableType.Clone(), foreachStatement.VariableName, hasIndexAccess ? (Expression)new IndexerExpression(inExpression.Clone(), id3) : new MemberReferenceExpression(id1, "Current") ); var forStatement = new ForStatement { Initializers = { initializer }, Condition = hasIndexAccess ? (Expression)new BinaryOperatorExpression (id1, BinaryOperatorType.LessThan, new MemberReferenceExpression (inExpression.Clone (), countProperty)) : new InvocationExpression(new MemberReferenceExpression (id2, "MoveNext")), EmbeddedStatement = new BlockStatement { variableDeclarationStatement } }; if (hasIndexAccess) forStatement.Iterators.Add(new UnaryOperatorExpression (UnaryOperatorType.PostIncrement, id2)); if (foreachStatement.EmbeddedStatement is BlockStatement) { variableDeclarationStatement.Remove(); var oldBlock = (BlockStatement)foreachStatement.EmbeddedStatement.Clone(); if (oldBlock.Statements.Any()) { oldBlock.Statements.InsertBefore(oldBlock.Statements.First(), variableDeclarationStatement); } else { oldBlock.Statements.Add(variableDeclarationStatement); } forStatement.EmbeddedStatement = oldBlock; } else { forStatement.EmbeddedStatement.AddChild (foreachStatement.EmbeddedStatement.Clone (), BlockStatement.StatementRole); } if (declarationStatement != null) script.InsertBefore (foreachStatement, declarationStatement); script.Replace (foreachStatement, forStatement); if (hasIndexAccess) { script.Link (initializer.Variables.First ().NameToken, id1, id2, id3); } else { script.Link (initializer.Variables.First ().NameToken, id1, id2); } }, foreachStatement); if (!hasIndexAccess) yield break; yield return new CodeAction(context.TranslateString("Convert 'foreach' loop to optimized 'for'"), script => { var result = context.Resolve(foreachStatement.InExpression); var countProperty = GetCountProperty(result.Type); var initializer = new VariableDeclarationStatement(new PrimitiveType("int"), name, new PrimitiveExpression(0)); var id1 = new IdentifierExpression(name); var id2 = id1.Clone(); var id3 = id1.Clone(); var inExpression = foreachStatement.InExpression; Statement declarationStatement = null; if (inExpression is ObjectCreateExpression || inExpression is ArrayCreateExpression) { string listName = GetName(state, CollectionNames) ?? "col"; declarationStatement = new VariableDeclarationStatement ( new PrimitiveType ("var"), listName, inExpression.Clone () ); inExpression = new IdentifierExpression (listName); } var variableDeclarationStatement = new VariableDeclarationStatement( foreachStatement.VariableType.Clone(), foreachStatement.VariableName, new IndexerExpression(inExpression.Clone(), id3) ); string optimizedUpperBound = GetBoundName(inExpression) + countProperty; initializer.Variables.Add(new VariableInitializer(optimizedUpperBound, new MemberReferenceExpression (inExpression.Clone (), countProperty))); var forStatement = new ForStatement { Initializers = { initializer }, Condition = new BinaryOperatorExpression (id1, BinaryOperatorType.LessThan, new IdentifierExpression(optimizedUpperBound)), Iterators = { new UnaryOperatorExpression (UnaryOperatorType.PostIncrement, id2) }, EmbeddedStatement = new BlockStatement { variableDeclarationStatement } }; if (foreachStatement.EmbeddedStatement is BlockStatement) { variableDeclarationStatement.Remove(); var oldBlock = (BlockStatement)foreachStatement.EmbeddedStatement.Clone(); if (oldBlock.Statements.Any()) { oldBlock.Statements.InsertBefore(oldBlock.Statements.First(), variableDeclarationStatement); } else { oldBlock.Statements.Add(variableDeclarationStatement); } forStatement.EmbeddedStatement = oldBlock; } else { forStatement.EmbeddedStatement.AddChild (foreachStatement.EmbeddedStatement.Clone (), BlockStatement.StatementRole); } if (declarationStatement != null) script.InsertBefore (foreachStatement, declarationStatement); script.Replace (foreachStatement, forStatement); script.Link (initializer.Variables.First ().NameToken, id1, id2, id3); }, foreachStatement); }
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) { var foreachStatement = GetForeachStatement(context); if (foreachStatement == null) { yield break; } var state = context.GetResolverStateBefore (foreachStatement.EmbeddedStatement); string name = GetName(state, VariableNames); if (name == null) // very unlikely, but just in case ... yield break; yield return new CodeAction(context.TranslateString("Convert 'foreach' loop to 'for'"), script => { var result = context.Resolve(foreachStatement.InExpression); var countProperty = GetCountProperty(result.Type); // TODO: use another variable name if 'i' is already in use var initializer = new VariableDeclarationStatement(new PrimitiveType("int"), name, new PrimitiveExpression(0)); var id1 = new IdentifierExpression(name); var id2 = id1.Clone(); var id3 = id1.Clone(); var inExpression = foreachStatement.InExpression; Statement declarationStatement = null; if (inExpression is ObjectCreateExpression || inExpression is ArrayCreateExpression) { string listName = GetName(state, CollectionNames) ?? "col"; declarationStatement = new VariableDeclarationStatement ( new PrimitiveType ("var"), listName, inExpression.Clone () ); inExpression = new IdentifierExpression (listName); } var variableDeclarationStatement = new VariableDeclarationStatement( foreachStatement.VariableType.Clone(), foreachStatement.VariableName, new IndexerExpression(inExpression.Clone(), id3) ); var forStatement = new ForStatement() { Initializers = { initializer }, Condition = new BinaryOperatorExpression (id1, BinaryOperatorType.LessThan, new MemberReferenceExpression (inExpression.Clone (), countProperty)), Iterators = { new ExpressionStatement (new UnaryOperatorExpression (UnaryOperatorType.PostIncrement, id2)) }, EmbeddedStatement = new BlockStatement { variableDeclarationStatement } }; if (foreachStatement.EmbeddedStatement is BlockStatement) { variableDeclarationStatement.Remove(); var oldBlock = (BlockStatement)foreachStatement.EmbeddedStatement.Clone(); if (oldBlock.Statements.Any()) { oldBlock.Statements.InsertBefore(oldBlock.Statements.First(), variableDeclarationStatement); } else { oldBlock.Statements.Add(variableDeclarationStatement); } forStatement.EmbeddedStatement = oldBlock; } else { forStatement.EmbeddedStatement.AddChild (foreachStatement.EmbeddedStatement.Clone (), BlockStatement.StatementRole); } if (declarationStatement != null) script.InsertBefore (foreachStatement, declarationStatement); script.Replace (foreachStatement, forStatement); script.Link (initializer.Variables.First ().NameToken, id1, id2, id3); }, foreachStatement); }