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

Commit 51ca3d8

Browse files
author
Dragan
committed
CodeCoverage: FileID/Document SequencePoint Attrs
Fixing [CodeContractClass/For] using SequencePoint fileid/url XML attributes
1 parent f6add54 commit 51ca3d8

1 file changed

Lines changed: 77 additions & 47 deletions

File tree

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

Lines changed: 77 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ public CodeCoverageMethodElement(XElement element, CodeCoverageResults parent)
4545
private static string cacheFileName = String.Empty;
4646
private static CodeCoverageStringTextSource cacheDocument = null;
4747

48+
private static string cache2FileName = String.Empty;
49+
private static CodeCoverageStringTextSource cache2Document = null;
50+
4851
public string FileID { get; private set; }
4952
public string FileName { get; private set; }
5053
public bool IsVisited { get; private set; }
@@ -56,9 +59,9 @@ public CodeCoverageMethodElement(XElement element, CodeCoverageResults parent)
5659
public bool IsConstructor { get; private set; }
5760
public bool IsStatic { get; private set; }
5861
public List<CodeCoverageSequencePoint> SequencePoints { get; private set; }
62+
public List<CodeCoverageBranchPoint> BranchPoints { get; private set; }
5963
public CodeCoverageSequencePoint BodyStartSP { get; private set; }
6064
public CodeCoverageSequencePoint BodyFinalSP { get; private set; }
61-
public List<CodeCoverageBranchPoint> BranchPoints { get; private set; }
6265

6366
public bool IsGetter { get; private set; }
6467
public bool IsSetter { get; private set; }
@@ -79,20 +82,9 @@ void Init()
7982
if (!String.IsNullOrEmpty(this.FileID)) {
8083
if (parent != null) {
8184
this.FileName = parent.GetFileName(this.FileID);
82-
if ( File.Exists(this.FileName) ) {
83-
if (cacheFileName != this.FileName) {
84-
cacheFileName = this.FileName;
85-
cacheDocument = null;
86-
try {
87-
using (Stream stream = new FileStream(this.FileName, FileMode.Open, FileAccess.Read)) {
88-
try {
89-
stream.Position = 0;
90-
string textSource = ICSharpCode.AvalonEdit.Utils.FileReader.ReadFileContent(stream, Encoding.Default);
91-
cacheDocument = new CodeCoverageStringTextSource(textSource);
92-
} catch {}
93-
}
94-
} catch {}
95-
}
85+
if (cacheFileName != this.FileName) {
86+
cacheFileName = this.FileName;
87+
cacheDocument = GetSource (cacheFileName);
9688
}
9789
}
9890
}
@@ -108,8 +100,7 @@ void Init()
108100
this.GetSequencePointsContent();
109101
this.getBodyStartSP(); // before OrderBy Line/Col
110102
this.getBodyFinalSP(); // before orderBy Line/Col
111-
this.FilterSequencePoints(); // before orderBy Line/Col
112-
this.GetBranchPoints();
103+
//this.FilterSequencePoints(); // before orderBy Line/Col
113104
this.GetBranchRatio();
114105
this.GetBranchCoverage();
115106

@@ -122,16 +113,37 @@ void Init()
122113
}
123114
}
124115

