Ejemplo n.º 1
0
        public InstrumentedAssembly InstrumentAssemblyFile(
            InstrumentationContext context,
            FileInfo assemblyFile)
        {
            var assemblyDirectory = assemblyFile.Directory;

            var resolver = new CustomAssemblyResolver(assemblyDirectory, _assemblyResolverLogger);

            _logger.LogTrace("Assembly resolver search directories: {directories}", new object[] { resolver.GetSearchDirectories() });

            try
            {
                using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyFile.FullName, new ReaderParameters {
                    ReadSymbols = true, AssemblyResolver = resolver
                }))
                {
                    return(InstrumentAssemblyDefinition(context, assemblyDefinition));
                }
            }
            catch (BadImageFormatException)
            {
                _logger.LogInformation("Invalid assembly format");
                return(null);
            }
        }
Ejemplo n.º 2
0
        public InstrumentedAssembly InstrumentAssembly(
            InstrumentationContext context,
            FileInfo assemblyFile)
        {
            var assemblyDirectory = assemblyFile.Directory;

            using (_logger.BeginScope("Checking assembly file {assembly}", assemblyFile.FullName, LogLevel.Information))
            {
                if (assemblyFile.Name == "MiniCover.HitServices.dll")
                {
                    _logger.LogInformation("Skipping HitServices");
                    return(null);
                }

                if (_loadedAssemblyFiles.Contains(assemblyFile.FullName))
                {
                    _logger.LogInformation("Can't instrument loaded assembly");
                    return(null);
                }

                var resolver = new CustomAssemblyResolver(assemblyDirectory, _assemblyResolverLogger);

                _logger.LogTrace("Assembly resolver search directories: {directories}", new object[] { resolver.GetSearchDirectories() });

                using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyFile.FullName, new ReaderParameters {
                    ReadSymbols = true, AssemblyResolver = resolver
                }))
                {
                    if (assemblyDefinition.CustomAttributes.Any(a => a.AttributeType.Name == "InstrumentedAttribute"))
                    {
                        _logger.LogInformation("Already instrumented");
                        return(null);
                    }

                    var assemblyDocuments = assemblyDefinition.GetAllDocuments();
                    if (!assemblyDocuments.Any(d => context.IsSource(d) || context.IsTest(d)))
                    {
                        _logger.LogInformation("No link to source files or test files");
                        return(null);
                    }

                    _logger.LogInformation("Instrumenting");

                    var instrumentedAssembly           = new InstrumentedAssembly(assemblyDefinition.Name.Name);
                    var instrumentedAttributeReference = assemblyDefinition.MainModule.ImportReference(instrumentedAttributeConstructor);
                    assemblyDefinition.CustomAttributes.Add(new CustomAttribute(instrumentedAttributeReference));

                    foreach (var type in assemblyDefinition.MainModule.GetTypes())
                    {
                        _typeInstrumenter.InstrumentType(
                            context,
                            type,
                            instrumentedAssembly);
                    }

                    var miniCoverTempPath = GetMiniCoverTempPath();

                    var instrumentedAssemblyFile = new FileInfo(Path.Combine(miniCoverTempPath, $"{Guid.NewGuid()}.dll"));
                    var instrumentedPdbFile      = FileUtils.GetPdbFile(instrumentedAssemblyFile);

                    assemblyDefinition.Write(instrumentedAssemblyFile.FullName, new WriterParameters {
                        WriteSymbols = true
                    });

                    instrumentedAssembly.TempAssemblyFile = instrumentedAssemblyFile.FullName;
                    instrumentedAssembly.TempPdbFile      = instrumentedPdbFile.FullName;

                    return(instrumentedAssembly);
                }
            }
        }
