private void FindFunctionTypes(Function function, bool makeNewStuffUp)
        {
            var code = ainFile.DecompiledCodeCache.GetDecompiledCode(function);

            foreach (var e in code.GetChildExpressions())
            {
                if (e.ExpressionType == Instruction.CALLFUNC2 || e.ExpressionType == Instruction.FT_ASSIGNS)
                {
                    int       funcTypeIndex    = -1;
                    IVariable funcTypeVariable = null;
                    if (e.ExpressionType == Instruction.CALLFUNC2)
                    {
                        funcTypeIndex    = e.Arg2.Value;
                        funcTypeVariable = e.Arg1.Variable.Canonicalize();
                    }
                    else if (e.ExpressionType == Instruction.FT_ASSIGNS)
                    {
                        funcTypeIndex    = e.Arg3.Value;
                        funcTypeVariable = e.Arg1.Variable.Canonicalize();
                    }
                    if (funcTypeVariable == null)
                    {
                        var arg1 = e.Arg1;
                        if (arg1 != null)
                        {
                            arg1 = arg1.Arg1;
                        }
                        if (arg1 != null)
                        {
                            funcTypeVariable = arg1.Variable;
                        }
                        if (funcTypeVariable != null)
                        {
                            funcTypeVariable = funcTypeVariable.Canonicalize();
                        }
                    }
                    if (funcTypeVariable != null && funcTypeVariable.StructType == -1)
                    {
                        matches.Clear();
                        finished.Clear();

                        var traceResults = TraceVariable(funcTypeVariable, VariableTraceMode.DirectCopiesRecursive);

                        foreach (var res in traceResults)
                        {
                            if (res.DataType.IsFuncType())
                            {
                                res.StructType = funcTypeIndex;
                            }
                        }
                        funcTypeVariable.StructType = funcTypeIndex;
                    }
                }
                else if (e.ExpressionType == Instruction.DG_CALLBEGIN)
                {
                    int       delegateIndex    = -1;
                    IVariable delegateVariable = null;
                    if (e.ExpressionType == Instruction.DG_CALLBEGIN)
                    {
                        delegateIndex    = e.Value;
                        delegateVariable = e.Arg2.Variable.Canonicalize();
                    }
                    if (delegateVariable == null)
                    {
                        var arg1 = e.Arg2;
                        if (arg1 != null)
                        {
                            arg1 = arg1.Arg1;
                        }
                        if (arg1 != null)
                        {
                            delegateVariable = arg1.Variable;
                        }
                        if (delegateVariable != null)
                        {
                            delegateVariable = delegateVariable.Canonicalize();
                        }
                    }
                    if (delegateVariable != null && delegateVariable.StructType == -1)
                    {
                        matches.Clear();
                        finished.Clear();
                        var traceResults = TraceVariable(delegateVariable, VariableTraceMode.DirectCopiesRecursive);

                        foreach (var res in traceResults)
                        {
                            if (res.DataType.IsDelegate())
                            {
                                res.StructType = delegateIndex;
                            }
                        }
                        delegateVariable.StructType = delegateIndex;
                    }
                }
                else if (e.ExpressionType == Instruction.DG_STR_TO_METHOD)
                {
                    var otherExpression = e.GetOtherSideOfBinaryExpression();
                    int delegateIndex   = -1;
                    if (e.Arg2.ExpressionType == Instruction.PUSH)
                    {
                        delegateIndex = e.Arg2.Value;
                    }
                    IVariable delegateVariable = null;
                    if (otherExpression == null)
                    {
                        delegateVariable = e.GetFunctionCallParameter();
                        if (e.Parent != null && e.Parent.ExpressionType == Instruction.DG_ADD)
                        {
                            delegateVariable = e.Parent.Arg1.Variable.Canonicalize();
                        }
                        else
                        {
                        }
                    }
                    else
                    {
                        delegateVariable = otherExpression.Variable;
                        if (delegateVariable != null)
                        {
                            delegateVariable = delegateVariable.Canonicalize();
                        }
                        else
                        {
                        }
                    }
                    if (delegateVariable != null && delegateVariable.StructType == -1 && delegateIndex != -1)
                    {
                        matches.Clear();
                        finished.Clear();
                        var traceResults = TraceVariable(delegateVariable, VariableTraceMode.DirectCopiesRecursive);

                        foreach (var res in traceResults)
                        {
                            if (res.DataType.IsDelegate())
                            {
                                res.StructType = delegateIndex;
                            }
                        }
                        delegateVariable.StructType = delegateIndex;
                    }
                }
                else if (e.ExpressionType == Instruction.DG_NEW_FROM_METHOD)
                {
                    var       otherExpression  = e.GetOtherSideOfBinaryExpression();
                    IVariable delegateVariable = null;
                    if (otherExpression == null)
                    {
                        delegateVariable = e.GetFunctionCallParameter();
                        if (e.Parent != null && e.Parent.ExpressionType == Instruction.DG_ADD)
                        {
                            delegateVariable = e.Parent.Arg1.Variable.Canonicalize();
                        }
                        else if (delegateVariable == null)
                        {
                        }
                    }
                    else
                    {
                        delegateVariable = otherExpression.Variable;
                    }
                    if (delegateVariable != null)
                    {
                        Function assignedFunction = null;
                        if (e.Arg2.ExpressionType == Instruction.PUSH)
                        {
                            assignedFunction = ainFile.GetFunction(e.Arg2.Value);
                        }
                        if (assignedFunction != null)
                        {
                            var          matchingTypes = ainFile.MatchingDelegates(assignedFunction);
                            FunctionType firstMatch = null, secondMatch = null;
                            foreach (var m in matchingTypes)
                            {
                                if (firstMatch == null)
                                {
                                    firstMatch = m;
                                }
                                else
                                {
                                    secondMatch = m;
                                    break;
                                }
                            }
                            if (firstMatch != null && (secondMatch == null || makeNewStuffUp))
                            {
                                int delegateIndex = firstMatch.Index;

                                if (delegateVariable.StructType == -1)
                                {
                                    matches.Clear();
                                    finished.Clear();
                                    var traceResults = TraceVariable(delegateVariable, VariableTraceMode.DirectCopiesRecursive);

                                    foreach (var res in traceResults)
                                    {
                                        if (res.DataType.IsDelegate())
                                        {
                                            res.StructType = delegateIndex;
                                        }
                                    }
                                    delegateVariable.StructType = delegateIndex;
                                }
                            }
                        }
                    }
                }
            }
        }
        private void TraceExpressionUp2(Expression firstExpression)
        {
            var expression = firstExpression;

            if (expression == null)
            {
                return;
            }

            //Called on a instance of a variable expression in a function
            //Want to find:
            //  Look at operators and assignment, ? : operator, casting
            //  Copying to a function arguments
            //  Return values
            //Types of searches:
            //  Direct copies of variables, ignoring casting
            //  Other variables that appear in a variable read
            //  Other variables that appear in a variable write

            var lookForVariable = firstExpression.Variable;

            if (lookForVariable != null)
            {
                lookForVariable = lookForVariable.Canonicalize();
            }

            //IVariable functionParameter = null;
            IVariable lValue = null;
            IVariable rValue = null;

            //look for a parent expression by seeking through operators
            while (true)
            {
                var parent = expression.Parent;
                if (parent == null || parent.ExpressionType == Instruction.Statement)
                {
                    break;
                }
                //check for Return
                if (parent.ExpressionType == Instruction.RETURN)
                {
                    expression = parent;
                    lValue     = parent.Root.Variable;
                    break;
                }
                //check for function call or comma
                if (parent.ExpressionType.IsFunctionCall() || parent.ExpressionType == Instruction.Comma)
                {
                    //functionParameter = expression.GetFunctionCallParameter();
                    lValue = expression.GetFunctionCallParameter();
                    break;
                }
                //check for cast operator or expression
                if (!ExpressionIsOperatorOrCast(parent))
                {
                    break;
                }
                expression = parent;
            }

            Expression e2 = SkipCastExpressions(expression);

            //is this an assignment expression?
            if (lValue == null)
            {
                if (expression.ExpressionType.IsAssignment())
                {
                    lValue = expression.Variable;
                    var lValueCanon        = lValue.Canonicalize();
                    var arg1ExpressionType = expression.Arg1.ExpressionType;
                    if (lValueCanon == null && (arg1ExpressionType == Instruction.REF || arg1ExpressionType == Instruction.ArrayIndex))
                    {
                        lValue = expression.Arg1.Arg1.Variable;
                    }
                    var arg2 = SkipCastExpressions(expression.Arg2);
                    if (arg2 != null)
                    {
                        rValue = arg2.Variable;
                    }
                    if (rValue != null)
                    {
                        rValue = rValue.Canonicalize();
                    }
                }
            }
            else
            {
                rValue = e2.Variable;
                if (rValue != null)
                {
                    rValue = rValue.Canonicalize();
                }
                if (rValue == null)
                {
                    e2     = SkipCastExpressions(firstExpression);
                    rValue = e2.Variable;
                    if (rValue != null)
                    {
                        rValue = rValue.Canonicalize();
                    }
                }
            }

            //fixme, lvalue and rvalue stuff got weird
            //Are we directly pointing to the variable? (excluding cast operations)
            //Expression e2 = SkipCastExpressions(expression);
            bool      isDirect = false;
            var       v2       = e2.Variable;
            IVariable v2Canon  = null;

            if (v2 != null)
            {
                v2Canon = v2.Canonicalize();
                if (v2Canon == v2 && !(expression.ExpressionType.IsAssignment() && !expression.ExpressionType.IsDirectAssignment()) && (lookForVariable != null && lookForVariable.DataType == v2.DataType))
                {
                    isDirect = true;
                }
                else if (v2Canon == v2 && (lookForVariable != null && lookForVariable.DataType == v2.DataType) && (expression.ExpressionType == Instruction.DG_PLUSA || expression.ExpressionType == Instruction.DG_MINUSA || expression.ExpressionType == Instruction.DG_ASSIGN))
                {
                    isDirect = true;
                }
            }

            if (0 != (mode & VariableTraceMode.DirectCopies))
            {
                if (isDirect && (lValue == lookFor || v2 == lookFor || rValue == lookFor))
                {
                    EnqueueVariable(v2);
                    if (!(lookFor.DataType == DataType.Functype && lValue != null && lValue.DataType != DataType.Functype))
                    {
                        EnqueueVariable(lValue);
                    }
                    if (!(lookFor.DataType == DataType.Functype && rValue != null && rValue.DataType != DataType.Functype))
                    {
                        EnqueueVariable(rValue);
                    }
                }
            }
            if (0 != (mode & VariableTraceMode.Writes))
            {
                if (lValue == lookFor)
                {
                    TraceExpressionDown(expression);
                }
            }
            if (0 != (mode & VariableTraceMode.Reads))
            {
                var lValueCanon = lValue.Canonicalize();
                if (lValueCanon != null)
                {
                    EnqueueVariable(lValueCanon);
                }
                TraceExpressionDown(expression);
            }
        }