public ForeachStatement TransformNonGenericForEach(ExpressionStatement node) { Match m1 = getEnumeratorPattern.Match(node); if (!m1.Success) { return(null); } AstNode tryCatch = node.NextSibling; Match m2 = nonGenericForeachPattern.Match(tryCatch); if (!m2.Success) { return(null); } IdentifierExpression enumeratorVar = m2.Get <IdentifierExpression>("enumerator").Single(); IdentifierExpression itemVar = m2.Get <IdentifierExpression>("itemVar").Single(); WhileStatement loop = m2.Get <WhileStatement>("loop").Single(); // verify that the getEnumeratorPattern assigns to the same variable as the nonGenericForeachPattern is reading from if (!enumeratorVar.IsMatch(m1.Get("left").Single())) { return(null); } VariableDeclarationStatement enumeratorVarDecl = FindVariableDeclaration(loop, enumeratorVar.Identifier); if (enumeratorVarDecl == null || !(enumeratorVarDecl.Parent is BlockStatement)) { return(null); } // Find the declaration of the item variable: // Because we look only outside the loop, we won't make the mistake of moving a captured variable across the loop boundary VariableDeclarationStatement itemVarDecl = FindVariableDeclaration(loop, itemVar.Identifier); if (itemVarDecl == null || !(itemVarDecl.Parent is BlockStatement)) { return(null); } // Now verify that we can move the variable declaration in front of the loop: Statement declarationPoint; CanMoveVariableDeclarationIntoStatement(itemVarDecl, loop, out declarationPoint); // We ignore the return value because we don't care whether we can move the variable into the loop // (that is possible only with non-captured variables). // We just care that we can move it in front of the loop: if (declarationPoint != loop) { return(null); } ForeachStatement foreachStatement = new ForeachStatement(); foreachStatement.VariableType = itemVarDecl.Type.Clone(); foreachStatement.VariableName = itemVar.Identifier; BlockStatement body = new BlockStatement(); foreachStatement.EmbeddedStatement = body; ((BlockStatement)node.Parent).Statements.InsertBefore(node, foreachStatement); body.Add(node.Detach()); body.Add((Statement)tryCatch.Detach()); // Now that we moved the whole try-catch into the foreach loop; verify that we can // move the enumerator into the foreach loop: CanMoveVariableDeclarationIntoStatement(enumeratorVarDecl, foreachStatement, out declarationPoint); if (declarationPoint != foreachStatement) { // oops, the enumerator variable can't be moved into the foreach loop // Undo our AST changes: ((BlockStatement)foreachStatement.Parent).Statements.InsertBefore(foreachStatement, node.Detach()); foreachStatement.ReplaceWith(tryCatch); return(null); } // Now create the correct body for the foreach statement: foreachStatement.InExpression = m1.Get <Expression>("collection").Single().Detach(); if (foreachStatement.InExpression is BaseReferenceExpression) { foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression); } body.Statements.Clear(); body.Statements.AddRange(m2.Get <Statement>("stmt").Select(stmt => stmt.Detach())); return(foreachStatement); }