public UsingStatement TransformUsings(ExpressionStatement node)
        {
            Match m1 = variableAssignPattern.Match(node);

            if (m1 == null)
            {
                return(null);
            }
            AstNode tryCatch = node.NextSibling;
            Match   m2       = usingTryCatchPattern.Match(tryCatch);

            if (m2 == null)
            {
                return(null);
            }
            string variableName = m1.Get <IdentifierExpression>("variable").Single().Identifier;

            if (variableName == m2.Get <IdentifierExpression>("ident").Single().Identifier)
            {
                if (m2.Has("valueType"))
                {
                    // if there's no if(x!=null), then it must be a value type
                    ILVariable v = m1.Get("variable").Single().Annotation <ILVariable>();
                    if (v == null || v.Type == null || !v.Type.IsValueType)
                    {
                        return(null);
                    }
                }
                node.Remove();
                BlockStatement body           = m2.Get <BlockStatement>("body").Single();
                UsingStatement usingStatement = new UsingStatement();
                usingStatement.ResourceAcquisition = node.Expression.Detach();
                usingStatement.EmbeddedStatement   = body.Detach();
                tryCatch.ReplaceWith(usingStatement);
                // Move the variable declaration into the resource acquisition, if possible
                // This is necessary for the foreach-pattern to work on the result of the using-pattern
                VariableDeclarationStatement varDecl = FindVariableDeclaration(usingStatement, variableName);
                if (varDecl != null && varDecl.Parent is BlockStatement)
                {
                    Statement declarationPoint;
                    if (CanMoveVariableDeclarationIntoStatement(varDecl, usingStatement, out declarationPoint))
                    {
                        Debug.Assert(declarationPoint == usingStatement);
                        // Moving the variable into the UsingStatement is allowed:
                        usingStatement.ResourceAcquisition = new VariableDeclarationStatement {
                            Type      = (AstType)varDecl.Type.Clone(),
                            Variables =
                            {
                                new VariableInitializer {
                                    Name        = variableName,
                                    Initializer = m1.Get <Expression>("initializer").Single().Detach()
                                }.CopyAnnotationsFrom(usingStatement.ResourceAcquisition)
                            }
                        }.CopyAnnotationsFrom(node);
                    }
                }
                return(usingStatement);
            }
            return(null);
        }
        internal void HandleStaticFieldInitializers(IEnumerable <AstNode> members)
        {
            // Translate static constructor into field initializers if the class is BeforeFieldInit
            var staticCtor = members.OfType <ConstructorDeclaration>().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static);

            if (staticCtor != null)
            {
                IMethod ctorMethod = staticCtor.GetSymbol() as IMethod;
                if (!ctorMethod.MetadataToken.IsNil)
                {
                    var metadata = context.TypeSystem.MainModule.PEFile.Metadata;
                    SRM.MethodDefinition ctorMethodDef = metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)ctorMethod.MetadataToken);
                    SRM.TypeDefinition   declaringType = metadata.GetTypeDefinition(ctorMethodDef.GetDeclaringType());
                    if (declaringType.HasFlag(System.Reflection.TypeAttributes.BeforeFieldInit))
                    {
                        while (true)
                        {
                            ExpressionStatement es = staticCtor.Body.Statements.FirstOrDefault() as ExpressionStatement;
                            if (es == null)
                            {
                                break;
                            }
                            AssignmentExpression assignment = es.Expression as AssignmentExpression;
                            if (assignment == null || assignment.Operator != AssignmentOperatorType.Assign)
                            {
                                break;
                            }
                            IMember fieldOrProperty = (assignment.Left.GetSymbol() as IMember)?.MemberDefinition;
                            if (!(fieldOrProperty is IField || fieldOrProperty is IProperty) || !fieldOrProperty.IsStatic)
                            {
                                break;
                            }
                            AstNode fieldOrPropertyDecl = members.FirstOrDefault(f => f.GetSymbol() == fieldOrProperty);
                            if (fieldOrPropertyDecl == null)
                            {
                                break;
                            }
                            if (fieldOrPropertyDecl is FieldDeclaration fd)
                            {
                                fd.Variables.Single().Initializer = assignment.Right.Detach();
                            }
                            else if (fieldOrPropertyDecl is PropertyDeclaration pd)
                            {
                                pd.Initializer = assignment.Right.Detach();
                            }
                            else
                            {
                                break;
                            }
                            es.Remove();
                        }
                        if (staticCtor.Body.Statements.Count == 0)
                        {
                            staticCtor.Remove();
                        }
                    }
                }
            }
        }
        public ForStatement TransformFor(ExpressionStatement node)
        {
            Match m1 = variableAssignPattern.Match(node);

            if (!m1.Success)
            {
                return(null);
            }
            var     variable = m1.Get <IdentifierExpression>("variable").Single().GetILVariable();
            AstNode next     = node.NextSibling;

            if (next is ForStatement forStatement && ForStatementUsesVariable(forStatement, variable))
            {
                node.Remove();
                next.InsertChildAfter(null, node, ForStatement.InitializerRole);
                return((ForStatement)next);
            }
            Match m3 = forPattern.Match(next);

            if (!m3.Success)
            {
                return(null);
            }
            // ensure the variable in the for pattern is the same as in the declaration
            if (variable != m3.Get <IdentifierExpression>("ident").Single().GetILVariable())
            {
                return(null);
            }
            WhileStatement loop = (WhileStatement)next;

            node.Remove();
            BlockStatement newBody = new BlockStatement();

            foreach (Statement stmt in m3.Get <Statement>("statement"))
            {
                newBody.Add(stmt.Detach());
            }
            forStatement = new ForStatement();
            forStatement.CopyAnnotationsFrom(loop);
            forStatement.Initializers.Add(node);
            forStatement.Condition = loop.Condition.Detach();
            forStatement.Iterators.Add(m3.Get <Statement>("increment").Single().Detach());
            forStatement.EmbeddedStatement = newBody;
            loop.ReplaceWith(forStatement);
            return(forStatement);
        }
        public LockStatement TransformLock(ExpressionStatement node)
        {
            Match m1 = lockFlagInitPattern.Match(node);

            if (m1 == null)
            {
                return(null);
            }
            AstNode tryCatch = node.NextSibling;
            Match   m2       = lockTryCatchPattern.Match(tryCatch);

            if (m2 == null)
            {
                return(null);
            }
            if (m1.Get <IdentifierExpression>("variable").Single().Identifier == m2.Get <IdentifierExpression>("flag").Single().Identifier)
            {
                Expression           enter = m2.Get <Expression>("enter").Single();
                IdentifierExpression exit  = m2.Get <IdentifierExpression>("exit").Single();
                if (exit.Match(enter) == null)
                {
                    // If exit and enter are not the same, then enter must be "exit = ..."
                    AssignmentExpression assign = enter as AssignmentExpression;
                    if (assign == null)
                    {
                        return(null);
                    }
                    if (exit.Match(assign.Left) == null)
                    {
                        return(null);
                    }
                    enter = assign.Right;
                    // TODO: verify that 'obj' variable can be removed
                }
                // TODO: verify that 'flag' variable can be removed
                // transform the code into a lock statement:
                LockStatement l = new LockStatement();
                l.Expression        = enter.Detach();
                l.EmbeddedStatement = ((TryCatchStatement)tryCatch).TryBlock.Detach();
                ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove(); // Remove 'Enter()' call
                tryCatch.ReplaceWith(l);
                node.Remove();                                                     // remove flag variable
                return(l);
            }
            return(null);
        }
        public ForStatement TransformFor(ExpressionStatement node)
        {
            Match m1 = variableAssignPattern.Match(node);

            if (m1 == null)
            {
                return(null);
            }
            AstNode next = node.NextSibling;
            Match   m2   = forPattern.Match(next);

            if (m2 == null)
            {
                return(null);
            }
            // ensure the variable in the for pattern is the same as in the declaration
            if (m1.Get <IdentifierExpression>("variable").Single().Identifier != m2.Get <IdentifierExpression>("ident").Single().Identifier)
            {
                return(null);
            }
            WhileStatement loop = (WhileStatement)next;

            node.Remove();
            BlockStatement newBody = new BlockStatement();

            foreach (Statement stmt in m2.Get <Statement>("statement"))
            {
                newBody.Add(stmt.Detach());
            }
            ForStatement forStatement = new ForStatement();

            forStatement.Initializers.Add(node);
            forStatement.Condition = loop.Condition.Detach();
            forStatement.Iterators.Add(m2.Get <Statement>("increment").Single().Detach());
            forStatement.EmbeddedStatement = newBody;
            loop.ReplaceWith(forStatement);
            return(forStatement);
        }