Merge branch 'exclude-files-by-path' of github.com:ido-namely/coverlet into exclude-files-by-path

This commit is contained in:
Ido David
2018-04-28 21:38:41 -04:00
4 changed files with 820 additions and 0 deletions
@@ -0,0 +1,217 @@
using System.IO;
using System.Linq;
using Coverlet.Core.Helpers;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using System;
using System.Xml.Linq;
namespace Coverlet.Core.Instrumentation
{
internal class Instrumenter
{
<<<<<<< HEAD
private readonly string _module;
private readonly string _identifier;
=======
private string _module;
private string _identifier;
>>>>>>> ccdca640f08350752297e2a68b8daf41cc6ced59
private IEnumerable<string> _excludedFiles;
private InstrumenterResult _result;
public Instrumenter(string module, string identifier, IEnumerable<string> excludedFiles = null)
{
_module = module;
_identifier = identifier;
_excludedFiles = excludedFiles ?? Enumerable.Empty<string>();
}
public bool CanInstrument() => InstrumentationHelper.HasPdb(_module);
public InstrumenterResult Instrument()
{
string hitsFilePath = Path.Combine(
Path.GetTempPath(),
Path.GetFileNameWithoutExtension(_module) + "_" + _identifier
);
_result = new InstrumenterResult
{
Module = Path.GetFileNameWithoutExtension(_module),
HitsFilePath = hitsFilePath,
ModulePath = _module
};
InstrumentModule();
InstrumentationHelper.CopyCoverletDependency(_module);
return _result;
}
private void InstrumentModule()
{
using (var stream = new FileStream(_module, FileMode.Open, FileAccess.ReadWrite))
using (var resolver = new DefaultAssemblyResolver())
{
resolver.AddSearchDirectory(Path.GetDirectoryName(_module));
var parameters = new ReaderParameters { ReadSymbols = true, AssemblyResolver = resolver };
using (var module = ModuleDefinition.ReadModule(stream, parameters))
{
foreach (var type in module.GetTypes())
{
<<<<<<< HEAD
if (type.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage"))
continue;
foreach (var method in type.Methods)
{
var sourceFile = method.DebugInformation.SequencePoints.Select(s => s.Document.Url).FirstOrDefault();
if (!string.IsNullOrEmpty(sourceFile) && _excludedFiles.Contains(sourceFile)) {
continue;
}
if (!method.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage"))
InstrumentMethod(method);
}
=======
var sourceFile = method.DebugInformation.SequencePoints.Select(s => s.Document.Url).FirstOrDefault();
if (!string.IsNullOrEmpty(sourceFile) && _excludedFiles.Contains(sourceFile)) {
continue;
}
if (!method.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage"))
InstrumentMethod(method);
>>>>>>> ccdca640f08350752297e2a68b8daf41cc6ced59
}
module.Write(stream);
}
}
}
private void InstrumentMethod(MethodDefinition method)
{
if (!method.HasBody)
return;
InstrumentIL(method);
}
private void InstrumentIL(MethodDefinition method)
{
ILProcessor processor = method.Body.GetILProcessor();
var index = 0;
var count = processor.Body.Instructions.Count;
for (int n = 0; n < count; n++)
{
var instruction = processor.Body.Instructions[index];
var sequencePoint = method.DebugInformation.GetSequencePoint(instruction);
if (sequencePoint == null || sequencePoint.StartLine == 16707566)
{
index++;
continue;
}
var target = AddInstrumentationCode(method, processor, instruction, sequencePoint);
foreach (var _instruction in processor.Body.Instructions)
ReplaceInstructionTarget(_instruction, instruction, target);
foreach (ExceptionHandler handler in processor.Body.ExceptionHandlers)
ReplaceExceptionHandlerBoundary(handler, instruction, target);
index += 4;
}
method.Body.SimplifyMacros();
method.Body.OptimizeMacros();
}
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint)
{
var document = _result.Documents.FirstOrDefault(d => d.Path == sequencePoint.Document.Url);
if (document == null)
{
document = new Document { Path = sequencePoint.Document.Url };
_result.Documents.Add(document);
}
for (int i = sequencePoint.StartLine; i <= sequencePoint.EndLine; i++)
{
if (!document.Lines.Exists(l => l.Number == i))
document.Lines.Add(new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName });
}
string flag = IsBranchTarget(processor, instruction) ? "B" : "L";
string marker = $"{document.Path},{sequencePoint.StartLine},{sequencePoint.EndLine},{flag}";
var pathInstr = Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath);
var markInstr = Instruction.Create(OpCodes.Ldstr, marker);
var callInstr = Instruction.Create(OpCodes.Call, processor.Body.Method.Module.ImportReference(typeof(CoverageTracker).GetMethod("MarkExecuted")));
processor.InsertBefore(instruction, callInstr);
processor.InsertBefore(callInstr, markInstr);
processor.InsertBefore(markInstr, pathInstr);
return pathInstr;
}
private static bool IsBranchTarget(ILProcessor processor, Instruction instruction)
{
foreach (var _instruction in processor.Body.Instructions)
{
if (_instruction.Operand is Instruction target)
{
if (target == instruction)
return true;
}
if (_instruction.Operand is Instruction[] targets)
return targets.Any(t => t == instruction);
}
return false;
}
private static void ReplaceInstructionTarget(Instruction instruction, Instruction oldTarget, Instruction newTarget)
{
if (instruction.Operand is Instruction _instruction)
{
if (_instruction == oldTarget)
{
instruction.Operand = newTarget;
return;
}
}
else if (instruction.Operand is Instruction[] _instructions)
{
for (int i = 0; i < _instructions.Length; i++)
{
if (_instructions[i] == oldTarget)
_instructions[i] = newTarget;
}
}
}
private static void ReplaceExceptionHandlerBoundary(ExceptionHandler handler, Instruction oldTarget, Instruction newTarget)
{
if (handler.FilterStart == oldTarget)
handler.FilterStart = newTarget;
if (handler.HandlerEnd == oldTarget)
handler.HandlerEnd = newTarget;
if (handler.HandlerStart == oldTarget)
handler.HandlerStart = newTarget;
if (handler.TryEnd == oldTarget)
handler.TryEnd = newTarget;
if (handler.TryStart == oldTarget)
handler.TryStart = newTarget;
}
}
}
@@ -0,0 +1,196 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Coverlet.Core.Helpers;
using Coverlet.Core.Extensions;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
namespace Coverlet.Core.Instrumentation
{
internal class Instrumenter
{
private string _module;
private string _identifier;
private InstrumenterResult _result;
public Instrumenter(string module, string identifier)
{
_module = module;
_identifier = identifier;
}
public bool CanInstrument() => InstrumentationHelper.HasPdb(_module);
public InstrumenterResult Instrument()
{
string hitsFilePath = Path.Combine(
Path.GetTempPath(),
Path.GetFileNameWithoutExtension(_module) + "_" + _identifier
);
_result = new InstrumenterResult
{
Module = Path.GetFileNameWithoutExtension(_module),
HitsFilePath = hitsFilePath,
ModulePath = _module
};
InstrumentModule();
InstrumentationHelper.CopyCoverletDependency(_module);
return _result;
}
private void InstrumentModule()
{
using (var stream = new FileStream(_module, FileMode.Open, FileAccess.ReadWrite))
{
var resolver = new DefaultAssemblyResolver();
resolver.AddSearchDirectory(Path.GetDirectoryName(_module));
var parameters = new ReaderParameters { ReadSymbols = true, AssemblyResolver = resolver };
ModuleDefinition module = ModuleDefinition.ReadModule(stream, parameters);
foreach (var type in module.GetTypes())
{
if (type.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage"))
continue;
foreach (var method in type.Methods)
{
if (!method.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage"))
InstrumentMethod(method);
}
}
module.Write(stream);
}
}
private void InstrumentMethod(MethodDefinition method)
{
if (!method.HasBody)
return;
InstrumentIL(method);
}
private void InstrumentIL(MethodDefinition method)
{
ILProcessor processor = method.Body.GetILProcessor();
var index = 0;
var count = processor.Body.Instructions.Count;
for (int n = 0; n < count; n++)
{
var instruction = processor.Body.Instructions[index];
var sequencePoint = method.DebugInformation.GetSequencePoint(instruction);
if (sequencePoint == null || sequencePoint.StartLine == 16707566)
{
index++;
continue;
}
var target = AddInstrumentationCode(method, processor, instruction, sequencePoint);
foreach (var _instruction in processor.Body.Instructions)
ReplaceInstructionTarget(_instruction, instruction, target);
foreach (ExceptionHandler handler in processor.Body.ExceptionHandlers)
ReplaceExceptionHandlerBoundary(handler, instruction, target);
index += 4;
}
method.Body.SimplifyMacros();
method.Body.OptimizeMacros();
}
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint)
{
var document = _result.Documents.FirstOrDefault(d => d.Path == sequencePoint.Document.Url);
if (document == null)
{
document = new Document { Path = sequencePoint.Document.Url };
_result.Documents.Add(document);
}
for (int i = sequencePoint.StartLine; i <= sequencePoint.EndLine; i++)
{
if (!document.Lines.Exists(l => l.Number == i))
document.Lines.Add(new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName });
}
string flag = IsBranchTarget(processor, instruction) ? "B" : "L";
string marker = $"{document.Path},{sequencePoint.StartLine},{sequencePoint.EndLine},{flag}";
var pathInstr = Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath);
var markInstr = Instruction.Create(OpCodes.Ldstr, marker);
var callInstr = Instruction.Create(OpCodes.Call, processor.Body.Method.Module.ImportReference(typeof(CoverageTracker).GetMethod("MarkExecuted")));
processor.InsertBefore(instruction, callInstr);
processor.InsertBefore(callInstr, markInstr);
processor.InsertBefore(markInstr, pathInstr);
return pathInstr;
}
private bool IsBranchTarget(ILProcessor processor, Instruction instruction)
{
foreach (var _instruction in processor.Body.Instructions)
{
if (_instruction.Operand is Instruction target)
{
if (target == instruction)
return true;
}
if (_instruction.Operand is Instruction[] targets)
return targets.Any(t => t == instruction);
}
return false;
}
private void ReplaceInstructionTarget(Instruction instruction, Instruction oldTarget, Instruction newTarget)
{
if (instruction.Operand is Instruction _instruction)
{
if (_instruction == oldTarget)
{
instruction.Operand = newTarget;
return;
}
}
else if (instruction.Operand is Instruction[] _instructions)
{
for (int i = 0; i < _instructions.Length; i++)
{
if (_instructions[i] == oldTarget)
_instructions[i] = newTarget;
}
}
}
private void ReplaceExceptionHandlerBoundary(ExceptionHandler handler, Instruction oldTarget, Instruction newTarget)
{
if (handler.FilterStart == oldTarget)
handler.FilterStart = newTarget;
if (handler.HandlerEnd == oldTarget)
handler.HandlerEnd = newTarget;
if (handler.HandlerStart == oldTarget)
handler.HandlerStart = newTarget;
if (handler.TryEnd == oldTarget)
handler.TryEnd = newTarget;
if (handler.TryStart == oldTarget)
handler.TryStart = newTarget;
}
}
}
@@ -0,0 +1,203 @@
using System.IO;
using System.Linq;
using Coverlet.Core.Helpers;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using System;
using System.Xml.Linq;
namespace Coverlet.Core.Instrumentation
{
internal class Instrumenter
{
private readonly string _module;
private readonly string _identifier;
private IEnumerable<string> _excludedFiles;
private InstrumenterResult _result;
public Instrumenter(string module, string identifier, IEnumerable<string> excludedFiles = null)
{
_module = module;
_identifier = identifier;
_excludedFiles = excludedFiles ?? Enumerable.Empty<string>();
}
public bool CanInstrument() => InstrumentationHelper.HasPdb(_module);
public InstrumenterResult Instrument()
{
string hitsFilePath = Path.Combine(
Path.GetTempPath(),
Path.GetFileNameWithoutExtension(_module) + "_" + _identifier
);
_result = new InstrumenterResult
{
Module = Path.GetFileNameWithoutExtension(_module),
HitsFilePath = hitsFilePath,
ModulePath = _module
};
InstrumentModule();
InstrumentationHelper.CopyCoverletDependency(_module);
return _result;
}
private void InstrumentModule()
{
using (var stream = new FileStream(_module, FileMode.Open, FileAccess.ReadWrite))
using (var resolver = new DefaultAssemblyResolver())
{
resolver.AddSearchDirectory(Path.GetDirectoryName(_module));
var parameters = new ReaderParameters { ReadSymbols = true, AssemblyResolver = resolver };
using (var module = ModuleDefinition.ReadModule(stream, parameters))
{
foreach (var type in module.GetTypes())
{
if (type.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage"))
continue;
foreach (var method in type.Methods)
{
var sourceFile = method.DebugInformation.SequencePoints.Select(s => s.Document.Url).FirstOrDefault();
if (!string.IsNullOrEmpty(sourceFile) && _excludedFiles.Contains(sourceFile)) {
continue;
}
if (!method.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage"))
InstrumentMethod(method);
}
}
module.Write(stream);
}
}
}
private void InstrumentMethod(MethodDefinition method)
{
if (!method.HasBody)
return;
InstrumentIL(method);
}
private void InstrumentIL(MethodDefinition method)
{
ILProcessor processor = method.Body.GetILProcessor();
var index = 0;
var count = processor.Body.Instructions.Count;
for (int n = 0; n < count; n++)
{
var instruction = processor.Body.Instructions[index];
var sequencePoint = method.DebugInformation.GetSequencePoint(instruction);
if (sequencePoint == null || sequencePoint.StartLine == 16707566)
{
index++;
continue;
}
var target = AddInstrumentationCode(method, processor, instruction, sequencePoint);
foreach (var _instruction in processor.Body.Instructions)
ReplaceInstructionTarget(_instruction, instruction, target);
foreach (ExceptionHandler handler in processor.Body.ExceptionHandlers)
ReplaceExceptionHandlerBoundary(handler, instruction, target);
index += 4;
}
method.Body.SimplifyMacros();
method.Body.OptimizeMacros();
}
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint)
{
var document = _result.Documents.FirstOrDefault(d => d.Path == sequencePoint.Document.Url);
if (document == null)
{
document = new Document { Path = sequencePoint.Document.Url };
_result.Documents.Add(document);
}
for (int i = sequencePoint.StartLine; i <= sequencePoint.EndLine; i++)
{
if (!document.Lines.Exists(l => l.Number == i))
document.Lines.Add(new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName });
}
string flag = IsBranchTarget(processor, instruction) ? "B" : "L";
string marker = $"{document.Path},{sequencePoint.StartLine},{sequencePoint.EndLine},{flag}";
var pathInstr = Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath);
var markInstr = Instruction.Create(OpCodes.Ldstr, marker);
var callInstr = Instruction.Create(OpCodes.Call, processor.Body.Method.Module.ImportReference(typeof(CoverageTracker).GetMethod("MarkExecuted")));
processor.InsertBefore(instruction, callInstr);
processor.InsertBefore(callInstr, markInstr);
processor.InsertBefore(markInstr, pathInstr);
return pathInstr;
}
private static bool IsBranchTarget(ILProcessor processor, Instruction instruction)
{
foreach (var _instruction in processor.Body.Instructions)
{
if (_instruction.Operand is Instruction target)
{
if (target == instruction)
return true;
}
if (_instruction.Operand is Instruction[] targets)
return targets.Any(t => t == instruction);
}
return false;
}
private static void ReplaceInstructionTarget(Instruction instruction, Instruction oldTarget, Instruction newTarget)
{
if (instruction.Operand is Instruction _instruction)
{
if (_instruction == oldTarget)
{
instruction.Operand = newTarget;
return;
}
}
else if (instruction.Operand is Instruction[] _instructions)
{
for (int i = 0; i < _instructions.Length; i++)
{
if (_instructions[i] == oldTarget)
_instructions[i] = newTarget;
}
}
}
private static void ReplaceExceptionHandlerBoundary(ExceptionHandler handler, Instruction oldTarget, Instruction newTarget)
{
if (handler.FilterStart == oldTarget)
handler.FilterStart = newTarget;
if (handler.HandlerEnd == oldTarget)
handler.HandlerEnd = newTarget;
if (handler.HandlerStart == oldTarget)
handler.HandlerStart = newTarget;
if (handler.TryEnd == oldTarget)
handler.TryEnd = newTarget;
if (handler.TryStart == oldTarget)
handler.TryStart = newTarget;
}
}
}
@@ -0,0 +1,204 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Coverlet.Core.Helpers;
using Coverlet.Core.Extensions;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using System;
using System.Xml.Linq;
namespace Coverlet.Core.Instrumentation
{
internal class Instrumenter
{
private string _module;
private string _identifier;
private IEnumerable<string> _excludedFiles;
private InstrumenterResult _result;
public Instrumenter(string module, string identifier, IEnumerable<string> excludedFiles = null)
{
_module = module;
_identifier = identifier;
_excludedFiles = excludedFiles ?? Enumerable.Empty<string>();
}
public bool CanInstrument() => InstrumentationHelper.HasPdb(_module);
public InstrumenterResult Instrument()
{
string hitsFilePath = Path.Combine(
Path.GetTempPath(),
Path.GetFileNameWithoutExtension(_module) + "_" + _identifier
);
_result = new InstrumenterResult
{
Module = Path.GetFileNameWithoutExtension(_module),
HitsFilePath = hitsFilePath,
ModulePath = _module
};
InstrumentModule();
InstrumentationHelper.CopyCoverletDependency(_module);
return _result;
}
private void InstrumentModule()
{
using (var stream = new FileStream(_module, FileMode.Open, FileAccess.ReadWrite))
{
var resolver = new DefaultAssemblyResolver();
resolver.AddSearchDirectory(Path.GetDirectoryName(_module));
var parameters = new ReaderParameters { ReadSymbols = true, AssemblyResolver = resolver };
ModuleDefinition module = ModuleDefinition.ReadModule(stream, parameters);
foreach (var type in module.GetTypes())
{
if (type.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage"))
continue;
foreach (var method in type.Methods)
{
var sourceFile = method.DebugInformation.SequencePoints.Select(s => s.Document.Url).FirstOrDefault();
if (!string.IsNullOrEmpty(sourceFile) && _excludedFiles.Contains(sourceFile)) {
continue;
}
if (!method.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage"))
InstrumentMethod(method);
}
}
module.Write(stream);
}
}
private void InstrumentMethod(MethodDefinition method)
{
if (!method.HasBody)
return;
InstrumentIL(method);
}
private void InstrumentIL(MethodDefinition method)
{
ILProcessor processor = method.Body.GetILProcessor();
var index = 0;
var count = processor.Body.Instructions.Count;
for (int n = 0; n < count; n++)
{
var instruction = processor.Body.Instructions[index];
var sequencePoint = method.DebugInformation.GetSequencePoint(instruction);
if (sequencePoint == null || sequencePoint.StartLine == 16707566)
{
index++;
continue;
}
var target = AddInstrumentationCode(method, processor, instruction, sequencePoint);
foreach (var _instruction in processor.Body.Instructions)
ReplaceInstructionTarget(_instruction, instruction, target);
foreach (ExceptionHandler handler in processor.Body.ExceptionHandlers)
ReplaceExceptionHandlerBoundary(handler, instruction, target);
index += 4;
}
method.Body.SimplifyMacros();
method.Body.OptimizeMacros();
}
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint)
{
var document = _result.Documents.FirstOrDefault(d => d.Path == sequencePoint.Document.Url);
if (document == null)
{
document = new Document { Path = sequencePoint.Document.Url };
_result.Documents.Add(document);
}
for (int i = sequencePoint.StartLine; i <= sequencePoint.EndLine; i++)
{
if (!document.Lines.Exists(l => l.Number == i))
document.Lines.Add(new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName });
}
string flag = IsBranchTarget(processor, instruction) ? "B" : "L";
string marker = $"{document.Path},{sequencePoint.StartLine},{sequencePoint.EndLine},{flag}";
var pathInstr = Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath);
var markInstr = Instruction.Create(OpCodes.Ldstr, marker);
var callInstr = Instruction.Create(OpCodes.Call, processor.Body.Method.Module.ImportReference(typeof(CoverageTracker).GetMethod("MarkExecuted")));
processor.InsertBefore(instruction, callInstr);
processor.InsertBefore(callInstr, markInstr);
processor.InsertBefore(markInstr, pathInstr);
return pathInstr;
}
private bool IsBranchTarget(ILProcessor processor, Instruction instruction)
{
foreach (var _instruction in processor.Body.Instructions)
{
if (_instruction.Operand is Instruction target)
{
if (target == instruction)
return true;
}
if (_instruction.Operand is Instruction[] targets)
return targets.Any(t => t == instruction);
}
return false;
}
private void ReplaceInstructionTarget(Instruction instruction, Instruction oldTarget, Instruction newTarget)
{
if (instruction.Operand is Instruction _instruction)
{
if (_instruction == oldTarget)
{
instruction.Operand = newTarget;
return;
}
}
else if (instruction.Operand is Instruction[] _instructions)
{
for (int i = 0; i < _instructions.Length; i++)
{
if (_instructions[i] == oldTarget)
_instructions[i] = newTarget;
}
}
}
private void ReplaceExceptionHandlerBoundary(ExceptionHandler handler, Instruction oldTarget, Instruction newTarget)
{
if (handler.FilterStart == oldTarget)
handler.FilterStart = newTarget;
if (handler.HandlerEnd == oldTarget)
handler.HandlerEnd = newTarget;
if (handler.HandlerStart == oldTarget)
handler.HandlerStart = newTarget;
if (handler.TryEnd == oldTarget)
handler.TryEnd = newTarget;
if (handler.TryStart == oldTarget)
handler.TryStart = newTarget;
}
}
}