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);
            }));
        }
示例#2
0
        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;
            }
        }
示例#5
0
        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));
        }
示例#7
0
        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);
        }