public void Can_GetBranchPoints_Of_MethodByToken() { // arrange var target = new BranchPoint(); BranchPoint[] pts; var module = new Module { FullName = "ModulePath", Classes = new[] { new Class { FullName = "namespace.class", Methods = new[] { new Method { MetadataToken = 1001, BranchPoints = new[] { target } } } } } }; module.Aliases.Add("ModulePath"); Instance.PersistModule(module); // act Instance.GetBranchPointsForFunction("ModulePath", 1001, out pts); // assert Assert.AreEqual(target.UniqueSequencePoint, pts[0].UniqueSequencePoint); }
Vector3 GetPositionAlongPoints(float val, out float w) { // Reduce by tiny amount so we can still sample up! // Also it gives us less of a chance of hitting the points exactly float v = val * .99f * ((float)numPoints - 1); float up = Mathf.Ceil(v); float down = Mathf.Floor(v); float inVal = v - down; Vector3 fPos; if (inVal == 0 || up == down) { fPos = points[(int)down].position; w = points[(int)down].width; } else { BranchPoint p1 = points[(int)down]; BranchPoint p2 = points[(int)up]; fPos = cubicPoint(inVal, p1.position, p1.position + p1.normal / 3, p2.position - p2.normal / 3, p2.position); w = Mathf.Lerp(p1.width, p2.width, inVal); } return(fPos); }
public void BuildModuleModel_Gets_NoBranchPoints_WhenNoSequencePoints() { // arrange var @class = new Class(); var @method = new Method { MetadataToken = 101 }; var brPoint = new BranchPoint(); Container.GetMock <ISymbolManager>() .Setup(x => x.GetInstrumentableTypes()) .Returns(new[] { @class }); Container.GetMock <ISymbolManager>() .Setup(x => x.GetMethodsForType(@class, It.IsAny <File[]>())) .Returns(new[] { @method }); Container.GetMock <ISymbolManager>() .Setup(x => x.GetBranchPointsForToken(101)) .Returns(new[] { brPoint }); Container.GetMock <IFilter>() .Setup(x => x.UseAssembly(It.IsAny <string>())) .Returns(true); // act var module = Instance.BuildModuleModel(true); // assert Assert.IsFalse(module.Classes[0].Methods[0].SequencePoints.Any()); Assert.IsFalse(module.Classes[0].Methods[0].BranchPoints.Any()); }
public void Commit_With_WithBranchPointsOnly() { // arrange var point = new BranchPoint(); Instance.CoverageSession.Modules = new[] { new Module { Classes = new[] { new Class { Methods = new[] { new Method { BranchPoints = new[] { point } } } } } } }; // act InstrumentationPoint.AddVisitCount(point.UniqueSequencePoint, 0, 42); Assert.DoesNotThrow(() => Instance.Commit()); // assert Assert.AreEqual(42, point.VisitCount); Assert.AreEqual(0, Instance.CoverageSession.Modules[0].Classes[0].Methods[0].Summary.NumSequencePoints); Assert.AreEqual(0, Instance.CoverageSession.Modules[0].Classes[0].Methods[0].Summary.VisitedSequencePoints); Assert.AreEqual(1, Instance.CoverageSession.Modules[0].Classes[0].Methods[0].Summary.NumBranchPoints); Assert.AreEqual(1, Instance.CoverageSession.Modules[0].Classes[0].Methods[0].Summary.VisitedBranchPoints); }
private static BranchPoint[] GetBranchPoints(MethodDefinition method, FileReference fileReference) { uint ordinal = 0; return(method.DebugInformation.GetScopes() .Select(x => { var branchPoint = new BranchPoint { Offset = x.Start.Offset, EndOffset = x.End.Offset, Ordinal = ordinal++, FileReference = fileReference }; if (x.HasScopes) { using (var enumerator = x.Scopes.GetEnumerator()) while (enumerator.MoveNext()) { branchPoint.OffsetPoints.Add(enumerator.Current.Start.Offset); } } return branchPoint; }).ToArray()); }
private IEnumerable <Suffix> AllFromNode(Node node, int length) { DebugCode.AssertArgument(length >= 0, nameof(length), "The length should be non-negative"); if (node.IsLeaf) // Empty subtree { if (length != 0) { yield return(CreateSuffix(node.End, length)); } yield break; } var branchStack = new Stack <BranchPoint>(); var branchPoint = new BranchPoint { Node = node, EdgeIndex = 0 }; for (;;) { DebugCode.BugIf(branchPoint.Node.Children == null, "branchPoint.Node.Children == null"); var edge = GetNode(branchPoint.Node.Children[branchPoint.EdgeIndex]); var edgeLength = edge.Length; length += edgeLength; if (!edge.IsTerminal) { branchPoint.Length = edgeLength; branchStack.Push(branchPoint); branchPoint = new BranchPoint { Node = edge, EdgeIndex = 0 }; continue; } // We have descended to a terminal edge. Let's produce a suffix yield return(CreateSuffix(edge.End, length)); // Move to the next suffix branch for (;;) { length -= edgeLength; var nextEdgeIndex = branchPoint.EdgeIndex + 1; DebugCode.BugIf(branchPoint.Node.Children == null, "branchPoint.Node.Children == null"); if (nextEdgeIndex < branchPoint.Node.Children.Count) { branchPoint.EdgeIndex = nextEdgeIndex; break; } // There is no more branches on the current level // Return to the previous level if (branchStack.Count == 0) { // no more branches to visit yield break; } branchPoint = branchStack.Pop(); edgeLength = branchPoint.Length; } } }
private uint BuildPointsForBranch(List <BranchPoint> list, Instruction then, int branchingInstructionLine, string document, int branchOffset, uint ordinal, int pathCounter, BranchPoint path0, Collection <Instruction> instructions, MethodDefinition methodDefinition) { var pathOffsetList1 = GetBranchPath(@then); // Add path 1 var path1 = new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter, OffsetPoints = pathOffsetList1.Count > 1 ? pathOffsetList1.GetRange(0, pathOffsetList1.Count - 1) : new List <int>(), EndOffset = pathOffsetList1.Last() }; // only add branch if branch does not match a known sequence // e.g. auto generated field assignment // or encapsulates at least one sequence point var offsets = new[] { path0.Offset, path0.EndOffset, path1.Offset, path1.EndOffset }; var ignoreSequences = new[] { // we may need other samples new[] { Code.Brtrue_S, Code.Pop, Code.Ldsfld, Code.Ldftn, Code.Newobj, Code.Dup, Code.Stsfld, Code.Newobj }, // CachedAnonymousMethodDelegate field allocation }; var bs = offsets.Min(); var be = offsets.Max(); var range = instructions.Where(i => (i.Offset >= bs) && (i.Offset <= be)).ToList(); var match = ignoreSequences .Where(ignoreSequence => range.Count >= ignoreSequence.Length) .Any(ignoreSequence => range.Zip(ignoreSequence, (instruction, code) => instruction.OpCode.Code == code).All(x => x)); var count = range .Count(i => methodDefinition.DebugInformation.GetSequencePoint(i) != null); if (!match || count > 0) { list.Add(path0); list.Add(path1); } return(ordinal); }
private bool BuildPointsForConditionalBranch(List <BranchPoint> list, Instruction instruction, int branchingInstructionLine, string document, int branchOffset, int pathCounter, Collection <Instruction> instructions, ref uint ordinal, MethodDefinition methodDefinition) { // Add Default branch (Path=0) // Follow else/default instruction var @else = instruction.Next; var pathOffsetList = GetBranchPath(@else); // add Path 0 var path0 = new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter++, OffsetPoints = pathOffsetList.Count > 1 ? pathOffsetList.GetRange(0, pathOffsetList.Count - 1) : new List <int>(), EndOffset = pathOffsetList.Last() }; // Add Conditional Branch (Path=1) if (instruction.OpCode.Code != Code.Switch) { // Follow instruction at operand var @then = instruction.Operand as Instruction; if (@then == null) { return(false); } ordinal = BuildPointsForBranch(list, then, branchingInstructionLine, document, branchOffset, ordinal, pathCounter, path0, instructions, methodDefinition); } else // instruction.OpCode.Code == Code.Switch { var branchInstructions = instruction.Operand as Instruction[]; if (branchInstructions == null || branchInstructions.Length == 0) { return(false); } ordinal = BuildPointsForSwitchCases(list, path0, branchInstructions, branchingInstructionLine, document, branchOffset, ordinal, ref pathCounter); } return(true); }
/// <summary> /// Get the branch ponts for a function /// </summary> /// <param name="modulePath"></param> /// <param name="functionToken"></param> /// <param name="branchPoints"></param> /// <returns></returns> public bool GetBranchPointsForFunction(string modulePath, int functionToken, out BranchPoint[] branchPoints) { branchPoints = new BranchPoint[0]; var method = GetMethod(modulePath, functionToken, out Class @class); if (method != null && method.BranchPoints.Any()) { System.Diagnostics.Debug.WriteLine("Getting Branch points for {0}({1})", method.FullName, method.MetadataToken); branchPoints = method.BranchPoints.ToArray(); return(true); } return(false); }
public void GetBarkData(float x, float y, out Vector3 pos, out Vector3 centerPos, out Vector3 dir, out Vector3 nor, out Vector3 tang, out float life, out float width) { float v = x * .99f * ((float)numPoints - 1); float angle = y * 2 * Mathf.PI; float up = Mathf.Ceil(v); float down = Mathf.Floor(v); float inVal = v - down; Vector3 fPos; Vector3 fPos1; float fLife; float fWidth; if (inVal == 0 || up == down) { v += .0001f; up = Mathf.Ceil(v); down = Mathf.Floor(v); inVal = v - down; } BranchPoint p1 = points[(int)down]; BranchPoint p2 = points[(int)up]; fPos = cubicPoint(inVal, p1.position, p1.position + p1.normal / 3, p2.position - p2.normal / 3, p2.position); fPos1 = cubicPoint(inVal + .001f, p1.position, p1.position + p1.normal / 3, p2.position - p2.normal / 3, p2.position); fLife = Mathf.Lerp(p1.timeCreated, p2.timeCreated, inVal); fWidth = Mathf.Lerp(p1.width, p2.width, inVal); Vector3 fNor = Vector3.Lerp(p1.normal, p2.normal, inVal); Vector3 fTan = Vector3.Lerp(p1.tangent, p2.tangent, inVal); Vector3 fBi = Vector3.Lerp(p1.binormal, p2.binormal, inVal); Vector3 outVec = (fTan * Mathf.Sin(angle) - fBi * Mathf.Cos(angle)) * fWidth; centerPos = fPos; fPos += outVec; // radius;; pos = fPos; dir = (fPos1 - fPos).normalized; nor = outVec.normalized; tang = Vector3.Cross(nor, dir).normalized; life = fLife; width = fWidth; }
public void CanReturnLineNumbers() { // arrange var sequencePoint = new BranchPoint { StartLine = 1 }; // act var lineNumbers = sequencePoint.GetSourceLocation(); // assert Assert.AreEqual(1, lineNumbers.Item1); Assert.IsNull(lineNumbers.Item2); }
private uint BuildPointsForConditionalBranch(List <BranchPoint> list, Instruction current, Instruction[] branchInstructions, int branchingInstructionLine, string document, int branchOffset, uint ordinal, ref int pathCounter) { // add Path 0 var pathOffsetList = GetConditionalBranchPath(current.Next); var path0 = new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter++, OffsetPoints = pathOffsetList.Count > 1 ? pathOffsetList.GetRange(0, pathOffsetList.Count - 1) : new List <int>(), EndOffset = pathOffsetList.Last() }; list.Add(path0); var counter = pathCounter; // Add Conditional Branches (Path>0) list.AddRange(branchInstructions.Select(GetConditionalBranchPath) .Select(pathOffsetList1 => new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = counter++, OffsetPoints = pathOffsetList1.Count > 1 ? pathOffsetList1.GetRange(0, pathOffsetList1.Count - 1) : new List <int>(), EndOffset = pathOffsetList1.Last() })); pathCounter = counter; return(ordinal); }
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, BranchPoint branchPoint) { if (!_result.Documents.TryGetValue(branchPoint.Document, out var document)) { document = new Document { Path = branchPoint.Document }; document.Index = _result.Documents.Count; _result.Documents.Add(document.Path, document); } BranchKey key = new BranchKey(branchPoint.StartLine, (int)branchPoint.Ordinal); if (!document.Branches.ContainsKey(key)) { document.Branches.Add( key, new Branch { Number = branchPoint.StartLine, Class = method.DeclaringType.FullName, Method = method.FullName, Offset = branchPoint.Offset, EndOffset = branchPoint.EndOffset, Path = branchPoint.Path, Ordinal = branchPoint.Ordinal } ); if (method.DeclaringType.CustomAttributes.Any(x => x.AttributeType.FullName == typeof(CompilerGeneratedAttribute).FullName)) { if (_branchesInCompiledGeneratedClass == null) { _branchesInCompiledGeneratedClass = new List <string>(); } if (!_branchesInCompiledGeneratedClass.Contains(method.FullName)) { _branchesInCompiledGeneratedClass.Add(method.FullName); } } } _result.HitCandidates.Add(new HitCandidate(true, document.Index, branchPoint.StartLine, (int)branchPoint.Ordinal)); return(AddInstrumentationInstructions(method, processor, instruction, _result.HitCandidates.Count - 1)); }
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, BranchPoint branchPoint) { if (!_result.Documents.TryGetValue(branchPoint.Document, out var document)) { document = new Document { Path = branchPoint.Document }; _result.Documents.Add(document.Path, document); } var key = (branchPoint.StartLine, (int)branchPoint.Ordinal); if (!document.Branches.ContainsKey(key)) { document.Branches.Add(key, new Branch { Number = branchPoint.StartLine, Class = method.DeclaringType.FullName, Method = method.FullName, Offset = branchPoint.Offset, EndOffset = branchPoint.EndOffset, Path = branchPoint.Path, Ordinal = branchPoint.Ordinal } ); } string marker = $"B,{document.Path},{branchPoint.StartLine},{branchPoint.Ordinal}"; var pathInstr = Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath); var markInstr = Instruction.Create(OpCodes.Ldstr, marker); var callInstr = Instruction.Create(OpCodes.Call, processor.Body.Method.Module.ImportReference(_markExecutedMethodLoader.Value)); processor.InsertBefore(instruction, callInstr); processor.InsertBefore(callInstr, markInstr); processor.InsertBefore(markInstr, pathInstr); return(pathInstr); }
// Making points along each branch public void MakePoints() { Vector3 currPos = startPosition; tree.currentTotalPoints += numPoints; // place the points along the branch for (int i = 0; i < numPoints; i++) { float valInBranch = ((float)i / ((float)numPoints - 1)); float widthMultiplier = 1; if (iterationLevel == 0) { widthMultiplier = tree.trunkCurve.Evaluate(valInBranch); } else { widthMultiplier = tree.branchCurve.Evaluate(valInBranch); } if (i != 0) { float currNoiseSize = currVal(tree.noiseSize, tree.noiseSizeReducer); float currNoisePower = currVal(tree.noisePower, tree.noisePowerReducer); float currUp = currVal(tree.upDesire, tree.upDesireReducer); if (i != 1) { Vector3 dir = points[i - 1].position - points[i - 2].position; currPos += dir.normalized * length * ((float)1 / ((float)numPoints - 1)); } else { currPos += length * direction * ((float)1 / ((float)numPoints - 1)); } currPos += currUp * Vector3.up * .003f; Vector3 noiseDir = Perlin.CurlNoise(currPos * currNoiseSize + tree.noiseOffset); currPos += noiseDir * currNoisePower * .04f; } float fWidth = baseWidth * widthMultiplier; BranchPoint p = new BranchPoint(currPos, valInBranch, timeCreated + valInBranch, fWidth); points.Add(p); // TODO ADD NOISE } // Gets Tangents for each of the points for sake of // cubic beziers for (int i = 0; i < numPoints; i++) { BranchPoint p = points[i]; if (i == 0) { p.normal = (points[1].position - p.position); } else if (i == points.Count - 1) { p.normal = (p.position - points[points.Count - 2].position); } else { p.normal = -(points[i - 1].position - points[i + 1].position); } if (i == 0) { p.tangent = (Vector3.Cross(p.normal.normalized, Vector3.left)).normalized; p.binormal = (Vector3.Cross(p.normal, p.tangent)).normalized; } else { p.tangent = -(Vector3.Cross(p.normal.normalized, points[i - 1].binormal)).normalized; p.binormal = (Vector3.Cross(p.normal, p.tangent)).normalized; } points[i] = p; } }
private void GetBranchPointsForToken(int token, List <BranchPoint> list) { var methodDefinition = GetMethodDefinition(token); if (methodDefinition == null) { return; } UInt32 ordinal = 0; int branchOffset = 0; int pathCounter = 0; List <int> PathOffsetList; foreach (var instruction in methodDefinition.Body.Instructions) { if (instruction.OpCode.FlowControl != FlowControl.Cond_Branch) { continue; } pathCounter = 0; // store branch origin offset branchOffset = instruction.Offset; Debug.Assert(!Object.ReferenceEquals(null, instruction.Next)); if (Object.ReferenceEquals(null, instruction.Next)) { return; } // Add Default branch (Path=0) Debug.Assert(pathCounter == 0); // Follow else/default instruction Instruction @else = instruction.Next; PathOffsetList = GetBranchPath(@else); Debug.Assert(PathOffsetList.Count > 0); // add Path 0 BranchPoint path0 = new BranchPoint() { Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter++, OffsetPoints = PathOffsetList.Count > 1 ? PathOffsetList.GetRange(0, PathOffsetList.Count - 1) : new List <int>(), EndOffset = PathOffsetList.Last() }; Debug.Assert(!Object.ReferenceEquals(null, path0.OffsetPoints)); list.Add(path0); Debug.Assert(ordinal != 0); Debug.Assert(pathCounter != 0); // Add Conditional Branch (Path=1) if (instruction.OpCode.Code != Code.Switch) { // Follow instruction at operand Instruction @then = instruction.Operand as Instruction; Debug.Assert(!Object.ReferenceEquals(null, @then)); if (Object.ReferenceEquals(null, @then)) { return; } PathOffsetList = GetBranchPath(@then); Debug.Assert(PathOffsetList.Count > 0); // Add path 1 BranchPoint path1 = new BranchPoint() { Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter++, OffsetPoints = PathOffsetList.Count > 1 ? PathOffsetList.GetRange(0, PathOffsetList.Count - 1) : new List <int>(), EndOffset = PathOffsetList.Last() }; Debug.Assert(!Object.ReferenceEquals(null, path1.OffsetPoints)); list.Add(path1); } else // instruction.OpCode.Code == Code.Switch { Instruction[] branchInstructions = instruction.Operand as Instruction[]; Debug.Assert(!Object.ReferenceEquals(null, branchInstructions)); Debug.Assert(branchInstructions.Length != 0); if (Object.ReferenceEquals(null, branchInstructions) || branchInstructions.Length == 0) { return; } // Add Conditional Branches (Path>0) foreach (var @case in branchInstructions) { // Follow operand istruction PathOffsetList = GetBranchPath(@case); Debug.Assert(PathOffsetList.Count > 0); // add paths 1..n BranchPoint path1toN = new BranchPoint() { Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter++, OffsetPoints = PathOffsetList.Count > 1 ? PathOffsetList.GetRange(0, PathOffsetList.Count - 1) : new List <int>(), EndOffset = PathOffsetList.Last() }; Debug.Assert(!Object.ReferenceEquals(null, path1toN.OffsetPoints)); list.Add(path1toN); } } } }
private void GetBranchPointsForToken(int token, List <BranchPoint> list) { var methodDefinition = GetMethodDefinition(token); if (methodDefinition == null) { return; } try { UInt32 ordinal = 0; foreach (var instruction in methodDefinition.SafeGetMethodBody().Instructions) { if (instruction.OpCode.FlowControl != FlowControl.Cond_Branch) { continue; } if (BranchIsInGeneratedFinallyBlock(instruction, methodDefinition)) { continue; } var pathCounter = 0; // store branch origin offset var branchOffset = instruction.Offset; var closestSeqPt = FindClosestSequencePoints(methodDefinition.Body, instruction); var branchingInstructionLine = closestSeqPt.Maybe(sp => sp.SequencePoint.StartLine, -1); var document = closestSeqPt.Maybe(sp => sp.SequencePoint.Document.Url); if (null == instruction.Next) { return; } // Add Default branch (Path=0) // Follow else/default instruction var @else = instruction.Next; var pathOffsetList = GetBranchPath(@else); // add Path 0 var path0 = new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter++, OffsetPoints = pathOffsetList.Count > 1 ? pathOffsetList.GetRange(0, pathOffsetList.Count - 1) : new List <int>(), EndOffset = pathOffsetList.Last() }; list.Add(path0); // Add Conditional Branch (Path=1) if (instruction.OpCode.Code != Code.Switch) { // Follow instruction at operand var @then = instruction.Operand as Instruction; if (@then == null) { return; } pathOffsetList = GetBranchPath(@then); // Add path 1 var path1 = new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter, OffsetPoints = pathOffsetList.Count > 1 ? pathOffsetList.GetRange(0, pathOffsetList.Count - 1) : new List <int>(), EndOffset = pathOffsetList.Last() }; list.Add(path1); } else // instruction.OpCode.Code == Code.Switch { var branchInstructions = instruction.Operand as Instruction[]; if (branchInstructions == null || branchInstructions.Length == 0) { return; } // Add Conditional Branches (Path>0) foreach (var @case in branchInstructions) { // Follow operand istruction pathOffsetList = GetBranchPath(@case); // add paths 1..n var path1ToN = new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter++, OffsetPoints = pathOffsetList.Count > 1 ? pathOffsetList.GetRange(0, pathOffsetList.Count - 1) : new List <int>(), EndOffset = pathOffsetList.Last() }; list.Add(path1ToN); } } } } catch (Exception ex) { throw new InvalidOperationException( string.Format("An error occurred with 'GetBranchPointsForToken' for method '{0}'", methodDefinition.FullName), ex); } }
public void CanLoadExistingFileWhenInitialising() { // arrange var moduleHash = Guid.NewGuid().ToString(); var persistence = new FilePersistance(_mockCommandLine.Object, _mockLogger.Object); persistence.Initialise(_filePath, false); var point = new SequencePoint() // BranchPoints within SequencePoint shorther than 3 characters will be removed { StartLine = 1, EndLine = 1, StartColumn = 1, EndColumn = 4 }; var branchPoint = new BranchPoint { Path = 0, OffsetPoints = new List <int>() }; var branchPoint2 = new BranchPoint { Path = 1, OffsetPoints = new List <int> { 1, 2 } }; var file = new OpenCover.Framework.Model.File(); var filref = new FileRef() { UniqueId = file.UniqueId }; persistence.PersistModule(new Module { Summary = new Summary { NumSequencePoints = 1 }, Files = new[] { file }, ModuleHash = moduleHash, Classes = new[] { new Class { Summary = new Summary { NumSequencePoints = 1 }, Files = new[] { file }, Methods = new[] { new Method { FileRef = filref, MetadataToken = 1234, Summary = new Summary { NumSequencePoints = 1 }, MethodPoint = point, SequencePoints = new[] { point }, BranchPoints = new[] { branchPoint, branchPoint2 } } } } } }); persistence.Commit(); var persistence2 = new FilePersistance(_mockCommandLine.Object, _mockLogger.Object); // act persistence2.Initialise(_filePath, true); // assert Assert.IsNotNull(persistence2.CoverageSession); Assert.AreEqual(moduleHash, persistence2.CoverageSession.Modules[0].ModuleHash); Assert.AreEqual(point.UniqueSequencePoint, persistence2.CoverageSession.Modules[0].Classes[0].Methods[0].SequencePoints[0].UniqueSequencePoint); Assert.AreEqual(point.UniqueSequencePoint, persistence2.CoverageSession.Modules[0].Classes[0].Methods[0].MethodPoint.UniqueSequencePoint); var method = persistence2.CoverageSession.Modules[0].Classes[0].Methods[0]; var br1 = persistence2.CoverageSession.Modules[0].Classes[0].Methods[0].BranchPoints[0]; var br2 = persistence2.CoverageSession.Modules[0].Classes[0].Methods[0].BranchPoints[1]; Assert.AreEqual(branchPoint.UniqueSequencePoint, br1.UniqueSequencePoint); Assert.AreEqual(branchPoint2.UniqueSequencePoint, br2.UniqueSequencePoint); Assert.AreEqual(0, br1.OffsetPoints.Count); Assert.AreEqual(2, br2.OffsetPoints.Count); Assert.AreEqual(1, br2.OffsetPoints[0]); Assert.AreEqual(2, br2.OffsetPoints[1]); // the method and sequence point if point to same offset need to merge Assert.AreSame(method.MethodPoint, method.SequencePoints[0]); // the loaded summary object needs to be cleared Assert.AreEqual(0, persistence2.CoverageSession.Summary.NumSequencePoints); Assert.AreEqual(0, persistence2.CoverageSession.Modules[0].Summary.NumSequencePoints); Assert.AreEqual(0, persistence2.CoverageSession.Modules[0].Classes[0].Summary.NumSequencePoints); Assert.AreEqual(0, persistence2.CoverageSession.Modules[0].Classes[0].Methods[0].Summary.NumSequencePoints); }
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, BranchPoint branchPoint) { if (!_result.Documents.TryGetValue(branchPoint.Document, out var document)) { document = new Document { Path = branchPoint.Document }; document.Index = _result.Documents.Count; _result.Documents.Add(document.Path, document); } BranchKey key = new BranchKey(branchPoint.StartLine, (int)branchPoint.Ordinal); if (!document.Branches.ContainsKey(key)) { document.Branches.Add(key, new Branch { Number = branchPoint.StartLine, Class = method.DeclaringType.FullName, Method = method.FullName, Offset = branchPoint.Offset, EndOffset = branchPoint.EndOffset, Path = branchPoint.Path, Ordinal = branchPoint.Ordinal } ); } _result.HitCandidates.Add(new HitCandidate(true, document.Index, branchPoint.StartLine, (int)branchPoint.Ordinal)); return(AddInstrumentationInstructions(method, processor, instruction, _result.HitCandidates.Count - 1)); }
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, BranchPoint branchPoint) { var document = _result.Documents.FirstOrDefault(d => d.Path == branchPoint.Document); if (document == null) { document = new Document { Path = branchPoint.Document }; _result.Documents.Add(document); } if (!document.Branches.Exists(l => l.Number == branchPoint.StartLine && l.Ordinal == branchPoint.Ordinal)) { document.Branches.Add( new Branch { Number = branchPoint.StartLine, Class = method.DeclaringType.FullName, Method = method.FullName, Offset = branchPoint.Offset, EndOffset = branchPoint.EndOffset, Path = branchPoint.Path, Ordinal = branchPoint.Ordinal } ); } string marker = $"B,{document.Path},{branchPoint.StartLine},{branchPoint.Ordinal}"; var pathInstr = Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath); var markInstr = Instruction.Create(OpCodes.Ldstr, marker); var callInstr = Instruction.Create(OpCodes.Call, processor.Body.Method.Module.ImportReference(_markExecutedMethodLoader.Value)); processor.InsertBefore(instruction, callInstr); processor.InsertBefore(callInstr, markInstr); processor.InsertBefore(markInstr, pathInstr); return(pathInstr); }
private void GetBranchPointsForToken(int token, List <BranchPoint> list) { var methodDefinition = GetMethodDefinition(token); if (methodDefinition == null) { return; } try { UInt32 ordinal = 0; var instructions = methodDefinition.SafeGetMethodBody().Instructions; // if method is a generated MoveNext skip first branch (could be a switch or a branch) var skipFirstBranch = Regex.IsMatch(methodDefinition.FullName, @"\<.+\>d__\d+::MoveNext\(\)$"); foreach (var instruction in instructions.Where(instruction => instruction.OpCode.FlowControl == FlowControl.Cond_Branch)) { if (skipFirstBranch) { skipFirstBranch = false; continue; } if (BranchIsInGeneratedFinallyBlock(instruction, methodDefinition)) { continue; } var pathCounter = 0; // store branch origin offset var branchOffset = instruction.Offset; var closestSeqPt = FindClosestSequencePoints(methodDefinition.Body, instruction); var branchingInstructionLine = closestSeqPt.Maybe(sp => sp.SequencePoint.StartLine, -1); var document = closestSeqPt.Maybe(sp => sp.SequencePoint.Document.Url); if (null == instruction.Next) { return; } // Add Default branch (Path=0) // Follow else/default instruction var @else = instruction.Next; var pathOffsetList = GetBranchPath(@else); // add Path 0 var path0 = new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter++, OffsetPoints = pathOffsetList.Count > 1 ? pathOffsetList.GetRange(0, pathOffsetList.Count - 1) : new List <int>(), EndOffset = pathOffsetList.Last() }; // Add Conditional Branch (Path=1) if (instruction.OpCode.Code != Code.Switch) { // Follow instruction at operand var @then = instruction.Operand as Instruction; if (@then == null) { return; } pathOffsetList = GetBranchPath(@then); // Add path 1 var path1 = new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter, OffsetPoints = pathOffsetList.Count > 1 ? pathOffsetList.GetRange(0, pathOffsetList.Count - 1) : new List <int>(), EndOffset = pathOffsetList.Last() }; // only add branch if branch does not match a known sequence // e.g. auto generated field assignment // or encapsulates at least one sequence point var offsets = new[] { path0.Offset, path0.EndOffset, path1.Offset, path1.EndOffset }; var ignoreSequences = new[] { new [] { Code.Brtrue_S, Code.Ldnull, Code.Ldftn, Code.Newobj, Code.Stsfld, Code.Br_S, Code.Ldsfld }, // CachedAnonymousMethodDelegate field allocation - debug new [] { Code.Brtrue_S, Code.Ldnull, Code.Ldftn, Code.Newobj, Code.Stsfld, Code.Ldsfld } // CachedAnonymousMethodDelegate field allocation }; var bs = offsets.Min(); var be = offsets.Max(); var range = instructions.Where(i => (i.Offset >= bs) && (i.Offset <= be)).ToList(); var match = ignoreSequences .Where(ignoreSequence => range.Count() >= ignoreSequence.Count()) .Select(x => x.Zip(range, (code, i1) => new { Code1 = code, Code2 = i1.OpCode.Code }).All(y => y.Code1 == y.Code2)) .Any(); var count = range .Count(i => i.SequencePoint != null); if (!match || count > 0) { list.Add(path0); list.Add(path1); } } else // instruction.OpCode.Code == Code.Switch { var branchInstructions = instruction.Operand as Instruction[]; if (branchInstructions == null || branchInstructions.Length == 0) { return; } list.Add(path0); // Add Conditional Branches (Path>0) foreach (var @case in branchInstructions) { // Follow operand istruction pathOffsetList = GetBranchPath(@case); // add paths 1..n var path1ToN = new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter++, OffsetPoints = pathOffsetList.Count > 1 ? pathOffsetList.GetRange(0, pathOffsetList.Count - 1) : new List <int>(), EndOffset = pathOffsetList.Last() }; list.Add(path1ToN); } } } } catch (Exception ex) { throw new InvalidOperationException( string.Format("An error occurred with 'GetBranchPointsForToken' for method '{0}'", methodDefinition.FullName), ex); } }
private uint BuildPointsForBranch(List <BranchPoint> list, Instruction then, int branchingInstructionLine, string document, int branchOffset, uint ordinal, int pathCounter, BranchPoint path0, Collection <Instruction> instructions) { var pathOffsetList1 = GetBranchPath(@then); // Add path 1 var path1 = new BranchPoint { StartLine = branchingInstructionLine, Document = document, Offset = branchOffset, Ordinal = ordinal++, Path = pathCounter, OffsetPoints = pathOffsetList1.Count > 1 ? pathOffsetList1.GetRange(0, pathOffsetList1.Count - 1) : new List <int>(), EndOffset = pathOffsetList1.Last() }; // only add branch if branch does not match a known sequence // e.g. auto generated field assignment // or encapsulates at least one sequence point var offsets = new[] { path0.Offset, path0.EndOffset, path1.Offset, path1.EndOffset }; var ignoreSequences = new[] { new[] { Code.Brtrue_S, Code.Ldnull, Code.Ldftn, Code.Newobj, Code.Stsfld, Code.Br_S, Code.Ldsfld }, // CachedAnonymousMethodDelegate field allocation - debug new[] { Code.Brtrue_S, Code.Ldnull, Code.Ldftn, Code.Newobj, Code.Stsfld, Code.Ldsfld } // CachedAnonymousMethodDelegate field allocation }; var bs = offsets.Min(); var be = offsets.Max(); var range = instructions.Where(i => (i.Offset >= bs) && (i.Offset <= be)).ToList(); var match = ignoreSequences .Where(ignoreSequence => range.Count() >= ignoreSequence.Count()) .Select( x => x.Zip(range, (code, i1) => new { Code1 = code, Code2 = i1.OpCode.Code }) .All(y => y.Code1 == y.Code2)) .Any(); var count = range .Count(i => i.SequencePoint != null); if (!match || count > 0) { list.Add(path0); list.Add(path1); } return(ordinal); }
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, BranchPoint branchPoint) { if (!_result.Documents.TryGetValue(branchPoint.Document, out var document)) { document = new Document { Path = branchPoint.Document }; document.Index = _result.Documents.Count; _result.Documents.Add(document.Path, document); } var key = (branchPoint.StartLine, (int)branchPoint.Ordinal); if (!document.Branches.ContainsKey(key)) { document.Branches.Add(key, new Branch { Number = branchPoint.StartLine, Class = method.DeclaringType.FullName, Method = method.FullName, Offset = branchPoint.Offset, EndOffset = branchPoint.EndOffset, Path = branchPoint.Path, Ordinal = branchPoint.Ordinal } ); if (IsAsyncStateMachineBranch(method.DeclaringType, method)) { if (_asyncMachineStateMethod == null) { _asyncMachineStateMethod = new List <string>(); } if (!_asyncMachineStateMethod.Contains(method.FullName)) { _asyncMachineStateMethod.Add(method.FullName); } } } var entry = (true, document.Index, branchPoint.StartLine, (int)branchPoint.Ordinal); _result.HitCandidates.Add(entry); return(AddInstrumentationInstructions(method, processor, instruction, _result.HitCandidates.Count - 1)); }
private void CreateEntries(Conversation conversation) { visitedIDs.Clear(); DialogueEntry currentEntry = conversation.dialogueEntries[0]; while (currentEntry.outgoingLinks.Count > 0 || branchPoints.Count > 0) { currentEntry = GetNextEntry(currentEntry); if (branchPoints.Count > 0 && (IsDeadEnd(currentEntry) || IsPickUpPoint(currentEntry))) { if (currentEntry != null && IsDeadEnd(currentEntry)) { TokenizeEntry(currentEntry); } BranchPoint bp = branchPoints[branchPoints.Count - 1]; TokenizeBranchName(bp.branchNodes[0]); bp.branchNodes.RemoveAt(0); builder.AppendLine(); if (bp.branchNodes.Count > 0) { currentEntry = bp.branchNodes[0]; TokenizeBranchName(bp.branchNodes[0]); } else { branchPoints.Remove(bp); while (branchPoints.Count > 0) { BranchPoint parentBranch = branchPoints[branchPoints.Count - 1]; TokenizeBranchName(parentBranch.branchNodes[0]); parentBranch.branchNodes.RemoveAt(0); if (parentBranch.branchNodes.Count > 0) { currentEntry = parentBranch.branchNodes[0]; builder.AppendLine(); TokenizeBranchName(parentBranch.branchNodes[0]); break; } else { branchPoints.Remove(parentBranch); } } } } if (currentEntry != null) { if (!HasAlreadyBeenVisited(currentEntry)) { TokenizeEntry(currentEntry); } else if (currentEntry.outgoingLinks.Count > 0) { AddRecursiveErrorWarning(); break; } } else { break; } } }