diff --git a/src/coverlet.core/Coverage.cs b/src/coverlet.core/Coverage.cs index e6750cefa..59439a91d 100644 --- a/src/coverlet.core/Coverage.cs +++ b/src/coverlet.core/Coverage.cs @@ -161,6 +161,8 @@ private void CalculateCoverage() continue; } + List documents = result.Documents.Values.ToList(); + using (var fs = new FileStream(result.HitsFilePath, FileMode.Open)) using (var sr = new StreamReader(fs)) { @@ -173,7 +175,7 @@ private void CalculateCoverage() continue; bool isBranch = info[0] == "B"; - var document = result.Documents.ElementAt(int.Parse(info[1])).Value; + var document = documents[int.Parse(info[1])]; int start = int.Parse(info[2]); int hits = int.Parse(info[4]); diff --git a/src/coverlet.core/Instrumentation/Instrumenter.cs b/src/coverlet.core/Instrumentation/Instrumenter.cs index 5925298e9..c89c42d75 100644 --- a/src/coverlet.core/Instrumentation/Instrumenter.cs +++ b/src/coverlet.core/Instrumentation/Instrumenter.cs @@ -175,17 +175,12 @@ private void InstrumentIL(MethodDefinition method) private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint) { - int documentIndex = 0; if (!_result.Documents.TryGetValue(sequencePoint.Document.Url, out var document)) { document = new Document { Path = sequencePoint.Document.Url }; - documentIndex = _result.Documents.Count; + document.Index = _result.Documents.Count; _result.Documents.Add(document.Path, document); } - else - { - documentIndex = _result.Documents.Keys.ToList().IndexOf(document.Path); - } for (int i = sequencePoint.StartLine; i <= sequencePoint.EndLine; i++) { @@ -193,7 +188,7 @@ private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor document.Lines.Add(i, new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName }); } - string marker = $"L,{documentIndex},{sequencePoint.StartLine},{sequencePoint.EndLine}"; + string marker = $"L,{document.Index},{sequencePoint.StartLine},{sequencePoint.EndLine}"; var pathInstr = Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath); var markInstr = Instruction.Create(OpCodes.Ldstr, marker); @@ -208,17 +203,12 @@ private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, BranchPoint branchPoint) { - int documentIndex = 0; if (!_result.Documents.TryGetValue(branchPoint.Document, out var document)) { document = new Document { Path = branchPoint.Document }; - documentIndex = _result.Documents.Count; + document.Index = _result.Documents.Count; _result.Documents.Add(document.Path, document); } - else - { - documentIndex = _result.Documents.Keys.ToList().IndexOf(document.Path); - } var key = (branchPoint.StartLine, (int)branchPoint.Ordinal); if (!document.Branches.ContainsKey(key)) @@ -235,7 +225,7 @@ private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor } ); - string marker = $"B,{documentIndex},{branchPoint.StartLine},{branchPoint.Ordinal}"; + string marker = $"B,{document.Index},{branchPoint.StartLine},{branchPoint.Ordinal}"; var pathInstr = Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath); var markInstr = Instruction.Create(OpCodes.Ldstr, marker); diff --git a/src/coverlet.core/Instrumentation/InstrumenterResult.cs b/src/coverlet.core/Instrumentation/InstrumenterResult.cs index 615e2e316..dcd82694a 100644 --- a/src/coverlet.core/Instrumentation/InstrumenterResult.cs +++ b/src/coverlet.core/Instrumentation/InstrumenterResult.cs @@ -27,6 +27,7 @@ public Document() } public string Path; + public int Index; public Dictionary Lines { get; private set; } public Dictionary<(int Line, int Ordinal), Branch> Branches { get; private set; } diff --git a/src/coverlet.tracker/CoverageTracker.cs b/src/coverlet.tracker/CoverageTracker.cs index c41accff5..6486a2f68 100644 --- a/src/coverlet.tracker/CoverageTracker.cs +++ b/src/coverlet.tracker/CoverageTracker.cs @@ -8,6 +8,7 @@ namespace Coverlet.Tracker public static class CoverageTracker { private static List>> _events; + private static readonly StringHashSuffixComparer _stringHashSuffixComparer = new StringHashSuffixComparer(); [ThreadStatic] private static Dictionary> t_events; @@ -25,7 +26,7 @@ public static void MarkExecuted(string file, string evt) { if (t_events == null) { - t_events = new Dictionary>(); + t_events = new Dictionary>(_stringHashSuffixComparer); lock (_events) { _events.Add(t_events); @@ -38,7 +39,7 @@ public static void MarkExecuted(string file, string evt) { if (!t_events.TryGetValue(file, out var fileEvents)) { - fileEvents = new Dictionary(); + fileEvents = new Dictionary(_stringHashSuffixComparer); t_events.Add(file, fileEvents); } diff --git a/src/coverlet.tracker/StringHashSuffixComparer.cs b/src/coverlet.tracker/StringHashSuffixComparer.cs new file mode 100644 index 000000000..78f0cd0fd --- /dev/null +++ b/src/coverlet.tracker/StringHashSuffixComparer.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +namespace Coverlet.Tracker +{ + internal class StringHashSuffixComparer : IEqualityComparer + { + public bool Equals(string x, string y) => string.Equals(x, y); + + public int GetHashCode(string s) + { + if (s == null || s.Length == 0) + return 0; + + // Hash calculation based on the old implementation of NameTable used in System.Xml + const int SuffixLength = 8; + const int Seed = 1031880390; + int hashCode; + unchecked + { + hashCode = s.Length + Seed; + int i = s.Length > SuffixLength ? s.Length - SuffixLength : 0; + for (; i> 17; + hashCode -= hashCode >> 11; + hashCode -= hashCode >> 5; + } + + return hashCode; + } + } +}