Skip to content
This repository was archived by the owner on Nov 15, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 32 additions & 30 deletions main/OpenCover.Framework/Filter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,35 +209,36 @@ public bool ExcludeByAttribute(IMemberDefinition originalEntity)
return false;

var entity = originalEntity;
while (true)
while (entity != null)
{
if (entity == null)
return false;

bool excludeByAttribute;
if (IsExcludedByAttributeSimple(entity, out excludeByAttribute))
if (IsExcludedByAttributeSimple(entity, out excludeByAttribute))
return excludeByAttribute;

MethodDefinition target;
if (!GetDeclaringMethod(entity, out target))
return false;

if (target.IsGetter || target.IsSetter)
{
entity = entity.DeclaringType.Properties.FirstOrDefault(p => p.GetMethod == target || p.SetMethod == target);
continue;
}
entity = target;
entity = GetDeclaringMethod(entity);
}
return false;
}

/// <summary>
/// Look for the declaring method e.g. if method is some type of lambda, getter/setter etc
/// </summary>
/// <param name="entity"></param>
/// <param name="target"></param>
/// <returns></returns>
private static bool GetDeclaringMethod(IMemberDefinition entity, out MethodDefinition target)
private static IMemberDefinition GetDeclaringMethod(IMemberDefinition entity)
{
MethodDefinition target;
if (!MatchDeclaringMethod(entity, out target))
return null;

if (target.IsGetter || target.IsSetter)
{
return entity.DeclaringType.Properties.FirstOrDefault(p => p.GetMethod == target || p.SetMethod == target);
}
return target;
}