Ejemplo n.º 3
0
        private InstrumentedAssembly InstrumentAssemblyIfNecessary(string assemblyFile)
        {
            var assemblyDirectory = Path.GetDirectoryName(assemblyFile);
            var resolver          = new CustomAssemblyResolver(assemblyDirectory);

            Console.WriteLine($"Assembly resolver search directories:\n{string.Join("\n", resolver.GetSearchDirectories())}\n");
            using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyFile, new ReaderParameters {
                ReadSymbols = true, AssemblyResolver = resolver
            }))
            {
                if (!HasSourceFiles(assemblyDefinition))
                {
                    return(null);
                }

                if (assemblyDefinition.CustomAttributes.Any(a => a.AttributeType.Name == "InstrumentedAttribute"))
                {
                    throw new Exception($"Assembly \"{assemblyFile}\" is already instrumented");
                }

                Console.WriteLine($"Instrumenting assembly \"{assemblyDefinition.Name.Name}\"");

                var instrumentedAssembly           = new InstrumentedAssembly(assemblyDefinition.Name.Name);
                var instrumentedAttributeReference = assemblyDefinition.MainModule.ImportReference(instrumentedAttributeConstructor);
                assemblyDefinition.CustomAttributes.Add(new CustomAttribute(instrumentedAttributeReference));

                var enterMethodInfo          = hitServiceType.GetMethod("EnterMethod");
                var exitMethodInfo           = methodContextType.GetMethod("Exit");
                var hitInstructionMethodInfo = methodContextType.GetMethod("HitInstruction");

                var methodContextClassReference = assemblyDefinition.MainModule.ImportReference(methodContextType);
                var enterMethodReference        = assemblyDefinition.MainModule.ImportReference(enterMethodInfo);
                var exitMethodReference         = assemblyDefinition.MainModule.ImportReference(exitMethodInfo);

                var hitInstructionReference = assemblyDefinition.MainModule.ImportReference(hitInstructionMethodInfo);

                var methods = assemblyDefinition.GetAllMethods()
                              .Where(m =>
                                     !(m.DeclaringType.CustomAttributes
                                       .Any(attribute =>
                                            attribute.AttributeType.FullName == "System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute") ||
                                       m.DeclaringType.DeclaringType?.CustomAttributes?
                                       .Any(attribute =>
                                            attribute.AttributeType.FullName == "System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute") == true));

                var documentsGroups = methods
                                      .SelectMany(m => m.DebugInformation.SequencePoints, (method, s) => new
                {
                    Method        = method,
                    SequencePoint = s,
                    s.Document
                })
                                      .GroupBy(j => j.Document)
                                      .ToArray();

                foreach (var documentGroup in documentsGroups)
                {
                    if (!sourceFiles.Contains(documentGroup.Key.Url))
                    {
                        continue;
                    }

                    var sourceRelativePath = GetSourceRelativePath(documentGroup.Key.Url);

                    if (documentGroup.Key.FileHasChanged())
                    {
                        Console.WriteLine($"Ignoring modified file \"{documentGroup.Key.Url}\"");
                        continue;
                    }

                    var fileLines = File.ReadAllLines(documentGroup.Key.Url);

                    var methodGroups = documentGroup
                                       .GroupBy(j => j.Method, j => j.SequencePoint)
                                       .ToArray();

                    foreach (var methodGroup in methodGroups)
                    {
                        var methodDefinition = methodGroup.Key;

                        InstrumentMethod(methodDefinition, methodGroup, methodContextClassReference, enterMethodReference, exitMethodReference, fileLines, instrumentedAssembly, sourceRelativePath, hitInstructionReference);
                    }
                }

                var miniCoverTempPath = GetMiniCoverTempPath();

                var instrumentedAssemblyFile = Path.Combine(miniCoverTempPath, $"{Guid.NewGuid()}.dll");
                var instrumentedPdbFile      = GetPdbFile(instrumentedAssemblyFile);

                assemblyDefinition.Write(instrumentedAssemblyFile, new WriterParameters {
                    WriteSymbols = true
                });

                instrumentedAssembly.TempAssemblyFile = instrumentedAssemblyFile;
                instrumentedAssembly.TempPdbFile      = instrumentedPdbFile;

                return(instrumentedAssembly);
            }
        }