Skip to content
This repository was archived by the owner on Oct 16, 2020. It is now read-only.

Commit ff7b87e

Browse files
committed
Merge pull request #495 from ddur/CodeCoverageFilter
Code coverage filter
2 parents 241d8df + 44b7357 commit ff7b87e

1 file changed

Lines changed: 71 additions & 50 deletions

File tree

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

Lines changed: 71 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public CodeCoverageMethodElement(XElement element, CodeCoverageResults results)
5858

5959
public string FileID { get; private set; }
6060
public string FileName { get; private set; }
61+
public string FileNameExt { get; private set; }
6162
public bool IsVisited { get; private set; }
6263
public int CyclomaticComplexity { get; private set; }
6364
public decimal SequenceCoverage { get; private set; }
@@ -86,9 +87,14 @@ void Init()
8687

8788
this.FileID = GetFileRef();
8889
this.FileName = String.Empty;
90+
this.FileNameExt = String.Empty;
8991
if (!String.IsNullOrEmpty(this.FileID)) {
9092
if (results != null) {
9193
this.FileName = results.GetFileName(this.FileID);
94+
try {
95+
this.FileNameExt = Path.GetExtension(this.FileName).ToLowerInvariant();
96+
}
97+
catch {}
9298
if (cacheFileName != this.FileName) {
9399
cacheFileName = this.FileName;
94100
cacheDocument = GetSource (cacheFileName);
@@ -220,14 +226,19 @@ void GetSequencePointContent(CodeCoverageSequencePoint sp)
220226
// -> this method SP with lowest Line/Column
221227
void getBodyStartSP() {
222228
if (this.SequencePoints.Count != 0) {
223-
foreach (CodeCoverageSequencePoint sp in this.SequencePoints) {
224-
if (sp.FileID != this.FileID) continue;
225-
if (this.BodyStartSP == null || (sp.Line < this.BodyStartSP.Line) ||
226-
(sp.Line == this.BodyStartSP.Line && sp.Column < this.BodyStartSP.Column)
227-
) {
228-
this.BodyStartSP = sp;
229+
if (this.FileNameExt == ".cs") {
230+
foreach (CodeCoverageSequencePoint sp in this.SequencePoints) {
231+
if (sp.FileID != this.FileID) continue;
232+
if (this.BodyStartSP == null || (sp.Line < this.BodyStartSP.Line) ||
233+
(sp.Line == this.BodyStartSP.Line && sp.Column < this.BodyStartSP.Column)
234+
) {
235+
this.BodyStartSP = sp;
236+
}
229237
}
230238
}
239+
else {
240+
this.BodyStartSP = this.SequencePoints.First();
241+
}
231242
}
232243
}
233244

@@ -236,29 +247,34 @@ void getBodyStartSP() {
236247
// and lowest Offset (when duplicated bw ccrewrite)
237248
void getBodyFinalSP() {
238249
if (this.SequencePoints.Count != 0) {
239-
for (int i = this.SequencePoints.Count-1; i > 0; i--) {
240-
var sp = this.SequencePoints[i];
241-
if (sp.FileID != this.FileID) continue;
242-
if (sp.Content != "}") continue;
243-
if (this.BodyFinalSP == null || (sp.Line > this.BodyFinalSP.Line) ||
244-
(sp.Line == this.BodyFinalSP.Line && sp.Column >= this.BodyFinalSP.Column)
245-
) {
246-
// ccrewrite ContractClass/ContractClassFor
247-
// adds duplicate method end-sequence-point "}"
248-
//
249-
// Take duplicate BodyFinalSP with lower Offset
250-
// Because IL.Offset of second duplicate
251-
// will extend branch coverage of this method
252-
// by coverage of ContractClassFor inserted SequencePoint!
253-
if (this.BodyFinalSP != null &&
254-
sp.Line == this.BodyFinalSP.Line &&
255-
sp.Column == this.BodyFinalSP.Column &&
256-
sp.Offset < this.BodyFinalSP.Offset) {
257-
this.SequencePoints.Remove(this.BodyFinalSP); // remove duplicate
250+
if (this.FileNameExt == ".cs") {
251+
for (int i = this.SequencePoints.Count-1; i > 0; i--) {
252+
var sp = this.SequencePoints[i];
253+
if (sp.FileID != this.FileID) continue;
254+
if (sp.Content != "}") continue;
255+
if (this.BodyFinalSP == null || (sp.Line > this.BodyFinalSP.Line) ||
256+
(sp.Line == this.BodyFinalSP.Line && sp.Column >= this.BodyFinalSP.Column)
257+
) {
258+
// ccrewrite ContractClass/ContractClassFor
259+
// adds duplicate method end-sequence-point "}"
260+
//
261+
// Take duplicate BodyFinalSP with lower Offset
262+
// Because IL.Offset of second duplicate
263+
// will extend branch coverage of this method
264+
// by coverage of ContractClassFor inserted SequencePoint!
265+
if (this.BodyFinalSP != null &&
266+
sp.Line == this.BodyFinalSP.Line &&
267+
sp.Column == this.BodyFinalSP.Column &&
268+
sp.Offset < this.BodyFinalSP.Offset) {
269+
this.SequencePoints.Remove(this.BodyFinalSP); // remove duplicate
270+
}
271+
this.BodyFinalSP = sp;
258272
}
259-
this.BodyFinalSP = sp;
260273
}
261274
}
275+
else {
276+
this.BodyFinalSP = this.SequencePoints.Last();
277+
}
262278
}
263279
}
264280

@@ -273,6 +289,9 @@ int GetSequencePointsCount() {
273289
return 0;
274290
}
275291

292+
const string @assert = "Assert";
293+
const string @contract = "Contract";
294+
276295
void GetBranchRatio () {
277296

278297
this.BranchCoverageRatio = null;
@@ -295,31 +314,33 @@ void GetBranchRatio () {
295314
// SequencePoint is visited and belongs to this method?
296315
if (sp.VisitCount != 0 && sp.FileID == this.FileID) {
297316

298-
// Don't want branch coverage of ccrewrite(n)
299-
// SequencePoint's with offset before and after method body
300-
if (sp.Offset < BodyStartSP.Offset ||
301-
sp.Offset > BodyFinalSP.Offset) {
302-
sp.BranchCoverage = true;
303-
continue; // skip
304-
}
317+
if (this.FileNameExt == ".cs") {
318+
// Only for C#
305319

306-
// 1) Generated "in" code for IEnumerables contains hidden "try/catch/finally" branches that
307-
// one do not want or cannot cover by test-case because is handled earlier at same method.
308-
// ie: NullReferenceException in foreach loop is pre-handled at method entry, ie. by Contract.Require(items!=null)
309-
// 2) Branches within sequence points "{" and "}" are not source branches but compiler generated branches
310-
// ie: static methods start sequence point "{" contains compiler generated branches
311-
// 3) Exclude Contract class (EnsuresOnThrow/Assert/Assume is inside method body)
312-
// 4) Exclude NUnit Assert(.Throws) class
313-
const string assert = "Assert";
314-
const string contract = "Contract";
315-
if (sp.Content == "in" || sp.Content == "{" || sp.Content == "}" ||
316-
sp.Content.StartsWith(assert + ".", StringComparison.Ordinal) ||
317-
sp.Content.StartsWith(assert + " ", StringComparison.Ordinal) ||
318-
sp.Content.StartsWith(contract + ".", StringComparison.Ordinal) ||
319-
sp.Content.StartsWith(contract + " ", StringComparison.Ordinal)
320-
) {
321-
sp.BranchCoverage = true;
322-
continue; // skip
320+
// Don't want branch coverage of ccrewrite(n)
321+
// SequencePoint(s) with offset before and after method body
322+
if (sp.Offset < BodyStartSP.Offset ||
323+
sp.Offset > BodyFinalSP.Offset) {
324+
sp.BranchCoverage = true;
325+
continue; // skip
326+
}
327+
328+
// 1) Generated "in" code for IEnumerables contains hidden "try/catch/finally" branches that
329+
// one do not want or cannot cover by test-case because is handled earlier at same method.
330+
// ie: NullReferenceException in foreach loop is pre-handled at method entry, ie. by Contract.Require(items!=null)
331+
// 2) Branches within sequence points "{" and "}" are not source branches but compiler generated branches
332+
// ie: static methods start sequence point "{" contains compiler generated branches
333+
// 3) Exclude Contract class (EnsuresOnThrow/Assert/Assume is inside method body)
334+
// 4) Exclude NUnit Assert(.Throws) class
335+
if (sp.Content == "in" || sp.Content == "{" || sp.Content == "}" ||
336+
sp.Content.StartsWith(@assert + ".", StringComparison.Ordinal) ||
337+
sp.Content.StartsWith(@assert + " ", StringComparison.Ordinal) ||
338+
sp.Content.StartsWith(@contract + ".", StringComparison.Ordinal) ||
339+
sp.Content.StartsWith(@contract + " ", StringComparison.Ordinal)
340+
) {
341+
sp.BranchCoverage = true;
342+
continue; // skip
343+
}
323344
}
324345

325346
totalBranchCount += sp.BranchExitsCount;

0 commit comments

Comments
 (0)