private static XElement CreateMethodElement(InstrumentedMethod method, IEnumerable <InstrumentedSequence> instructions, HitsInfo hitsInfo)
        {
            var allLines = instructions
                           .SelectMany(i => i.GetLines())
                           .Distinct()
                           .Count();

            var coveredLines = instructions
                               .Where(h => hitsInfo.WasHit(h.HitId))
                               .SelectMany(i => i.GetLines())
                               .Distinct()
                               .Count();

            var allBranches = instructions
                              .SelectMany(i => i.Conditions)
                              .SelectMany(c => c.Branches)
                              .Count();

            var coveredBranches = instructions
                                  .SelectMany(i => i.Conditions)
                                  .SelectMany(c => c.Branches)
                                  .Where(b => hitsInfo.WasHit(b.HitId))
                                  .Count();

            var lineRate   = allLines == 0 ? 1d : (double)coveredLines / (double)allLines;
            var branchRate = allBranches == 0 ? 1d : (double)coveredBranches / (double)allBranches;

            var openParametersIndex = method.FullName.IndexOf("(");
            var signature           = method.FullName.Substring(openParametersIndex);

            return(new XElement(
                       XName.Get("method"),
                       new XAttribute(XName.Get("name"), method.Name),
                       new XAttribute(XName.Get("signature"), signature),
                       new XAttribute(XName.Get("line-rate"), lineRate),
                       new XAttribute(XName.Get("branch-rate"), branchRate),
                       new XAttribute(XName.Get("complexity"), 0),
                       CreateLinesElement(instructions, hitsInfo)
                       ));
        }
        private void InstrumentInstructions(
            InstrumentationContext context,
            MethodDefinition methodDefinition,
            InstrumentedAssembly instrumentedAssembly,
            Dictionary <int, Instruction> instructionsByOffset,
            ILProcessor ilProcessor,
            VariableDefinition methodContextVariable,
            InstrumentedMethod instrumentedMethod)
        {
            var hitInstructionReference = methodDefinition.Module.GetOrImportReference(hitInstructionMethodInfo);

            foreach (var sequencePoint in methodDefinition.DebugInformation.SequencePoints)
            {
                var document = sequencePoint.Document;

                if (document.FileHasChanged())
                {
                    _logger.LogInformation("Ignoring modified file {file}", document.Url);
                    continue;
                }

                if (sequencePoint.IsHidden)
                {
                    continue;
                }

                var documentUrl = sequencePoint.Document.Url;

                var documentLines = _fileReader.ReadAllLines(new FileInfo(documentUrl));

                var code = documentLines.ExtractCode(
                    sequencePoint.StartLine,
                    sequencePoint.EndLine,
                    sequencePoint.StartColumn,
                    sequencePoint.EndColumn);

                if (code == null || code == "{" || code == "}")
                {
                    continue;
                }

                var instruction = instructionsByOffset[sequencePoint.Offset];

                // if the previous instruction is a Prefix instruction then this instruction MUST go with it.
                // we cannot put an instruction between the two.
                if (instruction.Previous != null && instruction.Previous.OpCode.OpCodeType == OpCodeType.Prefix)
                {
                    continue;
                }

                if (!ilProcessor.Body.Instructions.Contains(instruction))
                {
                    var methodFullName = $"{methodDefinition.DeclaringType.FullName}.{methodDefinition.Name}";
                    _logger.LogWarning("Skipping instruction because it was removed from method {method}", methodFullName);
                    continue;
                }

                var sourceRelativePath = GetSourceRelativePath(context, documentUrl);

                var instructionId = ++context.InstructionId;

                instrumentedAssembly.AddInstruction(sourceRelativePath, new InstrumentedInstruction
                {
                    Id          = instructionId,
                    StartLine   = sequencePoint.StartLine,
                    EndLine     = sequencePoint.EndLine,
                    StartColumn = sequencePoint.StartColumn,
                    EndColumn   = sequencePoint.EndColumn,
                    Instruction = instruction.ToString(),
                    Method      = instrumentedMethod,
                    Code        = code
                });

                ilProcessor.InsertBefore(instruction, new[]
                {
                    ilProcessor.Create(OpCodes.Ldloc, methodContextVariable),
                    ilProcessor.Create(OpCodes.Ldc_I4, instructionId),
                    ilProcessor.Create(OpCodes.Callvirt, hitInstructionReference)
                }, true);
            }
        }