116+
private static var cacheGetSource_LastFileName = (string)null;
117+
private static var cacheGetSource_LastSource = (CodeCoverageStringTextSource)null;
118+
119+
static CodeCoverageStringTextSource GetSource(string filename) {
120+
121+
if (filename == cacheGetSource_LastFileName) return cacheGetSource_LastSource;
122+
123+
var retSource = (CodeCoverageStringTextSource)null;
124+
try {
125+
using (Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read)) {
126+
try {
127+
stream.Position = 0;
128+
string textSource = ICSharpCode.AvalonEdit.Utils.FileReader.ReadFileContent(stream, Encoding.Default);
129+
retSource = new CodeCoverageStringTextSource(textSource);
130+
} catch (Exception e) { Debug.Fail(e.Message); }
131+
}
132+
} catch (Exception e) { Debug.Fail(e.Message); }
133+
134+
cacheGetSource_LastFileName = filename;
135+
cacheGetSource_LastSource = retSource;
136+
return retSource;
137+
}
138+
125139
void GetSequencePoints() {
126140

127141
var xSPoints = this.element
128142
.Elements("SequencePoints")
129143
.Elements("SequencePoint");
130144

131145
foreach (XElement xSPoint in xSPoints) {
132-
CodeCoverageSequencePoint sp = new CodeCoverageSequencePoint();
133-
sp.FileID = this.FileID;
134-
sp.Document = this.FileName;
146+
var sp = new CodeCoverageSequencePoint();
135147
sp.Line = (int)GetDecimalAttributeValue(xSPoint.Attribute("sl"));
136148
sp.EndLine = (int)GetDecimalAttributeValue(xSPoint.Attribute("el"));
137149
sp.Column = (int)GetDecimalAttributeValue(xSPoint.Attribute("sc"));
@@ -140,6 +152,22 @@ void GetSequencePoints() {
140152
sp.Offset = (int)GetDecimalAttributeValue(xSPoint.Attribute("offset"));
141153
sp.BranchExitsCount = (int)GetDecimalAttributeValue(xSPoint.Attribute("bec"));
142154
sp.BranchExitsVisit = (int)GetDecimalAttributeValue(xSPoint.Attribute("bev"));
155+
sp.FileID = xSPoint.Attribute("fileid").Value?? "0";
156+
if (sp.FileID == "0") {
157+
// SequencePoint from not covered (not runnable) file
158+
// ie: interface with CodeContractClass/CodeContractClassFor
159+
sp.Document = xSPoint.Attribute("fileid").Value?? "";
160+
}
161+
else if (sp.FileID == this.FileID) {
162+
// This method SequencePoint (from this.FileName)
163+
sp.Document = this.FileName;
164+
}
165+
else {
166+
// SequencePoint from another method/file
167+
// ie: ccrewriten CodeContractClass/CodeContractClassFor
168+
// [or dependency-injected or fody-weaved???]
169+
sp.Document = parent.GetFileName(sp.FileID);
170+
}
143171
sp.BranchCoverage = (sp.BranchExitsCount == sp.BranchExitsVisit);
144172
sp.Content = String.Empty;
145173
sp.Length = 0;
@@ -150,27 +178,36 @@ void GetSequencePoints() {
150178

151179
void GetSequencePointsContent()
152180
{
153-
if (cacheFileName == this.FileName && cacheDocument != null) {
154-
foreach (var sp in this.SequencePoints) {
155-
GetSequencePointContent(sp);
156-
}
181+
foreach (var sp in this.SequencePoints) {
182+
GetSequencePointContent(sp);
157183
}
158184
}
159185

160186
void GetSequencePointContent(CodeCoverageSequencePoint sp)
161187
{
162-
// ccrewrite will cause lots of invalid calls to GetText()!
163-
if (cacheFileName == sp.Document && cacheDocument != null) {
164-
sp.Content = cacheDocument.GetText(sp); // never returns null
165-
if (sp.Content != String.Empty) {
166-
if (sp.Line != sp.EndLine) {
167-
// merge lines to single line
168-
sp.Content = Regex.Replace(sp.Content, @"\s+", " ");
169-
}
170-
// SequencePoint.Length counts all but whitespace
171-
sp.Length = Regex.Replace(sp.Content, @"\s", "").Length;
188+
if (cacheFileName == sp.Document) {
189+
// check primary cache (this.Filename)
190+
sp.Content = cacheDocument == null? "" : cacheDocument.GetText(sp);
191+
}
192+
else {
193+
// check & update secondary cache
194+
if (cache2FileName == sp.Document) {
195+
sp.Content = cache2Document == null? "" : cache2Document.GetText(sp);
196+
}
197+
else {
198+
cache2FileName = sp.Document;
199+
cache2Document = GetSource (cache2FileName);
200+
sp.Content = cache2Document == null? "" : cache2Document.GetText(sp);
172201
}
173202
}
203+
if (sp.Content != String.Empty) {
204+
if (sp.Line != sp.EndLine) {
205+
// merge multiple lines to single line
206+
sp.Content = Regex.Replace(sp.Content, @"\s+", " ");
207+
}
208+
// SequencePoint.Length counts all but whitespace
209+
sp.Length = Regex.Replace(sp.Content, @"\s", "").Length;
210+
}
174211
}
175212

176213
// Find method-body start SequencePoint "{" (sp.Content required)
@@ -289,32 +326,25 @@ void GetBranchPoints() {
289326

290327
void GetBranchRatio () {
291328

292-
// goal: Get branch ratio, merge branch-exits and exclude (rewriten) Code Contracts branches
293329
this.BranchCoverageRatio = null;
294330

295-
if ( this.BranchPoints == null
296-
|| this.BranchPoints.Count == 0
297-
|| this.SequencePoints == null
298-
|| this.SequencePoints.Count == 0
299-
)
300-
{
301-
return;
302-
}
331+
Debug.Assert (this.SequencePoints != null);
332+
if ( this.SequencePoints.Count == 0 ) return;
303333

304334
// This sequence point offset is used to skip CCRewrite(n) BranchPoint's (Requires)
305335
// and '{' branches at static methods
306-
if (this.BodyStartSP == null) { return; } // empty body
336+
if (this.BodyStartSP == null) return; // empty body
307337

308338
// This sequence point offset is used to skip CCRewrite(n) BranchPoint's (Ensures)
309-
if (this.BodyFinalSP == null) { return; } // empty body
339+
if (this.BodyFinalSP == null) return; // empty body
310340

311341
// Calculate Method Branch coverage
312342
int totalBranchVisit = 0;
313343
int totalBranchCount = 0;
314344
foreach (var sp in this.SequencePoints) {
315345

316-
// SequencePoint is visited?
317-
if (sp.VisitCount != 0) {
346+
// SequencePoint is visited and belongs to this method?
347+
if (sp.VisitCount != 0 && sp.Document == this.FileName) {
318348

319349
// Don't want branch coverage of ccrewrite(n)
320350
// SequencePoint's with offset before and after method body

0 commit comments

Comments
 (0)