public static StackPushInformation CreateCopy(string stackName, StackPushInformation pushInformation)
 {
     return(new StackPushInformation(stackName)
     {
         FromCopy = pushInformation
     });
 }
 public static StackPushInformation CreateFromStack(string stackName, StackPushInformation stack)
 {
     return(new StackPushInformation(stackName)
     {
         FromStack = stack, IsReference = stack.IsReference
     });
 }
        private bool LdArgTransactions(Node node, IList <StackPushInformation> stackTransactions)
        {
            // Get argument index
            int argumentIndex = node.OpCode.GetArgumentIndex(node.Operand);

            if (node.Block.Method.Definition.HasThis)
            {
                // Handle this argument
                if (argumentIndex == 0)
                {
                    stackTransactions.Add(
                        StackPushInformation.CreateFromThisArgument(node.PushStackNames.Single(), node.Block.Method.Definition.DeclaringType));
                    return(true);
                }

                // Decrement with 1 to get correct argument
                argumentIndex--;
            }

            // Get argument
            ArgumentInformation argument = _argumentInformations[argumentIndex];
            bool isReference             = node.OpCode.Code == Code.Ldarga || node.OpCode.Code == Code.Ldarga_S;

            stackTransactions.Add(StackPushInformation.CreateFromArgument(node.PushStackNames.Single(), argument, isReference));
            return(true);
        }
        internal void AddStackInformation(string stLocPopName, StackPushInformation stTrans)
        {
            if (!_fromStackInformation.Any(s => s.StackName == stLocPopName))
            {
                _fromStackInformation.Add(stTrans);
            }

            NotAssignedStackInformation.Remove(stLocPopName);
        }
        private bool LdFldTransactions(Node node, List <StackPushInformation> stackTransactions)
        {
            // Get field index
            FieldDefinition field       = node.OpCode.GetField(node.Operand).Resolve();
            bool            isReference = node.OpCode.Code == Code.Ldflda || node.OpCode.Code == Code.Ldsflda;

            stackTransactions.Add(StackPushInformation.CreateFromField(node.PushStackNames.Single(), field, isReference));
            return(true);
        }
        private bool LdLocTransactions(Node node, List <StackPushInformation> stackTransactions)
        {
            // Get variable index
            int variableIndex = node.OpCode.GetVariableIndex(node.Operand);

            // Get argument
            var  variable    = _variableDefinitions[variableIndex];
            bool isReference = node.OpCode.Code == Code.Ldloca || node.OpCode.Code == Code.Ldloca_S;

            stackTransactions.Add(StackPushInformation.CreateFromVariable(node.PushStackNames.Single(), variable, isReference));
            return(true);
        }
        private bool NewObjTransactions(Node node, IList <StackPushInformation> stackTransactions)
        {
            if (node.Operand is MethodReference constructor)
            {
                // Resolve the new initilized type
                var type = constructor.DeclaringType.Resolve();
                stackTransactions.Add(StackPushInformation.CreateFromNewObj(node.PushStackNames.Single(), type));

                return(true);
            }

            // The operand should be a MethodReference - if not - we currently don't handle it
            throw new NotSupportedException();
        }
        private bool CallTransactions(Node node, IList <StackPushInformation> stackTransactions)
        {
            if (node.Operand is MethodReference method)
            {
                // Resolve the result type and detect if it's a void method
                var returnType = GetGenericType(method, method.ReturnType);
                if (returnType.IsVoid())
                {
                    return(false);
                }

                // Get method definition
                var methodDefinition = method.Resolve();
                stackTransactions.Add(StackPushInformation.CreateFromMethodCall(node.PushStackNames.Single(), methodDefinition));

                return(true);
            }

            // The operand should be a MethodReference - if not - we currently don't handle it
            throw new NotSupportedException();
        }
        public override void Visit(Node node)
        {
            // Add and get list with stack transactions
            if (!_stackTransactions.ContainsKey(node))
            {
                _stackTransactions.Add(node, new List <StackPushInformation>());
            }
            List <StackPushInformation> stackTransactions = _stackTransactions[node];

            // If there are already tranactions registrered we just skip the node
            if (stackTransactions.Any())
            {
                return;
            }

            // Switch on opcode
            switch (node.OpCode.Code)
            {
            case Code.Newobj:
                _changed |= NewObjTransactions(node, stackTransactions);
                break;

            case Code.Call:
            case Code.Calli:
            case Code.Callvirt:
                _changed |= CallTransactions(node, stackTransactions);
                break;

            case Code.Ldarg:
            case Code.Ldarga:
                _changed |= LdArgTransactions(node, stackTransactions);
                break;

            // Load field
            case Code.Ldfld:
            case Code.Ldflda:
            // Load static field
            case Code.Ldsfld:
            case Code.Ldsflda:
                _changed |= LdFldTransactions(node, stackTransactions);
                break;

            case Code.Ldloc:
            case Code.Ldloca:
                _changed |= LdLocTransactions(node, stackTransactions);
                break;

            case Code.Stloc:
            case Code.Stloc_S:
                // Get variable index
                int variableIndex = node.OpCode.GetVariableIndex(node.Operand);

                // Get argument
                var variable = _variableDefinitions[variableIndex];

                // Get pop
                var stLocPopName = node.PopStackNames.Single();

                // Find stack tranaction
                var stTrans = _stackTransactions.SelectMany(e => e.Value).SingleOrDefault(e => e.StackName == stLocPopName);
                if (stTrans == null)
                {
                    variable.AddStackInformation(stLocPopName);
                    break;
                }

                // Add transaction to index
                variable.AddStackInformation(stLocPopName, stTrans);

                break;

            case Code.Ldc_I8:
                stackTransactions.Add(StackPushInformation.CreateFromConstant(node.PushStackNames.Single(), (long)node.Operand));

                // Set changed
                _changed = true;
                break;

            case Code.Ldc_R8:
                stackTransactions.Add(StackPushInformation.CreateFromFloatingPointConstant(node.PushStackNames.Single(), (double)node.Operand));

                // Set changed
                _changed = true;
                break;

            case Code.Ldnull:
                stackTransactions.Add(StackPushInformation.CreateFromNull(node.PushStackNames.Single()));

                // Set changed
                _changed = true;
                break;

            case Code.Ldstr:
                stackTransactions.Add(StackPushInformation.CreateFromString(node.PushStackNames.Single(), node.Operand as string));

                // Set changed
                _changed = true;
                break;

            case Code.Neg:
            case Code.Not:
            case Code.Dup:
                // Get pop instruction
                var popName = node.PopStackNames.Single();
                var popNode = node.Block.Method.Blocks.SelectMany(e => e.Nodes)
                              .Distinct().SingleOrDefault(n => n.PushStackNames.Any(e => e == popName));

                // If we cannot find it - we wait
                if (popNode == null)
                {
                    break;
                }

                // Get transaction for this node
                if (!_stackTransactions.ContainsKey(popNode))
                {
                    break;
                }

                // Get sources (there should only be one source)
                var source = _stackTransactions[popNode].SingleOrDefault(transaction => transaction.StackName == popName);
                if (source == null)
                {
                    break;
                }

                // Get pushName
                var pushNames = node.PushStackNames.OrderBy(e => e);
                foreach (var pushName in pushNames)
                {
                    // Add transaction
                    stackTransactions.Add(StackPushInformation.CreateCopy(pushName, source));
                }

                // Set changed
                _changed = true;
                break;

            case Code.Castclass:
                // TODO: Easy to implement
                break;

            case Code.Isinst:
                // TODO:
                break;

            case Code.Ldtoken:
            case Code.Ldftn:
            case Code.Ldvirtftn:
                break;

            case Code.Ceq:
            case Code.Cgt:
            case Code.Cgt_Un:
            case Code.Clt:
            case Code.Clt_Un:
                // TODO:
                break;

            case Code.Add:
            case Code.Add_Ovf:
            case Code.Add_Ovf_Un:
            case Code.Sub:
            case Code.Sub_Ovf:
            case Code.Sub_Ovf_Un:
            case Code.Mul:
            case Code.Mul_Ovf:
            case Code.Mul_Ovf_Un:
            case Code.Div:
            case Code.Div_Un:
            case Code.Rem:
            case Code.Rem_Un:
                // TODO:
                break;

            case Code.And:
            case Code.Or:
            case Code.Xor:
                // TODO:
                break;

            case Code.Box:
            case Code.Unbox:
            case Code.Unbox_Any:
                // TODO:
                break;

            case Code.Conv_I1:
            case Code.Conv_I2:
            case Code.Conv_I4:
            case Code.Conv_I8:
                // TODO:
                break;

            case Code.Conv_R4:
            case Code.Conv_R8:
            case Code.Conv_R_Un:
                // TODO:
                break;

            case Code.Sizeof:
                // TODO:
                break;

            case Code.Ldobj:
                // TODO:
                break;

            case Code.Newarr:
            case Code.Ldelem_Any:
            case Code.Ldelem_I1:
            case Code.Ldelem_I2:
            case Code.Ldelem_I4:
            case Code.Ldelem_I8:
            case Code.Ldelem_R4:
            case Code.Ldelem_R8:
            case Code.Ldelem_Ref:
            case Code.Ldlen:
                break;

            default:
                // We need to handle all nodes which pushes to the stack
                Debug.Assert(node.PushCountFromStack == 0);
                break;
            }

            base.Visit(node);
        }