Example #1
0
        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);
        }