Browse Source

Refactoring

pull/67/head
Dragan 12 years ago
parent
commit
8a1aec0016
  1. 144
      src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageMethodElement.cs

144
src/AddIns/Analysis/CodeCoverage/Project/Src/CodeCoverageMethodElement.cs

@ -107,7 +107,7 @@ namespace ICSharpCode.CodeCoverage
} }
List<CodeCoverageBranchPoint> GetBranchPoints() { List<CodeCoverageBranchPoint> GetBranchPoints() {
// get all SequencePoints // get all BranchPoints
List<CodeCoverageBranchPoint> bps = new List<CodeCoverageBranchPoint>(); List<CodeCoverageBranchPoint> bps = new List<CodeCoverageBranchPoint>();
var xBPoints = this.element var xBPoints = this.element
.Elements("BranchPoints") .Elements("BranchPoints")
@ -130,108 +130,94 @@ namespace ICSharpCode.CodeCoverage
return null; return null;
} }
// start & final method sequence points line and offset // Find method-body first SequencePoint "{"
int methodStartLine = 0; // and then first next sequencePoint (and offset of that instruction in body)
int methodStartOffset = 0; // This will be used to skip CCRewrite(n) BranchPoint's (Requires)
CodeCoverageSequencePoint startSeqPoint = null;
int methodFinalLine = 0;
int methodFinalOffset = 0;
// find start & final method sequence points and offsets
bool nextMatch = false;
int startLine = 0;
int finalLine = 0;
int startChar = 0;
int finalChar = 0;
// Find method body SequencePoint ({)
// and then first next sequencePoint (and offset of first instruction in body)
// This will skip Contract.Require SequencePoints
// and help to filter-out Contract.Require BranchPoint's
foreach (CodeCoverageSequencePoint sp in this.SequencePoints) { foreach (CodeCoverageSequencePoint sp in this.SequencePoints) {
startLine = sp.Line; if ( sp.Line == sp.EndLine && ((sp.EndColumn-sp.Column) == 1) ) {
finalLine = sp.EndLine; startSeqPoint = sp;
startChar = sp.Column;
finalChar = sp.EndColumn;
if ( nextMatch ) {
methodStartLine = startLine;
methodStartOffset = sp.Offset;
break; break;
} }
if ( startLine==finalLine && (finalChar-startChar)==1 ) {
nextMatch = true;
}
} }
Debug.Assert (!Object.ReferenceEquals(null, startSeqPoint));
if (Object.ReferenceEquals(null, startSeqPoint)) { return null; }
// find method body last SequencePoint and final offset (}) // Find method-body last SequencePoint "}" and offset
// This will skip Contract.Ensures SequencePoints // This will be used to skip CCRewrite(n) BranchPoint's (Ensures)
// and help to filter-out Contract.Ensures BranchPoint's CodeCoverageSequencePoint finalSeqPoint = null;
foreach (CodeCoverageSequencePoint sp in Enumerable.Reverse(this.SequencePoints)) { foreach (CodeCoverageSequencePoint sp in Enumerable.Reverse(this.SequencePoints)) {
startLine = sp.Line; if ( sp.Line == sp.EndLine && ((sp.EndColumn-sp.Column) == 1) ) {
finalLine = sp.EndLine; finalSeqPoint = sp;
startChar = sp.Column;
finalChar = sp.EndColumn;
if ( startLine==finalLine && (finalChar-startChar)==1 ) {
methodFinalLine = finalLine;
methodFinalOffset = sp.Offset;
break; break;
} }
} }
Debug.Assert ( !Object.ReferenceEquals( null, finalSeqPoint) );
if (Object.ReferenceEquals(null, finalSeqPoint)) { return null; }
// Find compiler inserted code (=> inserted hidden branches) // Find compiler inserted code (=> inserted hidden branches)
// SequencePoints are ordered by offset and that order exposes reverse ordered lines // SequencePoints are ordered by offset and that order exposes reverse ordered lines
// ie: In code: foreach ( var item in items ) // ie: foreach ( var item in (IEnumerable)items ) code for "in" keyword is generated "out-of-sequence",
// Keyword "in" code is generated after loop with lower line number than previous line (reversed line order). // with lower line number than previous line (reversed line order).
// That "in" code contains hidden branches that we // Generated "in" code for IEnumerables contains hidden "try/catch/finally" branches that
// do not want or cannot cover by test-case because is handled by earlier line // we do not want or cannot cover by test-case because is handled in earlier code (SequencePoint)
// ie: Possible NullReferenceException in foreach loop is pre-handled at method entry, ie. by Contract.Require(items!=null) // ie: NullReferenceException in foreach loop is pre-handled at method entry, ie. by Contract.Require(items!=null)
nextMatch = false; bool nextMatch = false;
int lastOffset = 0; CodeCoverageSequencePoint previousSeqPoint = startSeqPoint;
int lastLine = methodStartLine; List<Tuple<int,int>> excludeOffsetList = new List<Tuple<int, int>>();
List<Tuple<int,int>> excludeList = new List<Tuple<int, int>>(); foreach (CodeCoverageSequencePoint currentSeqPoint in this.SequencePoints) {
foreach (CodeCoverageSequencePoint sp in this.SequencePoints) {
if ( (sp.Line < methodStartLine) || methodFinalLine < sp.Line ) { continue ; } // ignore CCRewrite(n) contracts
if (currentSeqPoint.Offset < startSeqPoint.Offset)
continue;
if (currentSeqPoint.Offset > finalSeqPoint.Offset)
break;
if (nextMatch && (sp.Line > lastLine)) { if (nextMatch) {
nextMatch = false; nextMatch = false;
excludeList.Add(new Tuple<int, int> ( lastOffset , sp.Offset )); excludeOffsetList.Add(new Tuple<int, int> ( previousSeqPoint.Offset , currentSeqPoint.Offset ));
} }
// reversed line number? // current SP has lower line number than stored SP and is made of two characters?
if (!nextMatch && (sp.Line < lastLine)) { // Very likely to be only "in" keyword (as observed in coverage.xml)
if (currentSeqPoint.Line < previousSeqPoint.Line
&& currentSeqPoint.Line == currentSeqPoint.EndLine
&& (currentSeqPoint.EndColumn - currentSeqPoint.Column) == 2 ) {
nextMatch = true; nextMatch = true;
lastOffset = sp.Offset;
} }
lastLine = sp.Line; previousSeqPoint = currentSeqPoint;
} }
// Collect branch offsets within method boundary { } (exclude Contracts) // Collect & offset-merge BranchPoints within method boundary { }
// and filter with excludeList // => exclude CCRewrite(n) Contracts and filter with excludeOffsetList
Dictionary<int, branchOffset> branchDictionary = new Dictionary<int, branchOffset>(); Dictionary<int, branchOffset> branchDictionary = new Dictionary<int, branchOffset>();
foreach (CodeCoverageBranchPoint bp in this.BranchPoints) { foreach (CodeCoverageBranchPoint bp in this.BranchPoints) {
if ( methodStartOffset <= bp.Offset && bp.Offset <= methodFinalOffset ) { // exclude CCRewrite(n) contracts
if (bp.Offset < startSeqPoint.Offset)
continue;
if (bp.Offset > finalSeqPoint.Offset)
break;
// Apply exclude BranchPoint filter // Apply excludeOffset filter
nextMatch = true; nextMatch = true;
foreach (var range in excludeList) { foreach (var offsetRange in excludeOffsetList) {
if (range.Item1 < bp.Offset && bp.Offset < range.Item2) { if (offsetRange.Item1 < bp.Offset && bp.Offset < offsetRange.Item2) {
// exclude range match // exclude range match
nextMatch = false; break; nextMatch = false; break;
}
} if (!nextMatch) { continue; }
// update/insert branch offset coverage data
if ( branchDictionary.ContainsKey( bp.Offset ) ) {
branchOffset update = branchDictionary[bp.Offset];
update.Visit += bp.VisitCount!=0?1:0;
update.Count += 1;
} else {
// Insert first branch at offset
branchOffset insert = new branchOffset(bp.Offset);
insert.Visit = bp.VisitCount!=0?1:0;
insert.Count = 1;
branchDictionary[insert.Offset] = insert;
} }
} if (!nextMatch) { continue; }
// update/insert branch offset coverage data
if ( branchDictionary.ContainsKey( bp.Offset ) ) {
branchOffset update = branchDictionary[bp.Offset];
update.Visit += bp.VisitCount!=0?1:0;
update.Count += 1;
} else {
// Insert first branch at offset
branchOffset insert = new branchOffset(bp.Offset);
insert.Visit = bp.VisitCount!=0?1:0;
insert.Count = 1;
branchDictionary[insert.Offset] = insert;
} }
} }

Loading…
Cancel
Save