private static bool MatchDeclaringMethod(IMemberDefinition entity, out MethodDefinition target)
{
target = null;
var match = Regex.Match(entity.Name, @"\<(?<name>.+)\>.+");
Expand Down Expand Up @@ -356,27 +357,28 @@ public bool InstrumentProcess(string processName)
if (!ExclusionFilters.Any() && !InclusionFilters.Any())
return true;

if (ExclusionFilters.Any()) {
var matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForProcessName(processName);
if (matchingExclusionFilters.Any
( exclusionFilter =>
// Excluded by all filters
(exclusionFilter.AssemblyName == ".*" && exclusionFilter.ClassName == ".*")
)
)
{
return false;
}
}
if (IsProcessExcluded(processName))
return false;

if (InclusionFilters.Any()) {
if (InclusionFilters.Any())
{
var matchingInclusionFilters = InclusionFilters.GetMatchingFiltersForProcessName(processName);
return matchingInclusionFilters.Any();
}

return true; // not excluded and no inclusion filters
}

private bool IsProcessExcluded(string processName)
{
if (!ExclusionFilters.Any())
return false;

var matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForProcessName(processName);
// Excluded by all filters
return matchingExclusionFilters.Any(exclusionFilter =>(exclusionFilter.AssemblyName == ".*" && exclusionFilter.ClassName == ".*"));
}

readonly IList<string> _excludePaths = new List<string>();

/// <summary>
Expand Down
253 changes: 140 additions & 113 deletions main/OpenCover.Framework/Symbols/CecilSymbolManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using OpenCover.Framework.Model;
using OpenCover.Framework.Strategy;
using log4net;
using Mono.Collections.Generic;
using File = OpenCover.Framework.Model.File;
using SequencePoint = OpenCover.Framework.Model.SequencePoint;

Expand Down Expand Up @@ -445,119 +446,8 @@ private void GetBranchPointsForToken(int token, List<BranchPoint> list)
if (null == instruction.Next)
return;

// Add Default branch (Path=0)

// Follow else/default instruction
var @else = instruction.Next;

var pathOffsetList = GetBranchPath(@else);

// add Path 0
var path0 = new BranchPoint
{
StartLine = branchingInstructionLine,
Document = document,
Offset = branchOffset,
Ordinal = ordinal++,
Path = pathCounter++,
OffsetPoints =
pathOffsetList.Count > 1
? pathOffsetList.GetRange(0, pathOffsetList.Count - 1)
: new List<int>(),
EndOffset = pathOffsetList.Last()
};

// Add Conditional Branch (Path=1)
if (instruction.OpCode.Code != Code.Switch)
{
// Follow instruction at operand
var @then = instruction.Operand as Instruction;
if (@then == null)
return;

pathOffsetList = GetBranchPath(@then);

// Add path 1
var path1 = new BranchPoint
{
StartLine = branchingInstructionLine,
Document = document,
Offset = branchOffset,
Ordinal = ordinal++,
Path = pathCounter,
OffsetPoints =
pathOffsetList.Count > 1
? pathOffsetList.GetRange(0, pathOffsetList.Count - 1)
: new List<int>(),
EndOffset = pathOffsetList.Last()
};

// only add branch if branch does not match a known sequence
// e.g. auto generated field assignment
// or encapsulates at least one sequence point
var offsets = new[]
{
path0.Offset,
path0.EndOffset,
path1.Offset,
path1.EndOffset
};

var ignoreSequences = new[]
{
new []{ Code.Brtrue_S, Code.Ldnull, Code.Ldftn, Code.Newobj, Code.Stsfld, Code.Br_S, Code.Ldsfld}, // CachedAnonymousMethodDelegate field allocation - debug
new []{ Code.Brtrue_S, Code.Ldnull, Code.Ldftn, Code.Newobj, Code.Stsfld, Code.Ldsfld} // CachedAnonymousMethodDelegate field allocation
};

var bs = offsets.Min();
var be = offsets.Max();

var range = instructions.Where(i => (i.Offset >= bs) && (i.Offset <= be)).ToList();

var match = ignoreSequences
.Where(ignoreSequence => range.Count() >= ignoreSequence.Count())
.Select(x => x.Zip(range, (code, i1) => new {Code1 = code, Code2 = i1.OpCode.Code}).All(y => y.Code1 == y.Code2))
.Any();

var count = range
.Count(i => i.SequencePoint != null);

if (!match || count > 0)
{
list.Add(path0);
list.Add(path1);
}
}
else // instruction.OpCode.Code == Code.Switch
{
var branchInstructions = instruction.Operand as Instruction[];
if (branchInstructions == null || branchInstructions.Length == 0)
return;

list.Add(path0);
// Add Conditional Branches (Path>0)
foreach (var @case in branchInstructions)
{
// Follow operand istruction
pathOffsetList = GetBranchPath(@case);

// add paths 1..n
var path1ToN = new BranchPoint
{
StartLine = branchingInstructionLine,
Document = document,
Offset = branchOffset,
Ordinal = ordinal++,
Path = pathCounter++,
OffsetPoints =
pathOffsetList.Count > 1
? pathOffsetList.GetRange(0, pathOffsetList.Count - 1)
: new List<int>(),
EndOffset = pathOffsetList.Last()
};
list.Add(path1ToN);
}
}
if (!BuildPointsForConditionalBranch(list, instruction, branchingInstructionLine, document, branchOffset, pathCounter, instructions, ref ordinal))
return;
}
}
catch (Exception ex)
Expand All @@ -568,6 +458,143 @@ private void GetBranchPointsForToken(int token, List<BranchPoint> list)
}
}

