public override void CaseALocalDeclStm(ALocalDeclStm node)
        {
            AMethodDecl pMethod = Util.GetAncestor<AMethodDecl>(node);
            AALocalDecl decl = (AALocalDecl) node.GetLocalDecl();

            if (decl.GetInit() == null)
            {
                ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(decl.GetName().Text));
                data.LocalLinks[lvalue] = decl;
                data.LvalueTypes[lvalue] = decl.GetType();
                List<PStm> statements = AssignDefault(lvalue);
                AABlock pBlock = (AABlock)node.Parent();
                foreach (PStm statement in statements)
                {
                    pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(node), statement);
                }
                pBlock.RemoveChild(node);
            }
            else
            {
                //Make an assignment expression before moving
                ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(decl.GetName().Text));
                data.LvalueTypes[lvalue] = decl.GetType();
                AAssignmentExp exp = new AAssignmentExp(new TAssign("="), lvalue, decl.GetInit());
                AExpStm expStm = new AExpStm(new TSemicolon(";"), exp);
                node.ReplaceBy(expStm);
                data.LvalueTypes[lvalue] = decl.GetType();
                data.ExpTypes[exp] = decl.GetType();
                data.LocalLinks[lvalue] = decl;
            }

            AABlock block = (AABlock) pMethod.GetBlock();
            block.GetStatements().Insert(0, node);
        }
        public override void CaseAMethodDecl(AMethodDecl node)
        {
            if (firstMethodCall)
                StatementRemover.Parse(node);
            firstMethodCall = false;

            before.Clear();
            after.Clear();
            uses.Clear();
            intersectingLocals.Clear();
            definedLocals.Clear();
            renamedLocals.Clear();
            assigns.Clear();
            changes = false;

            //Make uses
            setUses = true;
            base.CaseAMethodDecl(node);
            setUses = false;

            //Build a list of what's visible
            do
            {
                changes = false;
                base.CaseAMethodDecl(node);
            } while (changes);

            setSpans = true;
            base.CaseAMethodDecl(node);
            setSpans = false;

            //Join locals of same type, unless they are both parameters or they are listed as intersecting
            for (int i = 0; i < definedLocals.Count; i++)
            {
                for (int j = i + 1; j < definedLocals.Count; j++)
                {
                    AALocalDecl decl1 = definedLocals[i];
                    AALocalDecl decl2 = definedLocals[j];

                    if (Util.TypeToString(decl1.GetType()) == Util.TypeToString(decl2.GetType()) &&
                        !intersectingLocals.Contains(new Pair(decl1, decl2)))
                    {
                        if (Util.GetAncestor<AABlock>(decl1) == null &&
                            Util.GetAncestor<AABlock>(decl2) == null)
                            continue;

                        AALocalDecl replacement = decl1;
                        AALocalDecl replaced = decl2;

                        //Dont replace the parameter
                        if (Util.GetAncestor<AABlock>(replaced) == null)
                        {
                            replacement = decl2;
                            replaced = decl1;
                            i--;
                        }
                        j--;

                        renamedLocals.Add(replaced, replacement);
                        definedLocals.Remove(replaced);
                        foreach (Pair pair in intersectingLocals)
                        {
                            if (pair.Local1 == replaced)
                                pair.Local1 = replacement;
                            if (pair.Local2 == replaced)
                                pair.Local2 = replacement;
                        }

                        //Assign defaults
                        if (replaced.GetInit() == null)
                        {
                            ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(replaced.GetName().Text));
                            finalTrans.data.LocalLinks[lvalue] = replaced;
                            finalTrans.data.LvalueTypes[lvalue] = replaced.GetType();
                            List<PStm> statements = AssignDefault(lvalue);
                            PStm pStm = Util.GetAncestor<PStm>(replaced);
                            AABlock pBlock = (AABlock) pStm.Parent();
                            foreach (PStm statement in statements)
                            {
                                pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(pStm), statement);
                            }
                            pBlock.RemoveChild(pStm);
                        }
                        else
                        {
                            //Make an assignment expression instead
                            ALocalDeclStm declStm = (ALocalDeclStm)replaced.Parent();
                            ALocalLvalue lvalue = new ALocalLvalue((TIdentifier)replaced.GetName().Clone());
                            finalTrans.data.LvalueTypes[lvalue] = replaced.GetType();
                            AAssignmentExp exp = new AAssignmentExp(new TAssign("=", lvalue.GetName().Line, lvalue.GetName().Pos), lvalue, replaced.GetInit());
                            AExpStm expStm = new AExpStm(declStm.GetToken(), exp);
                            declStm.ReplaceBy(expStm);
                            finalTrans.data.LvalueTypes[lvalue] = replacement.GetType();
                            finalTrans.data.ExpTypes[exp] = replacement.GetType();
                            finalTrans.data.LocalLinks[lvalue] = replacement;
                        }
                    }
                }
            }

            //Unique names
            List<string> names = new List<string>();
            //Avoid clash with methods/fields/structs
            names.AddRange(finalTrans.data.Methods.Select(declItem => declItem.Decl.GetName().Text));
            names.AddRange(finalTrans.data.Fields.Select(declItem => declItem.Decl.GetName().Text));
            names.AddRange(finalTrans.data.Structs.Select(declItem => declItem.Decl.GetName().Text));
            foreach (AALocalDecl local in definedLocals)
            {
                string name = local.GetName().Text;
                int version = 1;
                while (names.Contains(name))
                {
                    version++;
                    name = local.GetName().Text + version;
                }
                local.GetName().Text = name;
                names.Add(name);
            }

            //Move defined locals to the start of the method
            foreach (AALocalDecl formal in node.GetFormals())
            {
                definedLocals.Remove(formal);
            }
            AABlock block = (AABlock)node.GetBlock();
            for (int i = 0; i < block.GetStatements().Count; i++)
            {
                ALocalDeclStm stm;
                if (block.GetStatements()[i] is ALocalDeclStm)
                {
                    stm = (ALocalDeclStm)block.GetStatements()[i];
                    definedLocals.Remove((AALocalDecl)stm.GetLocalDecl());
                    continue;
                }
                //Add the rest at i
                if (definedLocals.Count == 0)
                    break;
                AALocalDecl decl = definedLocals[0];
                definedLocals.RemoveAt(0);

                if (decl.GetInit() == null)
                {
                    ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(decl.GetName().Text));
                    finalTrans.data.LocalLinks[lvalue] = decl;
                    finalTrans.data.LvalueTypes[lvalue] = decl.GetType();
                    List<PStm> statements = AssignDefault(lvalue);
                    PStm pStm = Util.GetAncestor<PStm>(decl);
                    AABlock pBlock = (AABlock) pStm.Parent();
                    foreach (PStm statement in statements)
                    {
                        pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(pStm), statement);
                    }
                    pBlock.RemoveChild(pStm);
                }
                else
                {
                    //Make an assignment expression before moving
                    stm = (ALocalDeclStm)decl.Parent();
                    ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(decl.GetName().Text));
                    finalTrans.data.LvalueTypes[lvalue] = decl.GetType();
                    AAssignmentExp exp = new AAssignmentExp(new TAssign("="), lvalue, decl.GetInit());
                    AExpStm expStm = new AExpStm(new TSemicolon(";"), exp);
                    stm.ReplaceBy(expStm);
                    finalTrans.data.LvalueTypes[lvalue] = decl.GetType();
                    finalTrans.data.ExpTypes[exp] = decl.GetType();
                    finalTrans.data.LocalLinks[lvalue] = decl;
                }

                stm = new ALocalDeclStm(new TSemicolon(";"), decl);
                block.GetStatements().Insert(i, stm);
            }

            fixRefferences = true;
            base.CaseAMethodDecl(node);
            fixRefferences = false;

            //If we have an assignment to a local where the stored result is never used, remove the assignment

            //Since we changed some statements, rebuild stuff
            before.Clear();
            after.Clear();
            uses.Clear();
            intersectingLocals.Clear();
            definedLocals.Clear();
            renamedLocals.Clear();
            assigns.Clear();
            changes = false;

            //Make uses
            setUses = true;
            base.CaseAMethodDecl(node);
            setUses = false;

            //Build a list of what's visible
            do
            {
                changes = false;
                base.CaseAMethodDecl(node);
            } while (changes);

            PStm[] stms = new PStm[before.Keys.Count];
            before.Keys.CopyTo(stms, 0);
            foreach (PStm stm in stms)
            {
                if (assigns[stm] != null && //Assignment exp
                    !after[stm].Contains(assigns[stm]) && //Assignment unused
                    Util.GetAncestor<AMethodDecl>(assigns[stm]) != null &&
                    !(stm is ALocalDeclStm))//It is to a local
                {
                    stm.Apply(new MoveMethodDeclsOut(finalTrans.data));
                    stm.Parent().RemoveChild(stm);
                }
            }

            //Remove foo = foo;
            RemoveStupidAssignments assignmentRemover = new RemoveStupidAssignments(finalTrans.data);
            node.Apply(assignmentRemover);

            //Remove unused local variables
            foreach (AALocalDecl local in definedLocals)
            {
                if (Util.GetAncestor<AAProgram>(local) != null && Util.GetAncestor<AABlock>(local) != null &&
                    !finalTrans.data.LocalLinks.Where(p => p.Value == local).Any(p => Util.GetAncestor<AAProgram>(p.Key) != null))
                    local.Parent().Parent().RemoveChild(local.Parent());
            }

            if (assignmentRemover.RemovedOne)
            {
                CaseAMethodDecl(node);
                return;
            }

            //If an assignment to a variable is completely local, and that assignment is only used once, put the assignment where it is used
            //Since we changed some statements, rebuild stuff
            before.Clear();
            after.Clear();
            uses.Clear();
            intersectingLocals.Clear();
            definedLocals.Clear();
            renamedLocals.Clear();
            assigns.Clear();
            changes = false;

            //Make uses
            setUses = true;
            base.CaseAMethodDecl(node);
            setUses = false;

            //Build a list of what's visible
            do
            {
                changes = false;
                base.CaseAMethodDecl(node);
            } while (changes);
            foreach (KeyValuePair<PStm, AALocalDecl> pair in assigns)
            {
                PStm assignStm = pair.Key;
                AALocalDecl assignVar = pair.Value;
                bool isLocal = Util.IsLocal(assignStm, finalTrans.data);
                bool containsInvokeInPrevStm = false;
                if (assignVar != null && after[assignStm].Contains(assignVar))
                {
                    bool dontMove = false;
                    //First, if there are any conditional parrent statement, where the variable is in live before the stm, then we can't move it
                    PStm condParent = (PStm) Util.GetNearestAncestor(assignStm, typeof (AIfThenStm), typeof (AIfThenElseStm),
                                                                     typeof (AWhileStm));
                    while (condParent != null)
                    {
                        if (before[condParent].Contains(assignVar))
                        {
                            dontMove = true;
                            break;
                        }
                        condParent = (PStm)Util.GetNearestAncestor(condParent.Parent(), typeof(AIfThenStm), typeof(AIfThenElseStm),
                                                                     typeof(AWhileStm));
                    }

                    PStm useStm = null;
                    List<PStm> successors = GetSuccessor(assignStm);
                    bool containsConditionalAssignments = false;
                    while (successors.Count > 0)
                    {
                        if (successors.Count > 500)
                            useStm = useStm;
                        PStm successor = successors[0];
                        successors.RemoveAt(0);
                        if (uses[successor].Contains(assignVar))
                        {
                            if (useStm == null && !containsConditionalAssignments && !(successor is AWhileStm))
                                useStm = successor;
                            else
                            {
                                dontMove = true;
                                break;
                            }
                        }
                        if (after[successor].Contains(assignVar) && !(assigns.ContainsKey(successor) && assigns[successor] == assignVar))
                        {
                            List<PStm> newSuccessors = GetSuccessor(successor);
                            foreach (PStm stm in newSuccessors)
                            {
                                if (!successors.Contains(stm))
                                    successors.Add(stm);
                            }
                        }
                        if (assigns.ContainsKey(successor) && uses[assignStm].Contains(assigns[successor]))
                        {
                            dontMove = true;
                            break;
                        }

                        if (assigns.ContainsKey(successor) && assigns[successor] == assignVar)
                        {
                            condParent = (PStm)Util.GetNearestAncestor(successor, typeof(AIfThenStm), typeof(AIfThenElseStm),
                                                                       typeof(AWhileStm));
                            while (condParent != null)
                            {
                                if (!Util.IsAncestor(assignStm, condParent))
                                {
                                    containsConditionalAssignments = true;
                                    break;
                                }
                                condParent = (PStm)Util.GetNearestAncestor(condParent.Parent(), typeof(AIfThenStm), typeof(AIfThenElseStm),
                                                                             typeof(AWhileStm));
                            }

                            //If we found a usage, and it is inside a while that the assignStm is not inside, but we are inside, don't move
                            if (useStm != null)
                            {
                                AWhileStm whileParant = Util.GetAncestor<AWhileStm>(successor);
                                while (whileParant != null)
                                {
                                    if (Util.IsAncestor(useStm, whileParant) && !Util.IsAncestor(assignStm, whileParant))
                                    {
                                        dontMove = true;
                                        break;
                                    }
                                    whileParant = Util.GetAncestor<AWhileStm>(whileParant.Parent());
                                }
                            }
                        }

                        FindInvoke finder  = new FindInvoke();
                        successor.Apply(finder);
                        if (finder.ContainsInvoke && useStm == null)
                            containsInvokeInPrevStm = true;
                    }

                    if (useStm != null && !dontMove)
                    {
                        //If assignStm is inside an if, and the use stm is not, and there is another assignment
                        //to the same variable in an else block, then don't join
                        AIfThenElseStm ifThenElse = Util.GetAncestor<AIfThenElseStm>(assignStm);
                        while (ifThenElse != null)
                        {
                            if (!Util.IsAncestor(useStm, ifThenElse))
                            {
                                ABlockStm otherBlock;
                                if (Util.IsAncestor(assignStm, ifThenElse.GetThenBody()))
                                    otherBlock = (ABlockStm) ifThenElse.GetElseBody();
                                else
                                    otherBlock = (ABlockStm)ifThenElse.GetThenBody();
                                StmEnum enumerator = new StmEnum(otherBlock);
                                while (enumerator.MoveNext())
                                {
                                    PStm stm = (PStm) enumerator.Current;
                                    if (assigns.ContainsKey(stm) && assigns[stm] == assignVar)
                                    {
                                        dontMove = true;
                                        break;
                                    }
                                }
                                if (dontMove)
                                    break;
                            }
                            ifThenElse = Util.GetAncestor<AIfThenElseStm>(ifThenElse.Parent());
                        }

                        //If the assignStm or useStm is inside a while, it could get complicated
                        //if (Util.HasAncestor<AWhileStm>(assignStm) || Util.HasAncestor<AWhileStm>(useStm))
                        //    dontMove = true;
                    }

                    if (useStm != null && dontMove == false && (isLocal || !containsInvokeInPrevStm))
                    {

                        //Ensure that it is not used twice in this stm
                        FindLvalue finder = new FindLvalue(assignVar, finalTrans.data);
                        useStm.Apply(finder);
                        if (!finder.IsUsedTwice && (isLocal || !finder.HasPrevInvoke))
                        {
                            PExp rightside;
                            if (assignStm is ALocalDeclStm)
                            {
                                rightside = ((AALocalDecl)((ALocalDeclStm)assignStm).GetLocalDecl()).GetInit();
                            }
                            else
                            {
                                rightside = ((AAssignmentExp)((AExpStm)assignStm).GetExp()).GetExp();
                                assignStm.Parent().RemoveChild(assignStm);
                            }
                            if (rightside != null)
                            {
                                finder.Lvalue.Parent().ReplaceBy(rightside);
                                CaseAMethodDecl(node);
                                return;
                            }
                        }
                    }
                }
            }

            if (StatementRemover.Parse(node))
            {
                CaseAMethodDecl(node);
                return;
            }
            firstMethodCall = true;
        }