private void EmitMethodExitChecks(
            [NotNull] MethodDefinition methodDefinition, [NotNull] HashSet <int> positions)
        {
            var         outputChecks    = new Queue <Instruction[]>();
            Instruction lastInstruction = null;

            // walk over parameters in reverse order to build checks stack
            var parameters = methodDefinition.Parameters;

            for (var index1 = parameters.Count - 1; index1 >= 0; index1--)
            {
                var parameterDefinition = parameters[index1];
                if (!positions.Contains(parameterDefinition.Index))
                {
                    continue;
                }

                var parameterType = parameterDefinition.ParameterType;
                if (parameterType.IsByReference)
                {
                    if (!ChecksEmitUtil.IsNullableType(parameterType))
                    {
                        LogInfo(string.Format(
                                    "Invalid annotation usage in member {0} at parameter '{1}'.",
                                    methodDefinition.GetXmlDocId(), parameterDefinition.Name));
                        continue;
                    }

                    lastInstruction = lastInstruction ?? Instruction.Create(OpCodes.Ret);
                    var target = (outputChecks.Count > 0) ? outputChecks.Peek()[0] : lastInstruction;

                    var checkInstructions = ChecksEmitUtil.EmitNullCheckInstructions(
                        parameterDefinition, parameterType, ArgumentNullCtor, target,
                        parameterDefinition.Name, "Output parameter [NotNull] contract violation");

                    outputChecks.Enqueue(checkInstructions);
                }
            }

            var returnType       = methodDefinition.MethodReturnType;
            var checkReturnValue = false;

            if (positions.Contains(-1)) // check annotated return
            {
                if (ChecksEmitUtil.IsNullableType(returnType.ReturnType) && !returnType.ReturnType.IsByReference)
                {
                    lastInstruction = lastInstruction ?? Instruction.Create(OpCodes.Ret);
                    var target = (outputChecks.Count > 0) ? outputChecks.Peek()[0] : lastInstruction;

                    var checkInstructions = ChecksEmitUtil.EmitNullCheckInstructions(
                        null, returnType.ReturnType, ArgumentNullCtor, target,
                        "$return$", "Return value [NotNull] contract violation");

                    outputChecks.Enqueue(checkInstructions);
                    checkReturnValue = true;
                }
                else
                {
                    LogInfo(string.Format(
                                "Invalid annotation usage in member {0} at return value.",
                                methodDefinition.GetXmlDocId()));
                }
            }

            if (outputChecks.Count == 0)
            {
                return;
            }

            var instructions   = methodDefinition.Body.Instructions;
            var retInstruction = instructions[instructions.Count - 1];

            // replace ret with nop or dup (if return value check required)
            retInstruction.OpCode  = checkReturnValue ? OpCodes.Dup : OpCodes.Nop;
            retInstruction.Operand = null;

            foreach (var instruction in outputChecks.Dequeue())
            {
                instructions.Add(instruction);
            }

            instructions.Add(lastInstruction);
        }
        // todo: what about checks field for null?
        private void EmitFieldChecks([NotNull] MethodDefinition methodDefinition)
        {
            var methodBody = methodDefinition.Body;

            if (methodBody == null)
            {
                return;
            }

            var instructions = methodBody.Instructions;

            if (instructions.Count == 0)
            {
                return;
            }

            List <Instruction> modifiedBody = null;

            for (var index = 0; index < instructions.Count; index++)
            {
                var instruction = instructions[index];
                var opCode      = instruction.OpCode;

                switch (opCode.Code)
                {
                case Code.Ldfld:
                case Code.Stfld:
                case Code.Ldsfld:
                case Code.Stsfld: {
                    var fieldReference = instruction.Operand as FieldReference;
                    if (fieldReference == null)
                    {
                        break;
                    }

                    if (!Attributes.IsNotNullAnnotated(fieldReference))
                    {
                        break;
                    }
                    if (!ChecksEmitUtil.IsNullableType(fieldReference.FieldType))
                    {
                        LogInfo(string.Format(
                                    "Invalid annotation usage at field {0}.", fieldReference.GetXmlDocId()));
                        break;
                    }

                    if (modifiedBody == null)
                    {
                        modifiedBody = new List <Instruction>(instructions.Count);
                        for (var index2 = 0; index2 < index; index2++)
                        {
                            modifiedBody.Add(instructions[index2]);
                        }
                    }

                    var readAccess = (opCode == OpCodes.Ldfld || opCode == OpCodes.Ldsfld);
                    if (readAccess)
                    {
                        modifiedBody.Add(instruction);     // ldfld
                    }
                    modifiedBody.Add(Instruction.Create(OpCodes.Dup));

                    var nextInstruction   = instructions[index + 1];
                    var checkInstructions = ChecksEmitUtil.EmitNullCheckInstructions(
                        null, fieldReference.FieldType, ArgumentNullCtor,
                        nextInstruction, fieldReference.Name, "Field [NotNull] contract violation");

                    foreach (var instr in checkInstructions)
                    {
                        modifiedBody.Add(instr);
                    }

                    if (!readAccess)
                    {
                        modifiedBody.Add(instruction); // stfld
                    }
                    continue;                          // yes, we handled
                }
                }

                if (modifiedBody != null)
                {
                    modifiedBody.Add(instruction);
                }
            }

            if (modifiedBody != null)
            {
                instructions.Clear();
                foreach (var x in modifiedBody)
                {
                    instructions.Add(x);
                }
            }
        }
        private void EmitMethodEnterChecks(
            [NotNull] MethodDefinition methodDefinition, [NotNull] HashSet <int> positions)
        {
            var         inputСhecks      = new Stack <Instruction[]>();
            Instruction firstInstruction = null;

            // walk over parameters in reverse order to build checks stack
            var parameters = methodDefinition.Parameters;

            for (var index1 = parameters.Count - 1; index1 >= 0; index1--)
            {
                var parameterDefinition = parameters[index1];
                if (parameterDefinition.IsOut)
                {
                    continue;
                }

                if (!positions.Contains(parameterDefinition.Index))
                {
                    continue;
                }

                var parameterType = parameterDefinition.ParameterType;
                if (!ChecksEmitUtil.IsNullableType(parameterType))
                {
                    LogInfo(string.Format(
                                "Invalid annotation usage in member {0} at parameter '{1}'.",
                                methodDefinition.GetXmlDocId(), parameterDefinition.Name));
                    continue;
                }

                if (firstInstruction == null)
                {
                    var instrictions = methodDefinition.Body.Instructions;
                    if (instrictions.Count == 0)
                    {
                        return;                // shit happens
                    }
                    firstInstruction = instrictions[0];
                }

                var checkInstructions = ChecksEmitUtil.EmitNullCheckInstructions(
                    parameterDefinition, parameterType, ArgumentNullCtor, firstInstruction,
                    parameterDefinition.Name, "Input parameter [NotNull] contract violation");

                inputСhecks.Push(checkInstructions);
                firstInstruction = checkInstructions[0];
            }

            if (inputСhecks.Count == 0)
            {
                return;
            }

            var instructions = methodDefinition.Body.Instructions;
            var oldBody      = instructions.ToArray();

            instructions.Clear();

            while (inputСhecks.Count > 0)
            {
                foreach (var instruction in inputСhecks.Pop())
                {
                    instructions.Add(instruction);
                }
            }

            foreach (var instruction in oldBody)
            {
                instructions.Add(instruction);
            }
        }