//if ur an if you got 2
        //if ur a while you got 2
        //if ur not an if else, and your the last element of a block, look up untill you encounter
        //  another block, keep searching in that
        //  a while, pick that
        //  a method decl, no successor
        private List<PStm> GetSuccessor(PStm stm)
        {
            List<PStm> list = new List<PStm>();
            AABlock block;
            ABlockStm blockStm;
            if (stm is AIfThenElseStm)
            {
                AIfThenElseStm aStm = (AIfThenElseStm)stm;
                bool fallthrough = false;
                //Then
                blockStm = (ABlockStm)aStm.GetThenBody();
                block = (AABlock)blockStm.GetBlock();
                GetNonBlockStm stmFinder = new GetNonBlockStm(true);
                block.Apply(stmFinder);
                if (stmFinder.Stm != null)
                    list.Add(stmFinder.Stm);
                else
                    fallthrough = true;
                //Else
                blockStm = (ABlockStm)aStm.GetElseBody();
                block = (AABlock)blockStm.GetBlock();
                stmFinder = new GetNonBlockStm(true);
                block.Apply(stmFinder);
                if (stmFinder.Stm != null)
                    list.Add(stmFinder.Stm);
                else
                    fallthrough = true;
                if (!fallthrough)
                    return list;
            }
            if (stm is AIfThenStm)
            {
                AIfThenStm aStm = (AIfThenStm)stm;
                //Then
                blockStm = (ABlockStm)aStm.GetBody();
                block = (AABlock)blockStm.GetBlock();
                GetNonBlockStm stmFinder = new GetNonBlockStm(true);
                block.Apply(stmFinder);
                if (stmFinder.Stm != null)
                {
                    list.Add(stmFinder.Stm);
                }
            }
            if (stm is AWhileStm)
            {
                AWhileStm aStm = (AWhileStm)stm;
                //Then
                blockStm = (ABlockStm)aStm.GetBody();
                block = (AABlock)blockStm.GetBlock();
                GetNonBlockStm stmFinder = new GetNonBlockStm(true);
                block.Apply(stmFinder);
                if (stmFinder.Stm != null)
                {
                    list.Add(stmFinder.Stm);
                }
            }
            if (stm is ABreakStm)
            {
                AWhileStm whileStm = Util.GetAncestor<AWhileStm>(stm);

                list = GetSuccessor(whileStm);
                list.RemoveAt(0);
                return list;
            }
            if (stm is AContinueStm)
            {
                AWhileStm whileStm = Util.GetAncestor<AWhileStm>(stm);
                list.Add(whileStm);
                return list;
            }

            //Get the next statement in block
            block = (AABlock)stm.Parent();
            int index = block.GetStatements().IndexOf(stm);
            if (index == block.GetStatements().Count - 1)
                list.AddRange(GetSuccessor(block));
            else
            {
                stm = (PStm)block.GetStatements()[index + 1];
                while (stm is ABlockStm)
                {
                    blockStm = (ABlockStm)stm;
                    block = (AABlock)blockStm.GetBlock();

                    if (block.GetStatements().Count == 0)
                    {
                        list.AddRange(GetSuccessor(block));
                        return list;
                    }
                    stm = (PStm)block.GetStatements()[0];
                }
                list.Add(stm);
            }
            return list;
        }
        public static List<AABlock> Inline(ASimpleInvokeExp node, FinalTransformations finalTrans)
        {
            /*if (Util.GetAncestor<AMethodDecl>(node) != null && Util.GetAncestor<AMethodDecl>(node).GetName().Text == "UIChatFrame_LeaveChannel")
                node = node;*/

            SharedData data = finalTrans.data;
            //If this node is inside the condition of a while, replace it with a new local var,
            //make a clone before the while, one before each continue in the while, and one at the end of the while
            //(unless the end is a return or break)
            AABlock pBlock;
            if (Util.HasAncestor<AWhileStm>(node))
            {
                AWhileStm whileStm = Util.GetAncestor<AWhileStm>(node);
                if (Util.IsAncestor(node, whileStm.GetCondition()))
                {
                    List<ASimpleInvokeExp> toInline = new List<ASimpleInvokeExp>();
                    //Above while
                    AALocalDecl replaceVarDecl = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null,
                                                                 Util.MakeClone(data.ExpTypes[node], data),
                                                                 new TIdentifier("whileVar"), null);
                    ALocalLvalue replaceVarRef = new ALocalLvalue(new TIdentifier("whileVar"));
                    ALvalueExp replaceVarRefExp = new ALvalueExp(replaceVarRef);
                    data.LocalLinks[replaceVarRef] = replaceVarDecl;
                    data.ExpTypes[replaceVarRefExp] = data.LvalueTypes[replaceVarRef] = replaceVarDecl.GetType();
                    node.ReplaceBy(replaceVarRefExp);
                    replaceVarDecl.SetInit(node);
                    pBlock = (AABlock) whileStm.Parent();
                    pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(whileStm), new ALocalDeclStm(new TSemicolon(";"), replaceVarDecl));
                    toInline.Add(node);

                    //In the end of the while
                    PStm lastStm = whileStm.GetBody();
                    while (lastStm is ABlockStm)
                    {
                        AABlock block = (AABlock) ((ABlockStm) lastStm).GetBlock();
                        if (block.GetStatements().Count == 0)
                        {
                            lastStm = null;
                            break;
                        }
                        lastStm = (PStm) block.GetStatements()[block.GetStatements().Count - 1];
                    }
                    if (lastStm == null || !(lastStm is AValueReturnStm || lastStm is AVoidReturnStm || lastStm is ABreakStm))
                    {
                        lastStm = whileStm.GetBody();
                        AABlock block;
                        if (lastStm is ABlockStm)
                        {
                            block = (AABlock)((ABlockStm)lastStm).GetBlock();
                        }
                        else
                        {
                            block = new AABlock(new ArrayList(), new TRBrace("}"));
                            block.GetStatements().Add(lastStm);
                            whileStm.SetBody(new ABlockStm(new TLBrace("{"), block));
                        }

                        replaceVarRef = new ALocalLvalue(new TIdentifier("whileVar"));
                        ASimpleInvokeExp clone = (ASimpleInvokeExp)Util.MakeClone(node, data);
                        toInline.Add(clone);
                        AAssignmentExp assignment = new AAssignmentExp(new TAssign("="), replaceVarRef, clone);
                        data.LocalLinks[replaceVarRef] = replaceVarDecl;
                        data.ExpTypes[assignment] = data.LvalueTypes[replaceVarRef] = replaceVarDecl.GetType();
                        block.GetStatements().Add(new AExpStm(new TSemicolon(";"), assignment));
                    }

                    //After each continue
                    CloneBeforeContinue cloner = new CloneBeforeContinue(node, replaceVarDecl, data);
                    whileStm.GetBody().Apply(cloner);
                    toInline.AddRange(cloner.replacementExpressions);
                    List<AABlock> visitBlocks = new List<AABlock>();
                    foreach (ASimpleInvokeExp invoke in toInline)
                    {
                        visitBlocks.AddRange(Inline(invoke, finalTrans));
                    }
                    return visitBlocks;
                }
            }

            AMethodDecl decl = finalTrans.data.SimpleMethodLinks[node];
            FindAssignedToFormals assignedToFormalsFinder = new FindAssignedToFormals(finalTrans.data);
            decl.Apply(assignedToFormalsFinder);
            List<AALocalDecl> assignedToFormals = assignedToFormalsFinder.AssignedFormals;

            /*
                 * inline int foo(int a)
                 * {
                 *      int b = 2;
                 *      int c;
                 *      ...
                 *      while(...)
                 *      {
                 *          ...
                 *          break;
                 *          ...
                 *          return c;
                 *      }
                 *      ...
                 *      return 2;
                 * }
                 *
                 * bar(foo(<arg for a>));
                 * ->
                 *
                 * {
                 *      bool inlineMethodReturned = false;
                 *      int inlineReturner;
                 *      int a = <arg for a>;
                 *      while (!inlineMethodReturned)
                 *      {
                 *          int b = 2;
                 *          int c;
                 *          ...
                 *          while(...)
                 *          {
                 *              ...
                 *              break
                 *              ...
                 *              inlineReturner = c;
                 *              inlineMethodReturned = true;
                 *              break;
                 *          }
                 *          if (inlineMethodReturned)
                 *          {
                 *              break;
                 *          }
                 *          ...
                 *          inlineReturner = 2;
                 *          inlineMethodReturned = true;
                 *          break;
                 *          break;
                 *      }
                 *      bar(inlineReturner);
                 * }
                 *
                 *
                 */

            AABlock outerBlock = new AABlock();
            PExp exp = new ABooleanConstExp(new AFalseBool());
            finalTrans.data.ExpTypes[exp] = new ANamedType(new TIdentifier("bool"), null);
            AALocalDecl hasMethodReturnedVar = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null, new ANamedType(new TIdentifier("bool"), null),
                                                               new TIdentifier("hasInlineReturned"), exp);
            finalTrans.data.GeneratedVariables.Add(hasMethodReturnedVar);
            PStm stm = new ALocalDeclStm(new TSemicolon(";"), hasMethodReturnedVar);
            outerBlock.GetStatements().Add(stm);

            AALocalDecl methodReturnerVar = null;
            if (!(decl.GetReturnType() is AVoidType))
            {
                methodReturnerVar = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null, Util.MakeClone(decl.GetReturnType(), finalTrans.data),
                                                       new TIdentifier("inlineReturner"), null);
                stm = new ALocalDeclStm(new TSemicolon(";"), methodReturnerVar);
                outerBlock.GetStatements().Add(stm);
            }

            AABlock afterBlock = new AABlock();

            //A dictionary from the formals of the inline method to a cloneable replacement lvalue
            Dictionary<AALocalDecl, PLvalue> Parameters = new Dictionary<AALocalDecl, PLvalue>();
            Dictionary<AALocalDecl, PExp> ParameterExps = new Dictionary<AALocalDecl, PExp>();
            for (int i = 0; i < decl.GetFormals().Count; i++)
            {
                AALocalDecl formal = (AALocalDecl)decl.GetFormals()[i];
                PExp arg = (PExp)node.GetArgs()[0];
                PLvalue lvalue;
                //if ref, dont make a new var
                if (formal.GetRef() != null && arg is ALvalueExp)
                {
                    arg.Apply(new MoveMethodDeclsOut("inlineVar", finalTrans.data));
                    arg.Parent().RemoveChild(arg);
                    lvalue = ((ALvalueExp) arg).GetLvalue();

                }
                else if (!assignedToFormals.Contains(formal) && Util.IsLocal(arg, finalTrans.data))
                {
                    lvalue = new ALocalLvalue(new TIdentifier("I hope I dont make it"));
                    finalTrans.data.LvalueTypes[lvalue] = formal.GetType();
                    finalTrans.data.LocalLinks[(ALocalLvalue) lvalue] = formal;
                    ParameterExps[formal] = arg;
                    arg.Parent().RemoveChild(arg);
                }
                else
                {
                    AAssignmentExp assExp = null;
                    if (formal.GetOut() != null)
                    {
                        //Dont initialize with arg, but assign arg after
                        arg.Apply(new MoveMethodDeclsOut("inlineVar", finalTrans.data));
                        lvalue = ((ALvalueExp)arg).GetLvalue();
                        assExp = new AAssignmentExp(new TAssign("="), lvalue, null);
                        finalTrans.data.ExpTypes[assExp] = finalTrans.data.LvalueTypes[lvalue];
                        arg.Parent().RemoveChild(arg);
                        arg = null;
                    }
                    AALocalDecl parameter = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null, Util.MakeClone(formal.GetType(), finalTrans.data),
                                                            new TIdentifier(formal.GetName().Text),
                                                            arg);
                    stm = new ALocalDeclStm(new TSemicolon(";"), parameter);
                    outerBlock.GetStatements().Add(stm);

                    lvalue = new ALocalLvalue(new TIdentifier(parameter.GetName().Text));
                    finalTrans.data.LvalueTypes[lvalue] = parameter.GetType();
                    finalTrans.data.LocalLinks[(ALocalLvalue)lvalue] = parameter;

                    if (formal.GetOut() != null)
                    {
                        //Dont initialize with arg, but assign arg after
                        ALvalueExp lvalueExp = new ALvalueExp(Util.MakeClone(lvalue, finalTrans.data));
                        finalTrans.data.ExpTypes[lvalueExp] = finalTrans.data.LvalueTypes[lvalue];
                        assExp.SetExp(lvalueExp);
                        afterBlock.GetStatements().Add(new AExpStm(new TSemicolon(";"), assExp));
                    }
                }
                Parameters.Add(formal, lvalue);
            }

            AABlock innerBlock = (AABlock)decl.GetBlock().Clone();
            exp = new ABooleanConstExp(new ATrueBool());
            finalTrans.data.ExpTypes[exp] = new ANamedType(new TIdentifier("bool"), null);
            ABlockStm innerBlockStm = new ABlockStm(new TLBrace("{"), innerBlock);

            bool needWhile = CheckIfWhilesIsNeeded.IsWhileNeeded(decl.GetBlock());
            if (needWhile)
                stm = new AWhileStm(new TLParen("("), exp, innerBlockStm);
            else
                stm = innerBlockStm;
            outerBlock.GetStatements().Add(stm);

            outerBlock.GetStatements().Add(new ABlockStm(new TLBrace("{"), afterBlock));

            //Clone method contents to inner block.
            CloneMethod cloneFixer = new CloneMethod(finalTrans, Parameters, ParameterExps, innerBlockStm);
            decl.GetBlock().Apply(cloneFixer);
            foreach (KeyValuePair<PLvalue, PExp> pair in cloneFixer.ReplaceUsAfter)
            {
                PLvalue lvalue = pair.Key;
                PExp replacement =  Util.MakeClone(pair.Value, finalTrans.data);
                ALvalueExp lvalueParent = (ALvalueExp) lvalue.Parent();
                lvalueParent.ReplaceBy(replacement);
            }
            innerBlockStm.Apply(new FixTypes(finalTrans.data));

            innerBlock.Apply(new FixReturnsAndWhiles(hasMethodReturnedVar, methodReturnerVar, finalTrans.data, needWhile));

            GetNonBlockStm stmFinder = new GetNonBlockStm(false);
            innerBlock.Apply(stmFinder);
            if (needWhile && (stmFinder.Stm == null || !(stmFinder.Stm is ABreakStm)))
                innerBlock.GetStatements().Add(new ABreakStm(new TBreak("break")));

            //Insert before current statement
            ABlockStm outerBlockStm = new ABlockStm(new TLBrace("{"), outerBlock);

            PStm pStm = Util.GetAncestor<PStm>(node);

            pBlock = (AABlock)pStm.Parent();

            pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(pStm), outerBlockStm);

            if (node.Parent() == pStm && pStm is AExpStm)
            {
                pBlock.RemoveChild(pStm);
            }
            else
            {
                PLvalue lvalue = new ALocalLvalue(new TIdentifier(methodReturnerVar.GetName().Text));
                finalTrans.data.LvalueTypes[lvalue] = methodReturnerVar.GetType();
                finalTrans.data.LocalLinks[(ALocalLvalue)lvalue] = methodReturnerVar;
                exp = new ALvalueExp(lvalue);
                finalTrans.data.ExpTypes[exp] = methodReturnerVar.GetType();

                node.ReplaceBy(exp);
            }
            return new List<AABlock>() { outerBlock };
        }