public override void OutASimpleInvokeExp(ASimpleInvokeExp node)
            {
                if (currentMethod == null)
                    return;

                AMethodDecl targetMethod = data.SimpleMethodLinks[node];
                if (node.Parent() is APointerLvalue || node.Parent() is AStructLvalue)
                {
                    //Move node out
                    MoveOut(node, targetMethod.GetReturnType());
                }

                //Only if it is not a library method
                if (Util.HasAncestor<AAProgram>(node))
                {
                    if (!dependancies[currentMethod].Contains(targetMethod))
                        dependancies[currentMethod].Add(targetMethod);
                }
            }
            public override void OutASimpleInvokeExp(ASimpleInvokeExp node)
            {
                if (data.BulkCopyProcessedInvokes.Contains(node))
                {
                    base.OutASimpleInvokeExp(node);
                    return;
                }

                //If anything needs to be put after the invoke, move it to it's own local decl or exp statement
                AMethodDecl method = data.SimpleMethodLinks[node];

                if (!processedMethods.Contains(method))
                    CaseAMethodDecl(method);

                bool moveOut = Util.IsBulkCopy(data.ExpTypes[node]);
                PType type;
                if (!moveOut)
                    for (int i = 0; i < node.GetArgs().Count; i++)
                    {
                        PExp arg = (PExp)node.GetArgs()[i];
                        AALocalDecl formal = (AALocalDecl)method.GetFormals()[i];
                        type = data.ExpTypes[arg];
                        if (Util.IsBulkCopy(type) || formal.GetRef() != null || formal.GetOut() != null)
                        {
                            moveOut = true;
                            break;
                        }
                    }
                if (moveOut && !(node.Parent() is AExpStm || node.Parent() is AALocalDecl))
                {
                    PStm pStm = Util.GetAncestor<PStm>(node);
                    AABlock pBlock = (AABlock) pStm.Parent();

                    //Can not be a void type, since it is not in an expStm
                    AALocalDecl localDecl = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null, Util.MakeClone(data.ExpTypes[node], data),
                                                            new TIdentifier("bulkCopyVar"), null);
                    ALocalLvalue bulkCopyVarRef = new ALocalLvalue(new TIdentifier("bulkCopyVar"));
                    ALvalueExp bulkCopyVarRefExp = new ALvalueExp(bulkCopyVarRef);
                    node.ReplaceBy(bulkCopyVarRefExp);
                    localDecl.SetInit(node);
                    pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(pStm), new ALocalDeclStm(new TSemicolon(";"), localDecl));

                    data.LocalLinks[bulkCopyVarRef] = localDecl;
                    data.LvalueTypes[bulkCopyVarRef] =
                        data.ExpTypes[bulkCopyVarRefExp] = localDecl.GetType();
                }

                //Replace bulk copy arguments with a new pointer
                for (int i = 0; i < node.GetArgs().Count; i++)
                {
                    PExp arg = (PExp) node.GetArgs()[i];
                    AALocalDecl formal = (AALocalDecl) method.GetFormals()[i];
                    if (oldParameterTypes.ContainsKey(formal))
                        type = oldParameterTypes[formal];// data.ExpTypes[arg];
                    else
                        type = formal.GetType();
                    if (Util.IsBulkCopy(type) || formal.GetRef() != null || formal.GetOut() != null)
                    {
                        if (formal.GetRef() != null && arg is ALvalueExp)
                        {
                            ALvalueExp aArg = (ALvalueExp) arg;
                            if (aArg.GetLvalue() is APointerLvalue)
                            {
                                APointerLvalue pointer = (APointerLvalue) aArg.GetLvalue();
                                if (Util.TypesEqual(formal.GetType(), data.ExpTypes[pointer.GetBase()], data))
                                {//Just send the arg
                                    aArg.ReplaceBy(pointer.GetBase());
                                    continue;
                                }
                            }
                        }

                        TurnDynamic(arg, formal,
                                    oldParameterTypes.ContainsKey(formal) ? oldParameterTypes[formal] : formal.GetType(),
                                    formal.GetOut() == null,
                                    formal.GetRef() != null || formal.GetOut() != null);
                    }
                }
                //Do return stm
                type = data.ExpTypes[node];
                if (Util.IsBulkCopy(type))
                {
                    PStm pStm = Util.GetAncestor<PStm>(node);
                    AABlock pBlock = (AABlock)pStm.Parent();
                    bool isReturnUsed = !(node.Parent() is AExpStm);
                    if (isReturnUsed)
                    {
                        //Make
                        //var bulkCopyVar = <node>(...);
                        //<usage>... *bulkCopyVar ... </usage>
                        //delete bulkCopyVar;
                        bool isArray = type is AArrayTempType;
                        AALocalDecl newLocal = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null,
                                                               new APointerType(new TStar("*"),
                                                                                isArray
                                                                                    ? new ADynamicArrayType(
                                                                                          new TLBracket("["),
                                                                                          Util.MakeClone(
                                                                                              ((AArrayTempType) type).
                                                                                                  GetType(), data))
                                                                                    : Util.MakeClone(type, data)),
                                                               new TIdentifier("bulkCopyVar"), null);
                        data.ExpTypes[node] = newLocal.GetType();

                        ALocalLvalue newLocalRef;
                        ALvalueExp newLocalRefExp;
                        newLocalRef = new ALocalLvalue(new TIdentifier("bulkCopyVar"));
                        newLocalRefExp = new ALvalueExp(newLocalRef);
                        APointerLvalue newLocalPointer = new APointerLvalue(new TStar("*"), newLocalRefExp);
                        ALvalueExp newLocalPointerExp = new ALvalueExp(newLocalPointer);
                        node.ReplaceBy(newLocalPointerExp);

                        data.LocalLinks[newLocalRef] = newLocal;
                        data.LvalueTypes[newLocalRef] =
                            data.ExpTypes[newLocalRefExp] = newLocal.GetType();
                        data.LvalueTypes[newLocalPointer] =
                            data.ExpTypes[newLocalPointerExp] = ((APointerType) newLocal.GetType()).GetType();

                        newLocal.SetInit(node);

                        newLocalRef = new ALocalLvalue(new TIdentifier("bulkCopyVar"));
                        newLocalRefExp = new ALvalueExp(newLocalRef);
                        data.LocalLinks[newLocalRef] = newLocal;
                        data.LvalueTypes[newLocalRef] =
                            data.ExpTypes[newLocalRefExp] = newLocal.GetType();

                        pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(pStm),
                                                      new ALocalDeclStm(new TSemicolon(";"), newLocal));
                        pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(pStm) + 1,
                                                      new ADeleteStm(new TDelete("delete"), newLocalRefExp));
                    }
                    else
                    {
                        //Make delete <node>(...);
                        pStm.ReplaceBy(new ADeleteStm(new TDelete("delete"), node));
                    }
                }
                base.OutASimpleInvokeExp(node);
            }
            public override void CaseANewExp(ANewExp node)
            {
                //Call new object or new array
                ASimpleInvokeExp invoke = new ASimpleInvokeExp(new TIdentifier("invoke"), new ArrayList());
                ANamedType pointerType = new ANamedType(new TIdentifier("string"), null);
                if (node.GetType() is AArrayTempType)
                {
                    if (newArrayMethod == null) CreateNewArrayMethod(node, data);

                    node.GetType().Apply(this);
                    AArrayTempType type = (AArrayTempType) node.GetType();
                    invoke.GetArgs().Add(Util.MakeClone(type.GetDimention(), data));
                    data.SimpleMethodLinks[invoke] = newArrayMethod;
                }
                else if (Util.IsIntPointer(node, node.GetType(), data))
                {
                    if (node.GetType() is ANamedType && data.StructTypeLinks.ContainsKey((ANamedType) node.GetType()))
                        data.SimpleMethodLinks[invoke] = CreateNewObjectMethod(node, data.StructTypeLinks[(ANamedType) node.GetType()],
                                                                               data);
                    else
                    {
                        data.SimpleMethodLinks[invoke] = CreateNewObjectMethod(node,
                                                                                data.EnrichmentTypeLinks[node.GetType()],
                                                                                data);
                    }
                    pointerType = new ANamedType(new TIdentifier("int"), null);
                }
                else
                {
                    if (newObjectMethod == null) CreateNewObjectMethod(node, data);

                    data.SimpleMethodLinks[invoke] = newObjectMethod;
                }
                node.ReplaceBy(invoke);
                data.ExpTypes[invoke] = pointerType;

                //Call initializer
                if (data.ConstructorLinks.ContainsKey(node))
                {
                    PStm pStm = Util.GetAncestor<PStm>(invoke);
                    AABlock pblock = (AABlock) pStm.Parent();

                    PLvalue lvalue;
                    ALvalueExp lvalueExp;
                    PStm stm;
                    AAssignmentExp assignment = null;
                    AALocalDecl localDecl = null;
                    if (invoke.Parent() is AAssignmentExp)
                    {
                        AAssignmentExp parent = (AAssignmentExp) invoke.Parent();
                        assignment = parent;
                        /*lvalue = parent.GetLvalue();
                        lvalue.Apply(new MoveMethodDeclsOut("pointerVar", data));
                        lvalue = Util.MakeClone(lvalue, data);*/
                    }
                    else if (invoke.Parent() is AALocalDecl)
                    {
                        AALocalDecl parent = (AALocalDecl) invoke.Parent();
                        localDecl = parent;
                        /*lvalue = new ALocalLvalue(new TIdentifier(parent.GetName().Text));

                        data.LocalLinks[(ALocalLvalue) lvalue] = parent;
                        data.LvalueTypes[lvalue] = parent.GetType();*/
                    }
                    else
                    {
                        //Move the new invocation out into a local decl, and use that
                        localDecl = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null,
                                                                Util.MakeClone(pointerType, data),
                                                                new TIdentifier("newVar"), null);
                        ALocalLvalue localLvalue = new ALocalLvalue(new TIdentifier("newVar"));
                        lvalueExp = new ALvalueExp(localLvalue);
                        invoke.ReplaceBy(lvalueExp);
                        localDecl.SetInit(invoke);
                        stm = new ALocalDeclStm(new TSemicolon(";"), localDecl);
                        pblock.GetStatements().Insert(pblock.GetStatements().IndexOf(pStm), stm);
                        pStm = stm;
                        //lvalue = new ALocalLvalue(new TIdentifier("newVar"));

                        //data.LocalLinks[(ALocalLvalue) lvalue] =
                            data.LocalLinks[localLvalue] = localDecl;
                        //data.LvalueTypes[lvalue] =
                            data.LvalueTypes[localLvalue] =
                            data.ExpTypes[lvalueExp] = localDecl.GetType();
                    }

                    ASimpleInvokeExp oldInvoke = invoke;
                    invoke = new ASimpleInvokeExp(new TIdentifier("renameMe"), new ArrayList());
                    while (node.GetArgs().Count > 0)
                    {
                        invoke.GetArgs().Add(node.GetArgs()[0]);
                    }
                    if (assignment != null)
                    {
                        assignment.SetExp(invoke);
                        invoke.GetArgs().Add(oldInvoke);
                    }
                    else
                    {
                        localDecl.SetInit(invoke);
                        invoke.GetArgs().Add(oldInvoke);
                    }
                    //lvalueExp = new ALvalueExp(lvalue);
                    //invoke.GetArgs().Add(lvalueExp);
                    //stm = new AExpStm(new TSemicolon(";"), invoke);
                    //pblock.GetStatements().Insert(pblock.GetStatements().IndexOf(pStm) + 1, stm);

                    //data.ExpTypes[lvalueExp] = data.LvalueTypes[lvalue];
                    data.SimpleMethodLinks[invoke] = data.ConstructorMap[data.ConstructorLinks[node]];
                    data.ExpTypes[invoke] = data.ConstructorMap[data.ConstructorLinks[node]].GetReturnType();
                    invoke.Apply(this);
                }
            }
        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 };
        }