using System; using System.Collections.Generic; using System.Linq; using System.Xml.Serialization; namespace OpenCover.Framework.Model { /// /// An instrumentable point /// public class InstrumentationPoint { private static int _instrumentPoint; private static readonly object LockObject = new object(); private static readonly List InstrumentPoints; static InstrumentationPoint() { _instrumentPoint = 0; InstrumentPoints = new List(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; } /// /// Return the number of visit points /// public static int Count { get { return InstrumentPoints.Count; } } /// /// Get the number of recorded visit points for this identifier /// /// the sequence point identifier - NOTE 0 is not used public static int GetVisitCount(uint spid) { return InstrumentPoints[(int) spid].VisitCount; } /// /// Add a number of recorded visit ppints against this identifier /// /// the sequence point identifier - NOTE 0 is not used /// the id of a tracked method - Note 0 means no method currently tracking /// the number of visit points to add 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(); 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 _tracked; /// /// Initialise /// public InstrumentationPoint() { lock (LockObject) { UniqueSequencePoint = (uint)++_instrumentPoint; InstrumentPoints.Add(this); OrigSequencePoint = UniqueSequencePoint; } } /// /// Store the number of visits /// [XmlAttribute("vc")] public int VisitCount { get; set; } /// /// A unique number /// [XmlAttribute("uspid")] public UInt32 UniqueSequencePoint { get; set; } /// /// An order of the point within the method /// [XmlAttribute("ordinal")] public UInt32 Ordinal { get; set; } /// /// The IL offset of the point /// [XmlAttribute("offset")] public int Offset { get; set; } /// /// Used to hide an instrumentation point /// [XmlIgnore] public bool IsSkipped { get; set; } /// /// The list of tracked methods /// public TrackedMethodRef[] TrackedMethodRefs { get { if (_tracked != null) { return _tracked.ToArray(); } return null; } set { _tracked = null; if (value == null) return; _tracked = new List(value); } } /// /// /// [XmlIgnore] public UInt32 OrigSequencePoint { get; set; } } }