diff --git a/src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageMethodElement.cs b/src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageMethodElement.cs index 18d52aef50..9f1878485b 100644 --- a/src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageMethodElement.cs +++ b/src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageMethodElement.cs @@ -21,6 +21,7 @@ namespace ICSharpCode.CodeCoverage public int Offset; public int Visit; public int Count; + public CodeCoverageSequencePoint SeqPoint; public branchOffset( int offset ) { this.Offset = offset; } @@ -118,12 +119,12 @@ namespace ICSharpCode.CodeCoverage if (cacheFileName == sp.Document && cacheDocument != null) { sp.Content = cacheDocument.GetText(sp); if (sp.Line != sp.EndLine) { - sp.Content = Regex.Replace (sp.Content, @"\s+", " "); + sp.Content = Regex.Replace (sp.Content, @"\s+", " "); } - sp.Length = Regex.Replace (sp.Content, @"\s", "").Length; // ignore white-space for coverage% + sp.Length = Regex.Replace (sp.Content, @"\s", "").Length; // ignore white-space for coverage% } else { sp.Content = String.Empty; - sp.Length = 0; + sp.Length = 0; } sp.Offset = (int)GetDecimalAttributeValue(xSPoint.Attribute("offset")); sp.BranchCoverage = true; @@ -165,9 +166,9 @@ namespace ICSharpCode.CodeCoverage // goal: Get branch ratio and exclude (rewriten) Code Contracts branches if ( this.BranchPoints == null - || this.BranchPoints.Count() == 0 - || this.SequencePoints == null - || this.SequencePoints.Count == 0 + || this.BranchPoints.Count() == 0 + || this.SequencePoints == null + || this.SequencePoints.Count == 0 ) { return null; @@ -198,31 +199,9 @@ namespace ICSharpCode.CodeCoverage Debug.Assert ( !Object.ReferenceEquals( null, finalSeqPoint) ); if (Object.ReferenceEquals(null, finalSeqPoint)) { return null; } - // Create&populate excludeOffsetList (BranchPoint offset-filter) - bool nextMatch = false; - CodeCoverageSequencePoint previousSeqPoint = startSeqPoint; - List> excludeOffsetList = new List>(); - foreach (CodeCoverageSequencePoint currentSeqPoint in this.SequencePoints) { - - // ignore CCRewrite(n) contracts - if (currentSeqPoint.Offset < startSeqPoint.Offset) - continue; - if (currentSeqPoint.Offset > finalSeqPoint.Offset) - break; - - if (nextMatch) { - nextMatch = false; - excludeOffsetList.Add(new Tuple ( previousSeqPoint.Offset , currentSeqPoint.Offset )); - } - // Generated "in" code for IEnumerables contains hidden "try/catch/finally" branches that - // one do not want or cannot cover by test-case because is handled earlier at same method. - // ie: NullReferenceException in foreach loop is pre-handled at method entry, ie. by Contract.Require(items!=null) - if (currentSeqPoint.Content == "in") { - // Content is equal to "in" keyword - nextMatch = true; - } - previousSeqPoint = currentSeqPoint; - } + IEnumerator SPEnumerator = this.SequencePoints.GetEnumerator(); + CodeCoverageSequencePoint branchSeqPoint = startSeqPoint; + int nextOffset = branchSeqPoint.Offset; // Merge BranchPoints on same offset // Exclude BranchPoints outside of method boundary {...} => exclude CCRewrite(n) Contracts @@ -236,55 +215,55 @@ namespace ICSharpCode.CodeCoverage if (bp.Offset > finalSeqPoint.Offset) break; - // Apply excludeOffset filter - if (excludeOffsetList.Count != 0) { - nextMatch = true; - foreach (var offsetRange in excludeOffsetList) { - if (offsetRange.Item1 < bp.Offset && bp.Offset < offsetRange.Item2) { - // exclude range match - nextMatch = false; break; - } - } if (!nextMatch) { continue; } - } - // merge BranchPoint's with same offset - if ( branchDictionary.ContainsKey( bp.Offset ) ) { - // Update BranchPoint coverage at offset - branchOffset update = branchDictionary[bp.Offset]; - update.Visit += bp.VisitCount!=0?1:0; - update.Count += 1; - } else { + if ( !branchDictionary.ContainsKey( bp.Offset ) ) { // Insert BranchPoint coverage at offset branchOffset insert = new branchOffset(bp.Offset); insert.Visit = bp.VisitCount!=0?1:0; insert.Count = 1; + + // attach Sequence to Branch-Offset + while ( nextOffset < insert.Offset ) { + branchSeqPoint = SPEnumerator.Current; + if ( SPEnumerator.MoveNext() ) { + nextOffset = SPEnumerator.Current.Offset; + } else { + nextOffset = int.MaxValue; + } + } + insert.SeqPoint = branchSeqPoint; branchDictionary[insert.Offset] = insert; + + } else { + // Update BranchPoint coverage at offset + branchOffset update = branchDictionary[bp.Offset]; + update.Visit += bp.VisitCount!=0?1:0; + update.Count += 1; } } + // Calculate Method Branch coverage int totalBranchVisit = 0; int totalBranchCount = 0; - - // Branch coverage will display only if sequence coverage is 100%, so ... - // Ignore branch-offset if is not visited at all because ... : - // if SequencePoint is covered and branch-offset within that SequencePoint not visited (uncovered), - // then that branch-offset does not really exists in SOURCE code we try to cover - CodeCoverageSequencePoint sp_target = null; foreach ( branchOffset uniqueBranch in branchDictionary.Values ) { - if ( uniqueBranch.Visit != 0 ) { - totalBranchVisit += uniqueBranch.Visit; - totalBranchCount += uniqueBranch.Count; - // not full branch coverage? - if ( uniqueBranch.Visit != uniqueBranch.Count ) { - // update parent SequencePoint.BranchCoverage to false (== partial branch coverage) - sp_target = null; - foreach ( CodeCoverageSequencePoint sp_next in this.SequencePoints ) { - if ( uniqueBranch.Offset < sp_next.Offset && sp_target != null ) { - sp_target.BranchCoverage = false; - break; - } - sp_target = sp_next; + // Generated "in" code for IEnumerables contains hidden "try/catch/finally" branches that + // one do not want or cannot cover by test-case because is handled earlier at same method. + // ie: NullReferenceException in foreach loop is pre-handled at method entry, ie. by Contract.Require(items!=null) + if (uniqueBranch.SeqPoint.Content != "in") { + + // Branch coverage will display only if sequence coverage is 100%, so ... + // Ignore branch-offset if is not visited at all because ... : + // if SequencePoint is covered and branch-offset within that SequencePoint not visited (uncovered), + // then that branch-offset does not really exists in SOURCE code we try to cover + if ( uniqueBranch.Visit != 0 ) { + totalBranchVisit += uniqueBranch.Visit; + totalBranchCount += uniqueBranch.Count; + + // not full branch coverage? + if ( uniqueBranch.Visit != uniqueBranch.Count ) { + // update attached SequencePoint.BranchCoverage to false (== partial branch coverage) + uniqueBranch.SeqPoint.BranchCoverage = false; } } }