private bool BuildPointsForConditionalBranch(List<BranchPoint> list, Instruction instruction,
int branchingInstructionLine, string document, int branchOffset, int pathCounter,
Collection<Instruction> instructions, ref uint ordinal)
{
// Add Default branch (Path=0)

// Follow else/default instruction
var @else = instruction.Next;

var pathOffsetList = GetBranchPath(@else);

// add Path 0
var path0 = new BranchPoint
{
StartLine = branchingInstructionLine,
Document = document,
Offset = branchOffset,
Ordinal = ordinal++,
Path = pathCounter++,
OffsetPoints =
pathOffsetList.Count > 1
? pathOffsetList.GetRange(0, pathOffsetList.Count - 1)
: new List<int>(),
EndOffset = pathOffsetList.Last()
};

// Add Conditional Branch (Path=1)
if (instruction.OpCode.Code != Code.Switch)
{
// Follow instruction at operand
var @then = instruction.Operand as Instruction;
if (@then == null)
return false;

ordinal = BuildPointsForBranch(list, then, branchingInstructionLine, document, branchOffset,
ordinal, pathCounter, path0, instructions);
}
else // instruction.OpCode.Code == Code.Switch
{
var branchInstructions = instruction.Operand as Instruction[];
if (branchInstructions == null || branchInstructions.Length == 0)
return false;

ordinal = BuildPointsForSwitchCases(list, path0, branchInstructions, branchingInstructionLine,
document, branchOffset, ordinal, ref pathCounter);
}
return true;
}

private uint BuildPointsForBranch(List<BranchPoint> list, Instruction then, int branchingInstructionLine, string document,
int branchOffset, uint ordinal, int pathCounter, BranchPoint path0, Collection<Instruction> instructions)
{
var pathOffsetList1 = GetBranchPath(@then);

// Add path 1
var path1 = new BranchPoint
{
StartLine = branchingInstructionLine,
Document = document,
Offset = branchOffset,
Ordinal = ordinal++,
Path = pathCounter,
OffsetPoints =
pathOffsetList1.Count > 1
? pathOffsetList1.GetRange(0, pathOffsetList1.Count - 1)
: new List<int>(),
EndOffset = pathOffsetList1.Last()
};

// only add branch if branch does not match a known sequence
// e.g. auto generated field assignment
// or encapsulates at least one sequence point
var offsets = new[]
{
path0.Offset,
path0.EndOffset,
path1.Offset,
path1.EndOffset
};

var ignoreSequences = new[]
{
new[]
{Code.Brtrue_S, Code.Ldnull, Code.Ldftn, Code.Newobj, Code.Stsfld, Code.Br_S, Code.Ldsfld},
// CachedAnonymousMethodDelegate field allocation - debug
new[] {Code.Brtrue_S, Code.Ldnull, Code.Ldftn, Code.Newobj, Code.Stsfld, Code.Ldsfld}
// CachedAnonymousMethodDelegate field allocation
};

var bs = offsets.Min();
var be = offsets.Max();

var range = instructions.Where(i => (i.Offset >= bs) && (i.Offset <= be)).ToList();

var match = ignoreSequences
.Where(ignoreSequence => range.Count() >= ignoreSequence.Count())
.Select(
x =>
x.Zip(range, (code, i1) => new {Code1 = code, Code2 = i1.OpCode.Code})
.All(y => y.Code1 == y.Code2))
.Any();

var count = range
.Count(i => i.SequencePoint != null);

if (!match || count > 0)
{
list.Add(path0);
list.Add(path1);
}
return ordinal;
}

private uint BuildPointsForSwitchCases(List<BranchPoint> list, BranchPoint path0, Instruction[] branchInstructions,
int branchingInstructionLine, string document, int branchOffset, uint ordinal, ref int pathCounter)
{
var counter = pathCounter;
list.Add(path0);
// Add Conditional Branches (Path>0)
list.AddRange(branchInstructions.Select(GetBranchPath)
.Select(pathOffsetList1 => new BranchPoint
{
StartLine = branchingInstructionLine,
Document = document,
Offset = branchOffset,
Ordinal = ordinal++,
Path = counter++,
OffsetPoints =
pathOffsetList1.Count > 1
? pathOffsetList1.GetRange(0, pathOffsetList1.Count - 1)
: new List<int>(),
EndOffset = pathOffsetList1.Last()
}));
pathCounter = counter;
return ordinal;
}

private static bool BranchIsInGeneratedFinallyBlock(Instruction branchInstruction, MethodDefinition methodDefinition)
{
if (!methodDefinition.Body.HasExceptionHandlers)
Expand Down