first commit

This commit is contained in:
SimonSayeBabu
2025-01-17 13:10:20 +01:00
commit bd1057cec0
16967 changed files with 1048699 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
namespace UnityEditor.TestTools.CodeCoverage
{
internal enum CoverageFormat
{
OpenCover = 0,
DotCover = 1
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8419585fc64d77e4d8e18b7311df59a7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 401e5b541d6e30e489f5751eec729fab
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 74449815e747b4b1ba000bf66f12e01a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9c2ede2081f2f4c45a6f7f4c92e3a735
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 88cac9839726d46718b126833c76c5e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c0d40fe321f9746dcbccb27824986511
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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 */} }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 561dcfbc5a4094415b3d8348f1a6b738
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4ea0122a5084b4beca6bbb008fea821e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a74e938125304007a53cf9733cd1208
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ebffa2e2071ad4f79a3641b47e74b25e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86783b018856d4f82ab6105c443f2ffa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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 =&gt;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
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7f1f74c5e9b1146168b87690081420c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
{
"name": "Unity.TestTools.CodeCoverage.Editor.OpenCover.Model",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 19c3df1967929405fba735480b3da9a7
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7c00a2c9a9fd476c947d35ae18e21fd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 448b5b9c7773f48be878eb5f56008baf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2adfa90d9eaaa4702b2457c09db2f5e2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e49bf94f7d5348e2a48c3a09f3de201
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f84724c9beb0444b0b1a7166317d7262
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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(); }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b1b80d503cba7422cb21829a6891cde2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d7c779bb30ff546c08fce46737f83ec5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b6c4c078b09304bfeaae896e2e4ffa9e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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 ();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 68735f878b89447b4925a73a9074dfe9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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 ();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f2c36198237a34870a85b171e9097887
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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"));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c54348b43e9e464fa20499d8315beed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a8056948ac804bf891bd101b3216a55
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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": []
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: eecdf9bdfcb2949619db458f3e24c5e2
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More