first commit
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
namespace UnityEditor.TestTools.CodeCoverage
|
||||
{
|
||||
internal enum CoverageFormat
|
||||
{
|
||||
OpenCover = 0,
|
||||
DotCover = 1
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8419585fc64d77e4d8e18b7311df59a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 401e5b541d6e30e489f5751eec729fab
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,158 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using Mono.Reflection;
|
||||
|
||||
namespace UnityEditor.TestTools.CodeCoverage.OpenCover
|
||||
{
|
||||
internal static class CyclomaticComplexity
|
||||
{
|
||||
private static List<Instruction> targets = new List<Instruction>();
|
||||
|
||||
public static int CalculateCyclomaticComplexity(this MethodBase method)
|
||||
{
|
||||
if (method == null || method.GetMethodBody() == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool hasSwitch = false;
|
||||
foreach (Instruction ins in method.GetInstructions())
|
||||
{
|
||||
if (ins.OpCode.OperandType == OperandType.InlineSwitch)
|
||||
{
|
||||
hasSwitch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSwitch)
|
||||
{
|
||||
return GetSwitchCyclomaticComplexity(method);
|
||||
}
|
||||
return GetFastCyclomaticComplexity(method);
|
||||
}
|
||||
|
||||
private static int GetFastCyclomaticComplexity(MethodBase method)
|
||||
{
|
||||
int cc = 1;
|
||||
foreach (Instruction ins in method.GetInstructions())
|
||||
{
|
||||
switch (ins.OpCode.FlowControl)
|
||||
{
|
||||
case FlowControl.Branch:
|
||||
// detect ternary pattern
|
||||
Instruction previous = ins.Previous;
|
||||
if (previous != null && previous.OpCode.Name.StartsWith("ld"))
|
||||
{
|
||||
++cc;
|
||||
}
|
||||
break;
|
||||
|
||||
case FlowControl.Cond_Branch:
|
||||
++cc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
private static int GetSwitchCyclomaticComplexity(MethodBase method)
|
||||
{
|
||||
Instruction previous = null;
|
||||
Instruction branch = null;
|
||||
int cc = 1;
|
||||
|
||||
foreach (Instruction ins in method.GetInstructions())
|
||||
{
|
||||
switch (ins.OpCode.FlowControl)
|
||||
{
|
||||
case FlowControl.Branch:
|
||||
if (previous == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// detect ternary pattern
|
||||
previous = ins.Previous;
|
||||
if (previous.OpCode.Name.StartsWith("ld"))
|
||||
{
|
||||
cc++;
|
||||
}
|
||||
|
||||
// or 'default' (xmcs)
|
||||
if (previous.OpCode.FlowControl == FlowControl.Cond_Branch)
|
||||
{
|
||||
branch = (previous.Operand as Instruction);
|
||||
// branch can be null (e.g. switch -> Instruction[])
|
||||
if ((branch != null) && targets.Contains(branch) && !targets.Contains(ins))
|
||||
{
|
||||
targets.Add(ins);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FlowControl.Cond_Branch:
|
||||
// note: a single switch (C#) with sparse values can be broken into several swicth (IL)
|
||||
// that will use the same 'targets' and must be counted only once
|
||||
if (ins.OpCode.OperandType == OperandType.InlineSwitch)
|
||||
{
|
||||
AccumulateSwitchTargets(ins);
|
||||
}
|
||||
else
|
||||
{
|
||||
// some conditional branch can be related to the sparse switch
|
||||
branch = (ins.Operand as Instruction);
|
||||
previous = branch.Previous;
|
||||
if ((previous != null) && previous.Previous.OpCode.OperandType != OperandType.InlineSwitch)
|
||||
{
|
||||
if (!targets.Contains(branch))
|
||||
{
|
||||
cc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// count all unique targets (and default if more than one C# switch is used)
|
||||
cc += targets.Count;
|
||||
targets.Clear();
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
private static void AccumulateSwitchTargets(Instruction ins)
|
||||
{
|
||||
Instruction[] cases = (Instruction[])ins.Operand;
|
||||
foreach (Instruction target in cases)
|
||||
{
|
||||
// ignore targets that are the next instructions (xmcs)
|
||||
if (target != ins.Next && !targets.Contains(target))
|
||||
targets.Add(target);
|
||||
}
|
||||
// add 'default' branch (if one exists)
|
||||
Instruction next = ins.Next;
|
||||
if (next.OpCode.FlowControl == FlowControl.Branch)
|
||||
{
|
||||
Instruction unc = FindFirstUnconditionalBranchTarget(cases[0]);
|
||||
if (unc != next.Operand && !targets.Contains(next.Operand as Instruction))
|
||||
targets.Add(next.Operand as Instruction);
|
||||
}
|
||||
}
|
||||
|
||||
private static Instruction FindFirstUnconditionalBranchTarget(Instruction ins)
|
||||
{
|
||||
while (ins != null)
|
||||
{
|
||||
if (FlowControl.Branch == ins.OpCode.FlowControl)
|
||||
return ((Instruction)ins.Operand);
|
||||
|
||||
ins = ins.Next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74449815e747b4b1ba000bf66f12e01a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c2ede2081f2f4c45a6f7f4c92e3a735
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// OpenCover - S Wilde
|
||||
//
|
||||
// This source code is released under the MIT License; see the accompanying license file.
|
||||
//
|
||||
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// a branch point
|
||||
/// </summary>
|
||||
public class BranchPoint : InstrumentationPoint, IDocumentReference
|
||||
{
|
||||
/// <summary>
|
||||
/// Line of the branching instruction
|
||||
/// </summary>
|
||||
[XmlAttribute("sl")]
|
||||
public int StartLine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A path that can be taken
|
||||
/// </summary>
|
||||
[XmlAttribute("path")]
|
||||
public int Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of OffsetPoints between Offset and EndOffset (exclusive)
|
||||
/// </summary>
|
||||
[XmlAttribute("offsetchain")]
|
||||
public System.Collections.Generic.List<int> OffsetPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should offset points be serialized
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool ShouldSerializeOffsetPoints()
|
||||
{
|
||||
return OffsetPoints.Maybe(_ => _.Any());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Last Offset == EndOffset.
|
||||
/// Can be same as Offset
|
||||
/// </summary>
|
||||
[XmlAttribute("offsetend")]
|
||||
public int EndOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The file associated with the supplied startline
|
||||
/// </summary>
|
||||
[XmlAttribute("fileid")]
|
||||
public uint FileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The url to the document if an entry was not mapped to an id
|
||||
/// </summary>
|
||||
[XmlAttribute("url")]
|
||||
public string Document { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88cac9839726d46718b126833c76c5e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// OpenCover - S Wilde
|
||||
//
|
||||
// This source code is released under the MIT License; see the accompanying license file.
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity that contains methods
|
||||
/// </summary>
|
||||
public class Class : SummarySkippedEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// instantiate
|
||||
/// </summary>
|
||||
public Class()
|
||||
{
|
||||
Methods = new Method[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The full name of the class
|
||||
/// </summary>
|
||||
public string FullName { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
internal File[] Files { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of methods that make up the class
|
||||
/// </summary>
|
||||
public Method[] Methods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If a class was skipped by instrumentation, supply the reason why
|
||||
/// </summary>
|
||||
/// <param name="reason"></param>
|
||||
public override void MarkAsSkipped(SkippedMethod reason)
|
||||
{
|
||||
SkippedDueTo = reason;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0d40fe321f9746dcbccb27824986511
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// OpenCover - S Wilde
|
||||
//
|
||||
// This source code is released under the MIT License; see the accompanying license file.
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// A coverage session
|
||||
/// </summary>
|
||||
public class CoverageSession
|
||||
{
|
||||
private string _version;
|
||||
|
||||
/// <summary>
|
||||
/// initialise a coverage session
|
||||
/// </summary>
|
||||
public CoverageSession()
|
||||
{
|
||||
Modules = new Module[0];
|
||||
Summary = new Summary();
|
||||
_version = GetType().Assembly.GetName().Version.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// A unique session identifier
|
||||
/// </summary>
|
||||
public string SessionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A Summary of results for the session
|
||||
/// </summary>
|
||||
public Summary Summary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of modules that have been profiled under the session
|
||||
/// </summary>
|
||||
public Module[] Modules { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current version
|
||||
/// </summary>
|
||||
[XmlAttribute("Version")]
|
||||
public string Version {
|
||||
get { return _version; }
|
||||
// ReSharper disable once ValueParameterNotUsed
|
||||
set { /* intentionally left blank */} }
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 561dcfbc5a4094415b3d8348f1a6b738
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// OpenCover - S Wilde
|
||||
//
|
||||
// This source code is released under the MIT License; see the accompanying license file.
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// A file reference within the coverage session and is used to point to an existing File entity
|
||||
/// </summary>
|
||||
public class FileRef
|
||||
{
|
||||
/// <summary>
|
||||
/// The uniqueid of a file in a coverage session
|
||||
/// </summary>
|
||||
[XmlAttribute("uid")]
|
||||
public UInt32 UniqueId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// File details of a source file
|
||||
/// </summary>
|
||||
public class File : FileRef
|
||||
{
|
||||
private static int _uId;
|
||||
|
||||
static readonly List<File> Files = new List<File>();
|
||||
|
||||
internal static void ResetAfterLoading()
|
||||
{
|
||||
_uId = (int)Files.Max(x => x.UniqueId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A standard constructor
|
||||
/// </summary>
|
||||
public File()
|
||||
{
|
||||
UniqueId = (UInt32)Interlocked.Increment(ref _uId);
|
||||
Files.Add(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The path to file
|
||||
/// </summary>
|
||||
[XmlAttribute("fullPath")]
|
||||
public string FullPath { get; set; }
|
||||
}
|
||||
|
||||
internal class FileEqualityComparer : IEqualityComparer<File>
|
||||
{
|
||||
public bool Equals(File x, File y)
|
||||
{
|
||||
return x.FullPath == y.FullPath;
|
||||
}
|
||||
|
||||
public int GetHashCode(File obj)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ea0122a5084b4beca6bbb008fea821e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
|
||||
namespace OpenCover.Framework
|
||||
{
|
||||
internal static class HelperExtensions
|
||||
{
|
||||
public static TRet Maybe<T, TRet>(this T value, Func<T, TRet> action, TRet defValue = default(TRet))
|
||||
where T : class
|
||||
{
|
||||
return (value != null) ? action(value) : defValue;
|
||||
}
|
||||
|
||||
public static T Do<T>(this T value, Action<T> action)
|
||||
where T : class
|
||||
{
|
||||
if (value != null)
|
||||
action(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public static T Try<T>(this T value, Action<T> action)
|
||||
where T : class
|
||||
{
|
||||
try
|
||||
{
|
||||
if (value != null)
|
||||
action(value);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignore error
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a74e938125304007a53cf9733cd1208
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// OpenCover - S Wilde
|
||||
//
|
||||
// This source code is released under the MIT License; see the accompanying license file.
|
||||
//
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// A point may have a document reference
|
||||
/// </summary>
|
||||
public interface IDocumentReference
|
||||
{
|
||||
/// <summary>
|
||||
/// The document url
|
||||
/// </summary>
|
||||
string Document { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The document id after lookup
|
||||
/// </summary>
|
||||
uint FileId { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebffa2e2071ad4f79a3641b47e74b25e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// An instrumentable point
|
||||
/// </summary>
|
||||
public class InstrumentationPoint
|
||||
{
|
||||
private static int _instrumentPoint;
|
||||
private static readonly object LockObject = new object();
|
||||
private static readonly List<InstrumentationPoint> InstrumentPoints;
|
||||
|
||||
static InstrumentationPoint()
|
||||
{
|
||||
_instrumentPoint = 0;
|
||||
InstrumentPoints = new List<InstrumentationPoint>(8192) {null};
|
||||
}
|
||||
|
||||
internal static void Clear()
|
||||
{
|
||||
InstrumentPoints.Clear();
|
||||
InstrumentPoints.Add(null);
|
||||
_instrumentPoint = 0;
|
||||
}
|
||||
|
||||
internal static void ResetAfterLoading()
|
||||
{
|
||||
var points = InstrumentPoints
|
||||
.Where(x => x != null)
|
||||
.GroupBy(x => x.UniqueSequencePoint)
|
||||
.Select(g => g.OrderBy(x => x.OrigSequencePoint).First())
|
||||
.ToList();
|
||||
|
||||
var max = (int)points.Max(x => x.UniqueSequencePoint);
|
||||
|
||||
InstrumentPoints.Clear();
|
||||
InstrumentPoints.Add(null);
|
||||
|
||||
for (var i = 1; i <= max; i++)
|
||||
{
|
||||
var point = new SequencePoint();
|
||||
InstrumentPoints[i] = point;
|
||||
point.UniqueSequencePoint = (uint)i;
|
||||
}
|
||||
|
||||
foreach (var instrumentationPoint in points)
|
||||
{
|
||||
InstrumentPoints[(int)instrumentationPoint.UniqueSequencePoint] = instrumentationPoint;
|
||||
}
|
||||
|
||||
_instrumentPoint = max;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the number of visit points
|
||||
/// </summary>
|
||||
public static int Count {
|
||||
get { return InstrumentPoints.Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of recorded visit points for this identifier
|
||||
/// </summary>
|
||||
/// <param name="spid">the sequence point identifier - NOTE 0 is not used</param>
|
||||
public static int GetVisitCount(uint spid)
|
||||
{
|
||||
return InstrumentPoints[(int) spid].VisitCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a number of recorded visit ppints against this identifier
|
||||
/// </summary>
|
||||
/// <param name="spid">the sequence point identifier - NOTE 0 is not used</param>
|
||||
/// <param name="trackedMethodId">the id of a tracked method - Note 0 means no method currently tracking</param>
|
||||
/// <param name="amount">the number of visit points to add</param>
|
||||
public static bool AddVisitCount(uint spid, uint trackedMethodId, int amount)
|
||||
{
|
||||
if (spid != 0 && spid < InstrumentPoints.Count)
|
||||
{
|
||||
var point = InstrumentPoints[(int) spid];
|
||||
point.VisitCount += amount;
|
||||
if (point.VisitCount < 0)
|
||||
{
|
||||
point.VisitCount = int.MaxValue;
|
||||
}
|
||||
if (trackedMethodId != 0)
|
||||
{
|
||||
AddOrUpdateTrackingPoint(trackedMethodId, amount, point);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void AddOrUpdateTrackingPoint(uint trackedMethodId, int amount, InstrumentationPoint point)
|
||||
{
|
||||
point._tracked = point._tracked ?? new List<TrackedMethodRef>();
|
||||
var tracked = point._tracked.Find(x => x.UniqueId == trackedMethodId);
|
||||
if (tracked == null)
|
||||
{
|
||||
tracked = new TrackedMethodRef {UniqueId = trackedMethodId, VisitCount = amount};
|
||||
point._tracked.Add(tracked);
|
||||
}
|
||||
else
|
||||
{
|
||||
tracked.VisitCount += amount;
|
||||
if (tracked.VisitCount < 0)
|
||||
tracked.VisitCount = int.MaxValue;
|
||||
}
|
||||
}
|
||||
|
||||
private List<TrackedMethodRef> _tracked;
|
||||
|
||||
/// <summary>
|
||||
/// Initialise
|
||||
/// </summary>
|
||||
public InstrumentationPoint()
|
||||
{
|
||||
lock (LockObject)
|
||||
{
|
||||
UniqueSequencePoint = (uint)++_instrumentPoint;
|
||||
InstrumentPoints.Add(this);
|
||||
OrigSequencePoint = UniqueSequencePoint;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Store the number of visits
|
||||
/// </summary>
|
||||
[XmlAttribute("vc")]
|
||||
public int VisitCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A unique number
|
||||
/// </summary>
|
||||
[XmlAttribute("uspid")]
|
||||
public UInt32 UniqueSequencePoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An order of the point within the method
|
||||
/// </summary>
|
||||
[XmlAttribute("ordinal")]
|
||||
public UInt32 Ordinal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IL offset of the point
|
||||
/// </summary>
|
||||
[XmlAttribute("offset")]
|
||||
public int Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to hide an instrumentation point
|
||||
/// </summary>
|
||||
[XmlIgnore]
|
||||
public bool IsSkipped { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of tracked methods
|
||||
/// </summary>
|
||||
public TrackedMethodRef[] TrackedMethodRefs
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_tracked != null)
|
||||
{
|
||||
return _tracked.ToArray();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
_tracked = null;
|
||||
if (value == null)
|
||||
return;
|
||||
_tracked = new List<TrackedMethodRef>(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[XmlIgnore]
|
||||
public UInt32 OrigSequencePoint { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86783b018856d4f82ab6105c443f2ffa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,195 @@
|
||||
//
|
||||
// OpenCover - S Wilde
|
||||
//
|
||||
// This source code is released under the MIT License; see the accompanying license file.
|
||||
//
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// An method entity that can be instrumented
|
||||
/// </summary>
|
||||
public class Method : SummarySkippedEntity
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The MetadataToken used to identify this entity within the assembly
|
||||
/// </summary>
|
||||
public int MetadataToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The full name of the method (method-definition), includes return-type namespace-class::call-name(argument-types)
|
||||
/// </summary>
|
||||
[XmlElement("Name")]
|
||||
public string FullName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A reference to a file in the file collection (used to help visualisation)
|
||||
/// </summary>
|
||||
public FileRef FileRef { get; set; }
|
||||
|
||||
internal UInt32 FileRefUniqueId {
|
||||
get { return FileRef == null? 0 : FileRef.UniqueId; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of sequence points that have been produced for this method
|
||||
/// </summary>
|
||||
public SequencePoint[] SequencePoints {
|
||||
get {
|
||||
return _sequencePoints;
|
||||
}
|
||||
set {
|
||||
_sequencePoints = value ?? new SequencePoint[0];
|
||||
}
|
||||
}
|
||||
private SequencePoint[] _sequencePoints = new SequencePoint[0];
|
||||
|
||||
/// <summary>
|
||||
/// A list of branch points that have been identified for this method
|
||||
/// </summary>
|
||||
public BranchPoint[] BranchPoints {
|
||||
get {
|
||||
return _branchPoints;
|
||||
}
|
||||
set {
|
||||
_branchPoints = value ?? new BranchPoint[0];
|
||||
}
|
||||
}
|
||||
private BranchPoint[] _branchPoints = new BranchPoint[0];
|
||||
|
||||
/// <summary>
|
||||
/// A method point to identify the entry of a method
|
||||
/// </summary>
|
||||
public InstrumentationPoint MethodPoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Has the method been visited
|
||||
/// </summary>
|
||||
[XmlAttribute("visited")]
|
||||
public bool Visited { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the cyclomatic complexity of this method.
|
||||
/// </summary>
|
||||
/// <remarks>Calculated using the Gendarme rules library</remarks>
|
||||
[XmlAttribute("cyclomaticComplexity")]
|
||||
public int CyclomaticComplexity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the NPath complexity of this method.
|
||||
/// </summary>
|
||||
/// <remarks>Product of path branches (ie:path0=2;path1=3;path2=2 =>2*3*2==12</remarks>
|
||||
[XmlAttribute("nPathComplexity")]
|
||||
public int NPathComplexity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the sequence coverage of this method
|
||||
/// </summary>
|
||||
/// <remarks>Rounded for ease</remarks>
|
||||
[XmlAttribute("sequenceCoverage")]
|
||||
public decimal SequenceCoverage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the branch coverage of this method
|
||||
/// </summary>
|
||||
/// <remarks>Rounded for ease</remarks>
|
||||
[XmlAttribute("branchCoverage")]
|
||||
public decimal BranchCoverage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the crap score of this method
|
||||
/// based on the following calculation
|
||||
/// CRAP1(m) = comp(m)^2 * (1 – cov(m)/100)^3 + comp(m)
|
||||
/// </summary>
|
||||
/// <remarks>Rounded for ease</remarks>
|
||||
[XmlAttribute("crapScore")]
|
||||
public decimal CrapScore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this method a constructor
|
||||
/// </summary>
|
||||
[XmlAttribute("isConstructor")]
|
||||
public bool IsConstructor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this method static
|
||||
/// </summary>
|
||||
[XmlAttribute("isStatic")]
|
||||
public bool IsStatic { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this method a property getter
|
||||
/// </summary>
|
||||
[XmlAttribute("isGetter")]
|
||||
public bool IsGetter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this method a property setter
|
||||
/// </summary>
|
||||
[XmlAttribute("isSetter")]
|
||||
public bool IsSetter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Mark an entity as skipped
|
||||
/// </summary>
|
||||
/// <param name="reason">Provide a reason</param>
|
||||
public override void MarkAsSkipped(SkippedMethod reason)
|
||||
{
|
||||
SkippedDueTo = reason;
|
||||
if (MethodPoint != null)
|
||||
MethodPoint.IsSkipped = true;
|
||||
MethodPoint = null;
|
||||
SequencePoints = null;
|
||||
BranchPoints = null;
|
||||
}
|
||||
|
||||
#region IsGenerated & CallName
|
||||
|
||||
/// <summary>
|
||||
/// True if this.FullName matches generated-method-regex-pattern
|
||||
/// </summary>
|
||||
internal bool IsGenerated {
|
||||
get {
|
||||
if (_resolvedIsGenerated == null) {
|
||||
_resolvedIsGenerated = !(string.IsNullOrEmpty(FullName) || FullName.Trim().Length == 0)
|
||||
&& FullName.Contains("__") // quick test before using regex heavy weapon
|
||||
&& IsGeneratedMethodRegex.IsMatch(FullName);
|
||||
}
|
||||
return _resolvedIsGenerated == true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method "::CallName(". (Name excluding return type, namespace and arguments)
|
||||
/// </summary>
|
||||
internal string CallName {
|
||||
get {
|
||||
if (_resolvedCallName != null)
|
||||
return _resolvedCallName;
|
||||
_resolvedCallName = string.Empty; // init resolve value
|
||||
if (!(string.IsNullOrEmpty(FullName) || FullName.Trim().Length == 0)) {
|
||||
var startIndex = FullName.IndexOf("::", StringComparison.Ordinal);
|
||||
startIndex += 2;
|
||||
var finalIndex = FullName.IndexOf('(', startIndex);
|
||||
if (startIndex > 1 && finalIndex > startIndex) {
|
||||
_resolvedCallName = FullName // resolve cache
|
||||
.Substring(startIndex, finalIndex - startIndex);
|
||||
}
|
||||
}
|
||||
return _resolvedCallName;
|
||||
}
|
||||
}
|
||||
|
||||
private bool? _resolvedIsGenerated;
|
||||
private string _resolvedCallName;
|
||||
private const RegexOptions RegexOptions = System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.ExplicitCapture;
|
||||
private static readonly Regex IsGeneratedMethodRegex = new Regex(@"(<[^\s:>]+>\w__\w)", RegexOptions);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f1f74c5e9b1146168b87690081420c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "Unity.TestTools.CodeCoverage.Editor.OpenCover.Model",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": []
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19c3df1967929405fba735480b3da9a7
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// OpenCover - S Wilde
|
||||
//
|
||||
// This source code is released under the MIT License; see the accompanying license file.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// The details of a module
|
||||
/// </summary>
|
||||
public class Module : SummarySkippedEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// simple constructor
|
||||
/// </summary>
|
||||
public Module()
|
||||
{
|
||||
Aliases = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The full path name to the module
|
||||
/// </summary>
|
||||
public string ModulePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// GetlastWriteTimeUtc
|
||||
/// </summary>
|
||||
public DateTime ModuleTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of aliases
|
||||
/// </summary>
|
||||
[XmlIgnore]
|
||||
public IList<string> Aliases { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the module
|
||||
/// </summary>
|
||||
public string ModuleName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The files that make up the module
|
||||
/// </summary>
|
||||
public File[] Files { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The classes that make up the module
|
||||
/// </summary>
|
||||
public Class[] Classes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Methods that are being tracked i.e. test methods
|
||||
/// </summary>
|
||||
public TrackedMethod[] TrackedMethods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A hash of the file used to group them together (especially when running against mstest)
|
||||
/// </summary>
|
||||
[XmlAttribute("hash")]
|
||||
public string ModuleHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Mark an entity as skipped
|
||||
/// </summary>
|
||||
/// <param name="reason">Provide a reason</param>
|
||||
public override void MarkAsSkipped(SkippedMethod reason)
|
||||
{
|
||||
SkippedDueTo = reason;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7c00a2c9a9fd476c947d35ae18e21fd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// OpenCover - S Wilde
|
||||
//
|
||||
// This source code is released under the MIT License; see the accompanying license file.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// a sequence point
|
||||
/// </summary>
|
||||
public class SequencePoint : InstrumentationPoint, IDocumentReference
|
||||
{
|
||||
/// <summary>
|
||||
/// The start line of the sequence point
|
||||
/// </summary>
|
||||
[XmlAttribute("sl")]
|
||||
public int StartLine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start column of the sequence point
|
||||
/// </summary>
|
||||
[XmlAttribute("sc")]
|
||||
public int StartColumn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end line of the sequence point
|
||||
/// </summary>
|
||||
[XmlAttribute("el")]
|
||||
public int EndLine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end column of the sequence point
|
||||
/// </summary>
|
||||
[XmlAttribute("ec")]
|
||||
public int EndColumn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Count of merged branches
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// The number of branch exits
|
||||
/// </summary>
|
||||
[XmlAttribute("bec")]
|
||||
public int BranchExitsCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Visit count of merged branches
|
||||
/// </summary>
|
||||
[XmlAttribute("bev")]
|
||||
public int BranchExitsVisit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The file associated with the supplied startline
|
||||
/// </summary>
|
||||
[XmlAttribute("fileid")]
|
||||
public uint FileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The url to the document if an entry was not mapped to an id
|
||||
/// </summary>
|
||||
[XmlAttribute("url")]
|
||||
public string Document { get; set; }
|
||||
|
||||
internal List<BranchPoint> BranchPoints {
|
||||
get{
|
||||
return _branchPoints;
|
||||
}
|
||||
set{
|
||||
_branchPoints = value ?? new List<BranchPoint>();
|
||||
}
|
||||
}
|
||||
private List<BranchPoint> _branchPoints = new List<BranchPoint>();
|
||||
|
||||
/// <summary>
|
||||
/// Property
|
||||
/// </summary>
|
||||
public bool IsSingleCharSequencePoint {
|
||||
get {
|
||||
return (StartLine == EndLine) && (EndColumn - StartColumn) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SonnarQube wants no more than 3 boolean conditions
|
||||
/// </summary>
|
||||
/// <param name="sp"></param>
|
||||
/// <returns></returns>
|
||||
private bool IsLineEqual (SequencePoint sp) {
|
||||
return StartLine == sp.StartLine && EndLine == sp.EndLine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SonnarQube wants no more than 3 boolean conditions
|
||||
/// </summary>
|
||||
/// <param name="sp"></param>
|
||||
/// <returns></returns>
|
||||
private bool IsColumnEqual (SequencePoint sp) {
|
||||
return StartColumn == sp.StartColumn && EndColumn == sp.EndColumn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is Start/End Line/Column equal
|
||||
/// </summary>
|
||||
/// <param name="sp"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsPositionEqual (SequencePoint sp) {
|
||||
return sp != null && IsLineEqual (sp) && IsColumnEqual (sp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is FileId equal? (If FileId is 0 then file is unknown)
|
||||
/// </summary>
|
||||
/// <param name="sp"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsFileIdEqual (SequencePoint sp) {
|
||||
return sp != null && FileId != 0 && FileId == sp.FileId;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 448b5b9c7773f48be878eb5f56008baf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,33 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// The entity can be skipped from coverage but needs to supply a reason
|
||||
/// </summary>
|
||||
public abstract class SkippedEntity
|
||||
{
|
||||
private SkippedMethod? _skippedDueTo;
|
||||
|
||||
/// <summary>
|
||||
/// If this class has been skipped then this value will describe why
|
||||
/// </summary>
|
||||
[XmlAttribute("skippedDueTo")]
|
||||
public SkippedMethod SkippedDueTo
|
||||
{
|
||||
get { return _skippedDueTo.GetValueOrDefault(); }
|
||||
set { _skippedDueTo = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this class has been skipped then this value will allow the data to be serialized
|
||||
/// </summary>
|
||||
public bool ShouldSerializeSkippedDueTo() { return _skippedDueTo.HasValue; }
|
||||
|
||||
/// <summary>
|
||||
/// Mark an entity as skipped
|
||||
/// </summary>
|
||||
/// <param name="reason">Provide a reason</param>
|
||||
public abstract void MarkAsSkipped(SkippedMethod reason);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2adfa90d9eaaa4702b2457c09db2f5e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,64 @@
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes how a method or class was skipped
|
||||
/// </summary>
|
||||
public enum SkippedMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity was skipped due to a matching exclusion attribute filter
|
||||
/// </summary>
|
||||
Attribute = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Entity was skipped due to a matching exclusion file filter
|
||||
/// </summary>
|
||||
File = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Entity was skipped due to a matching exclusion module/class filter
|
||||
/// </summary>
|
||||
Filter = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Entity was skipped due to a missing PDB
|
||||
/// </summary>
|
||||
MissingPdb = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Entity was skipped by inference (usually related to File filters)
|
||||
/// </summary>
|
||||
Inferred = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Entity (method) was skipped as it is an auto-implemented property.
|
||||
/// </summary>
|
||||
AutoImplementedProperty = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Entity (method) was skipped as it is native code.
|
||||
/// </summary>
|
||||
NativeCode = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Entity (method) was skipped for other reasons.
|
||||
/// </summary>
|
||||
Unknown = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Entity (dll) was skipped due to folder exclusion.
|
||||
/// </summary>
|
||||
FolderExclusion = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Entity (method) was skipped due to being a delegate.
|
||||
/// </summary>
|
||||
Delegate = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Entity (method) was skipped due to being an F# internal implementation
|
||||
/// detail (in either a record or discriminated union type).
|
||||
/// </summary>
|
||||
FSharpInternal = 11,
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e49bf94f7d5348e2a48c3a09f3de201
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// A summary of results
|
||||
/// </summary>
|
||||
public class Summary
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of sequence points
|
||||
/// </summary>
|
||||
[XmlAttribute("numSequencePoints")]
|
||||
public int NumSequencePoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of sequence points visited
|
||||
/// </summary>
|
||||
[XmlAttribute("visitedSequencePoints")]
|
||||
public int VisitedSequencePoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of branch points
|
||||
/// </summary>
|
||||
[XmlAttribute("numBranchPoints")]
|
||||
public int NumBranchPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of branch points visited
|
||||
/// </summary>
|
||||
[XmlAttribute("visitedBranchPoints")]
|
||||
public int VisitedBranchPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the sequence coverage?
|
||||
/// </summary>
|
||||
/// <remarks>Rounded for ease</remarks>
|
||||
[XmlAttribute("sequenceCoverage")]
|
||||
public decimal SequenceCoverage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the branch coverage?
|
||||
/// </summary>
|
||||
/// <remarks>Rounded for ease</remarks>
|
||||
[XmlAttribute("branchCoverage")]
|
||||
public decimal BranchCoverage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the maximum cyclomatic complexity.
|
||||
/// </summary>
|
||||
/// <remarks>Calculated using the Gendarme rules library</remarks>
|
||||
[XmlAttribute("maxCyclomaticComplexity")]
|
||||
public int MaxCyclomaticComplexity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the minimum cyclomatic complexity.
|
||||
/// </summary>
|
||||
/// <remarks>Calculated using the Gendarme rules library</remarks>
|
||||
[XmlAttribute("minCyclomaticComplexity")]
|
||||
public int MinCyclomaticComplexity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the maximum crap score
|
||||
/// </summary>
|
||||
[XmlAttribute("maxCrapScore")]
|
||||
public decimal MaxCrapScore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the minimum crap score.
|
||||
/// </summary>
|
||||
[XmlAttribute("minCrapScore")]
|
||||
public decimal MinCrapScore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the number of visited classes
|
||||
/// </summary>
|
||||
[XmlAttribute("visitedClasses")]
|
||||
public int VisitedClasses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the total number of classes
|
||||
/// </summary>
|
||||
[XmlAttribute("numClasses")]
|
||||
public int NumClasses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the number of visited methods
|
||||
/// </summary>
|
||||
[XmlAttribute("visitedMethods")]
|
||||
public int VisitedMethods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What is the total number of methods
|
||||
/// </summary>
|
||||
[XmlAttribute("numMethods")]
|
||||
public int NumMethods { get; set; }
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f84724c9beb0444b0b1a7166317d7262
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,28 @@
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// A skipped entity that also carries a Summary object which is not
|
||||
/// always serialized
|
||||
/// </summary>
|
||||
public abstract class SummarySkippedEntity : SkippedEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialise
|
||||
/// </summary>
|
||||
protected SummarySkippedEntity()
|
||||
{
|
||||
Summary = new Summary();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A Summary of results for a entity
|
||||
/// </summary>
|
||||
public Summary Summary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Control serialization of the Summary object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool ShouldSerializeSummary() { return !ShouldSerializeSkippedDueTo(); }
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1b80d503cba7422cb21829a6891cde2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace OpenCover.Framework.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// A reference to a tracked method
|
||||
/// </summary>
|
||||
public class TrackedMethodRef
|
||||
{
|
||||
/// <summary>
|
||||
/// unique id assigned
|
||||
/// </summary>
|
||||
[XmlAttribute("uid")]
|
||||
public UInt32 UniqueId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The visit count
|
||||
/// </summary>
|
||||
[XmlAttribute("vc")]
|
||||
public int VisitCount { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A method being tracked
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class TrackedMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// unique id assigned
|
||||
/// </summary>
|
||||
[XmlAttribute("uid")]
|
||||
public UInt32 UniqueId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The MetadataToken used to identify this entity within the assembly
|
||||
/// </summary>
|
||||
[XmlAttribute("token")]
|
||||
public int MetadataToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the method being tracked
|
||||
/// </summary>
|
||||
[XmlAttribute("name")]
|
||||
public string FullName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The reason/plugin why the method is being tracked
|
||||
/// </summary>
|
||||
[XmlAttribute("strategy")]
|
||||
public string Strategy { get; set; }
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7c779bb30ff546c08fce46737f83ec5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6c4c078b09304bfeaae896e2e4ffa9e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,130 @@
|
||||
//
|
||||
// ByteBuffer.cs
|
||||
//
|
||||
// Author:
|
||||
// Jb Evain (jbevain@novell.com)
|
||||
//
|
||||
// (C) 2009 - 2010 Novell, Inc. (http://www.novell.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Mono.Reflection {
|
||||
|
||||
class ByteBuffer {
|
||||
|
||||
internal byte [] buffer;
|
||||
internal int position;
|
||||
|
||||
public ByteBuffer (byte [] buffer)
|
||||
{
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
public byte ReadByte ()
|
||||
{
|
||||
CheckCanRead (1);
|
||||
return buffer [position++];
|
||||
}
|
||||
|
||||
public byte [] ReadBytes (int length)
|
||||
{
|
||||
CheckCanRead (length);
|
||||
var value = new byte [length];
|
||||
Buffer.BlockCopy (buffer, position, value, 0, length);
|
||||
position += length;
|
||||
return value;
|
||||
}
|
||||
|
||||
public short ReadInt16 ()
|
||||
{
|
||||
CheckCanRead (2);
|
||||
short value = (short) (buffer [position]
|
||||
| (buffer [position + 1] << 8));
|
||||
position += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
public int ReadInt32 ()
|
||||
{
|
||||
CheckCanRead (4);
|
||||
int value = buffer [position]
|
||||
| (buffer [position + 1] << 8)
|
||||
| (buffer [position + 2] << 16)
|
||||
| (buffer [position + 3] << 24);
|
||||
position += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
public long ReadInt64 ()
|
||||
{
|
||||
CheckCanRead (8);
|
||||
uint low = (uint) (buffer [position]
|
||||
| (buffer [position + 1] << 8)
|
||||
| (buffer [position + 2] << 16)
|
||||
| (buffer [position + 3] << 24));
|
||||
|
||||
uint high = (uint) (buffer [position + 4]
|
||||
| (buffer [position + 5] << 8)
|
||||
| (buffer [position + 6] << 16)
|
||||
| (buffer [position + 7] << 24));
|
||||
|
||||
long value = (((long) high) << 32) | low;
|
||||
position += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
public float ReadSingle ()
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian) {
|
||||
var bytes = ReadBytes (4);
|
||||
Array.Reverse (bytes);
|
||||
return BitConverter.ToSingle (bytes, 0);
|
||||
}
|
||||
|
||||
CheckCanRead (4);
|
||||
float value = BitConverter.ToSingle (buffer, position);
|
||||
position += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
public double ReadDouble ()
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian) {
|
||||
var bytes = ReadBytes (8);
|
||||
Array.Reverse (bytes);
|
||||
return BitConverter.ToDouble (bytes, 0);
|
||||
}
|
||||
|
||||
CheckCanRead (8);
|
||||
double value = BitConverter.ToDouble (buffer, position);
|
||||
position += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
void CheckCanRead (int count)
|
||||
{
|
||||
if (position + count > buffer.Length)
|
||||
throw new ArgumentOutOfRangeException ();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68735f878b89447b4925a73a9074dfe9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Disassembler.cs
|
||||
//
|
||||
// Author:
|
||||
// Jb Evain (jbevain@novell.com)
|
||||
//
|
||||
// (C) 2009 - 2010 Novell, Inc. (http://www.novell.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Mono.Reflection {
|
||||
|
||||
public static class Disassembler {
|
||||
|
||||
public static IList<Instruction> GetInstructions (this MethodBase self)
|
||||
{
|
||||
if (self == null)
|
||||
throw new ArgumentNullException ("self");
|
||||
|
||||
return MethodBodyReader.GetInstructions (self).AsReadOnly ();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2c36198237a34870a85b171e9097887
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,156 @@
|
||||
//
|
||||
// Instruction.cs
|
||||
//
|
||||
// Author:
|
||||
// Jb Evain (jbevain@novell.com)
|
||||
//
|
||||
// (C) 2009 - 2010 Novell, Inc. (http://www.novell.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text;
|
||||
|
||||
namespace Mono.Reflection {
|
||||
|
||||
public sealed class Instruction {
|
||||
|
||||
int offset;
|
||||
OpCode opcode;
|
||||
object operand;
|
||||
|
||||
Instruction previous;
|
||||
Instruction next;
|
||||
|
||||
public int Offset {
|
||||
get { return offset; }
|
||||
}
|
||||
|
||||
public OpCode OpCode {
|
||||
get { return opcode; }
|
||||
}
|
||||
|
||||
public object Operand {
|
||||
get { return operand; }
|
||||
internal set { operand = value; }
|
||||
}
|
||||
|
||||
public Instruction Previous {
|
||||
get { return previous; }
|
||||
internal set { previous = value; }
|
||||
}
|
||||
|
||||
public Instruction Next {
|
||||
get { return next; }
|
||||
internal set { next = value; }
|
||||
}
|
||||
|
||||
public int Size {
|
||||
get {
|
||||
int size = opcode.Size;
|
||||
|
||||
switch (opcode.OperandType) {
|
||||
case OperandType.InlineSwitch:
|
||||
size += (1 + ((Instruction []) operand).Length) * 4;
|
||||
break;
|
||||
case OperandType.InlineI8:
|
||||
case OperandType.InlineR:
|
||||
size += 8;
|
||||
break;
|
||||
case OperandType.InlineBrTarget:
|
||||
case OperandType.InlineField:
|
||||
case OperandType.InlineI:
|
||||
case OperandType.InlineMethod:
|
||||
case OperandType.InlineString:
|
||||
case OperandType.InlineTok:
|
||||
case OperandType.InlineType:
|
||||
case OperandType.ShortInlineR:
|
||||
size += 4;
|
||||
break;
|
||||
case OperandType.InlineVar:
|
||||
size += 2;
|
||||
break;
|
||||
case OperandType.ShortInlineBrTarget:
|
||||
case OperandType.ShortInlineI:
|
||||
case OperandType.ShortInlineVar:
|
||||
size += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
internal Instruction (int offset, OpCode opcode)
|
||||
{
|
||||
this.offset = offset;
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
var instruction = new StringBuilder ();
|
||||
|
||||
AppendLabel (instruction, this);
|
||||
instruction.Append (':');
|
||||
instruction.Append (' ');
|
||||
instruction.Append (opcode.Name);
|
||||
|
||||
if (operand == null)
|
||||
return instruction.ToString ();
|
||||
|
||||
instruction.Append (' ');
|
||||
|
||||
switch (opcode.OperandType) {
|
||||
case OperandType.ShortInlineBrTarget:
|
||||
case OperandType.InlineBrTarget:
|
||||
AppendLabel (instruction, (Instruction) operand);
|
||||
break;
|
||||
case OperandType.InlineSwitch:
|
||||
var labels = (Instruction []) operand;
|
||||
for (int i = 0; i < labels.Length; i++) {
|
||||
if (i > 0)
|
||||
instruction.Append (',');
|
||||
|
||||
AppendLabel (instruction, labels [i]);
|
||||
}
|
||||
break;
|
||||
case OperandType.InlineString:
|
||||
instruction.Append ('\"');
|
||||
instruction.Append (operand);
|
||||
instruction.Append ('\"');
|
||||
break;
|
||||
default:
|
||||
instruction.Append (operand);
|
||||
break;
|
||||
}
|
||||
|
||||
return instruction.ToString ();
|
||||
}
|
||||
|
||||
static void AppendLabel (StringBuilder builder, Instruction instruction)
|
||||
{
|
||||
builder.Append ("IL_");
|
||||
builder.Append (instruction.offset.ToString ("x4"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c54348b43e9e464fa20499d8315beed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,306 @@
|
||||
//
|
||||
// MethodBodyReader.cs
|
||||
//
|
||||
// Author:
|
||||
// Jb Evain (jbevain@novell.com)
|
||||
//
|
||||
// (C) 2009 - 2010 Novell, Inc. (http://www.novell.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mono.Reflection {
|
||||
|
||||
class MethodBodyReader {
|
||||
|
||||
static readonly OpCode [] one_byte_opcodes;
|
||||
static readonly OpCode [] two_bytes_opcodes;
|
||||
|
||||
static MethodBodyReader ()
|
||||
{
|
||||
one_byte_opcodes = new OpCode [0xe1];
|
||||
two_bytes_opcodes = new OpCode [0x1f];
|
||||
|
||||
var fields = typeof (OpCodes).GetFields (
|
||||
BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
foreach (var field in fields) {
|
||||
var opcode = (OpCode) field.GetValue (null);
|
||||
if (opcode.OpCodeType == OpCodeType.Nternal)
|
||||
continue;
|
||||
|
||||
if (opcode.Size == 1)
|
||||
one_byte_opcodes [opcode.Value] = opcode;
|
||||
else
|
||||
two_bytes_opcodes [opcode.Value & 0xff] = opcode;
|
||||
}
|
||||
}
|
||||
|
||||
readonly MethodBase method;
|
||||
readonly MethodBody body;
|
||||
readonly Module module;
|
||||
readonly Type [] type_arguments;
|
||||
readonly Type [] method_arguments;
|
||||
readonly ByteBuffer il;
|
||||
readonly ParameterInfo this_parameter;
|
||||
readonly ParameterInfo [] parameters;
|
||||
readonly IList<LocalVariableInfo> locals;
|
||||
readonly List<Instruction> instructions;
|
||||
|
||||
MethodBodyReader (MethodBase method)
|
||||
{
|
||||
this.method = method;
|
||||
|
||||
this.body = method.GetMethodBody ();
|
||||
if (this.body == null)
|
||||
throw new ArgumentException ("Method has no body");
|
||||
|
||||
var bytes = body.GetILAsByteArray ();
|
||||
if (bytes == null)
|
||||
throw new ArgumentException ("Can not get the body of the method");
|
||||
|
||||
if (!(method is ConstructorInfo))
|
||||
method_arguments = method.GetGenericArguments ();
|
||||
|
||||
if (method.DeclaringType != null)
|
||||
type_arguments = method.DeclaringType.GetGenericArguments ();
|
||||
|
||||
if (!method.IsStatic)
|
||||
this.this_parameter = new ThisParameter (method);
|
||||
this.parameters = method.GetParameters ();
|
||||
this.locals = body.LocalVariables;
|
||||
this.module = method.Module;
|
||||
this.il = new ByteBuffer (bytes);
|
||||
this.instructions = new List<Instruction> ((bytes.Length + 1) / 2);
|
||||
}
|
||||
|
||||
void ReadInstructions ()
|
||||
{
|
||||
Instruction previous = null;
|
||||
|
||||
while (il.position < il.buffer.Length) {
|
||||
var instruction = new Instruction (il.position, ReadOpCode ());
|
||||
|
||||
ReadOperand (instruction);
|
||||
|
||||
if (previous != null) {
|
||||
instruction.Previous = previous;
|
||||
previous.Next = instruction;
|
||||
}
|
||||
|
||||
instructions.Add (instruction);
|
||||
previous = instruction;
|
||||
}
|
||||
|
||||
ResolveBranches ();
|
||||
}
|
||||
|
||||
void ReadOperand (Instruction instruction)
|
||||
{
|
||||
switch (instruction.OpCode.OperandType) {
|
||||
case OperandType.InlineNone:
|
||||
break;
|
||||
case OperandType.InlineSwitch:
|
||||
int length = il.ReadInt32 ();
|
||||
int base_offset = il.position + (4 * length);
|
||||
int [] branches = new int [length];
|
||||
for (int i = 0; i < length; i++)
|
||||
branches [i] = il.ReadInt32 () + base_offset;
|
||||
|
||||
instruction.Operand = branches;
|
||||
break;
|
||||
case OperandType.ShortInlineBrTarget:
|
||||
instruction.Operand = (((sbyte) il.ReadByte ()) + il.position);
|
||||
break;
|
||||
case OperandType.InlineBrTarget:
|
||||
instruction.Operand = il.ReadInt32 () + il.position;
|
||||
break;
|
||||
case OperandType.ShortInlineI:
|
||||
if (instruction.OpCode == OpCodes.Ldc_I4_S)
|
||||
instruction.Operand = (sbyte) il.ReadByte ();
|
||||
else
|
||||
instruction.Operand = il.ReadByte ();
|
||||
break;
|
||||
case OperandType.InlineI:
|
||||
instruction.Operand = il.ReadInt32 ();
|
||||
break;
|
||||
case OperandType.ShortInlineR:
|
||||
instruction.Operand = il.ReadSingle ();
|
||||
break;
|
||||
case OperandType.InlineR:
|
||||
instruction.Operand = il.ReadDouble ();
|
||||
break;
|
||||
case OperandType.InlineI8:
|
||||
instruction.Operand = il.ReadInt64 ();
|
||||
break;
|
||||
case OperandType.InlineSig:
|
||||
instruction.Operand = module.ResolveSignature (il.ReadInt32 ());
|
||||
break;
|
||||
case OperandType.InlineString:
|
||||
instruction.Operand = module.ResolveString (il.ReadInt32 ());
|
||||
break;
|
||||
case OperandType.InlineTok:
|
||||
{
|
||||
int metaDataToken = il.ReadInt32 ();
|
||||
try
|
||||
{
|
||||
instruction.Operand = module.ResolveMember (metaDataToken, type_arguments, method_arguments);
|
||||
}
|
||||
catch(BadImageFormatException)
|
||||
{
|
||||
instruction.Operand = module.ResolveMember (metaDataToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OperandType.InlineType:
|
||||
instruction.Operand = module.ResolveType (il.ReadInt32 (), type_arguments, method_arguments);
|
||||
break;
|
||||
case OperandType.InlineMethod:
|
||||
{
|
||||
int metaDataToken = il.ReadInt32 ();
|
||||
try
|
||||
{
|
||||
instruction.Operand = module.ResolveMethod (metaDataToken, type_arguments, method_arguments);
|
||||
}
|
||||
catch(TypeLoadException)
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OperandType.InlineField:
|
||||
instruction.Operand = module.ResolveField (il.ReadInt32 (), type_arguments, method_arguments);
|
||||
break;
|
||||
case OperandType.ShortInlineVar:
|
||||
instruction.Operand = GetVariable (instruction, il.ReadByte ());
|
||||
break;
|
||||
case OperandType.InlineVar:
|
||||
instruction.Operand = GetVariable (instruction, il.ReadInt16 ());
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
}
|
||||
|
||||
void ResolveBranches ()
|
||||
{
|
||||
foreach (var instruction in instructions) {
|
||||
switch (instruction.OpCode.OperandType) {
|
||||
case OperandType.ShortInlineBrTarget:
|
||||
case OperandType.InlineBrTarget:
|
||||
instruction.Operand = GetInstruction (instructions, (int) instruction.Operand);
|
||||
break;
|
||||
case OperandType.InlineSwitch:
|
||||
var offsets = (int []) instruction.Operand;
|
||||
var branches = new Instruction [offsets.Length];
|
||||
for (int j = 0; j < offsets.Length; j++)
|
||||
branches [j] = GetInstruction (instructions, offsets [j]);
|
||||
|
||||
instruction.Operand = branches;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Instruction GetInstruction (List<Instruction> instructions, int offset)
|
||||
{
|
||||
var size = instructions.Count;
|
||||
if (offset < 0 || offset > instructions [size - 1].Offset)
|
||||
return null;
|
||||
|
||||
int min = 0;
|
||||
int max = size - 1;
|
||||
while (min <= max) {
|
||||
int mid = min + ((max - min) / 2);
|
||||
var instruction = instructions [mid];
|
||||
var instruction_offset = instruction.Offset;
|
||||
|
||||
if (offset == instruction_offset)
|
||||
return instruction;
|
||||
|
||||
if (offset < instruction_offset)
|
||||
max = mid - 1;
|
||||
else
|
||||
min = mid + 1;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
object GetVariable (Instruction instruction, int index)
|
||||
{
|
||||
return TargetsLocalVariable (instruction.OpCode)
|
||||
? (object) GetLocalVariable (index)
|
||||
: (object) GetParameter (index);
|
||||
}
|
||||
|
||||
static bool TargetsLocalVariable (OpCode opcode)
|
||||
{
|
||||
return opcode.Name.Contains ("loc");
|
||||
}
|
||||
|
||||
LocalVariableInfo GetLocalVariable (int index)
|
||||
{
|
||||
return locals [index];
|
||||
}
|
||||
|
||||
ParameterInfo GetParameter (int index)
|
||||
{
|
||||
if (method.IsStatic)
|
||||
return parameters [index];
|
||||
|
||||
if (index == 0)
|
||||
return this_parameter;
|
||||
|
||||
return parameters [index - 1];
|
||||
}
|
||||
|
||||
OpCode ReadOpCode ()
|
||||
{
|
||||
byte op = il.ReadByte ();
|
||||
return op != 0xfe
|
||||
? one_byte_opcodes [op]
|
||||
: two_bytes_opcodes [il.ReadByte ()];
|
||||
}
|
||||
|
||||
public static List<Instruction> GetInstructions (MethodBase method)
|
||||
{
|
||||
var reader = new MethodBodyReader (method);
|
||||
reader.ReadInstructions ();
|
||||
return reader.instructions;
|
||||
}
|
||||
|
||||
class ThisParameter : ParameterInfo
|
||||
{
|
||||
public ThisParameter (MethodBase method)
|
||||
{
|
||||
this.MemberImpl = method;
|
||||
this.ClassImpl = method.DeclaringType;
|
||||
this.NameImpl = "this";
|
||||
this.PositionImpl = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a8056948ac804bf891bd101b3216a55
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "Unity.TestTools.CodeCoverage.Editor.OpenCover.Mono.Reflection",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": []
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eecdf9bdfcb2949619db458f3e24c5e2
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user