Skip to content

Commit

Permalink
#685 Extended "raw mode" for dotCover format (settings:rawMode=true) …
Browse files Browse the repository at this point in the history
…to disable that coverage data of nested or compiler generated classes is included in the parent class.
  • Loading branch information
danielpalme committed Aug 18, 2024
1 parent 0dc5e83 commit 4444f14
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 39 deletions.
5 changes: 5 additions & 0 deletions src/Readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ For further details take a look at LICENSE.txt.

CHANGELOG

5.3.9.0

* New: #685 Extended "raw mode" for dotCover format (settings:rawMode=true) to disable that coverage data of nested or compiler generated
classes is included in the parent class.

5.3.8.0

* Fix: #681 Updated System.Text.Json to address CVE-2024-30105 (contributed by @304NotModified)
Expand Down
5 changes: 4 additions & 1 deletion src/ReportGenerator.Core/Parser/CoverageReportParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,10 @@ private IEnumerable<ParserResult> ParseXmlFile(string filePath)
new DotCoverReportPreprocessor().Execute(item);

Logger.DebugFormat(Resources.InitiatingParser, "dotCover");
yield return new DotCoverParser(this.assemblyFilter, this.classFilter, this.fileFilter).Parse(item);
yield return new DotCoverParser(this.assemblyFilter, this.classFilter, this.fileFilter)
{
RawMode = !this.rawModeProhibited && this.reportContext?.Settings.RawMode == true
}.Parse(item);
}

yield break;
Expand Down
97 changes: 59 additions & 38 deletions src/ReportGenerator.Core/Parser/DotCoverParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,45 +96,63 @@ private Assembly ProcessAssembly(XElement[] modules, XElement[] files, string as
var assemblyElement = modules
.Where(m => m.Attribute("Name").Value.Equals(assemblyName));

var classNames = assemblyElement
.Elements("Namespace")
.Elements("Type")
.Concat(assemblyElement.Elements("Type"))
var classes = assemblyElement
.Descendants("Type")
.Where(c => this.RawMode || c.Parent.Name != "Type")
.Where(c => !Regex.IsMatch(c.Attribute("Name").Value, "<.*>.+__", RegexOptions.Compiled))
.Select(c => c.Parent.Attribute("Name").Value + "." + c.Attribute("Name").Value)
.Distinct()
.Where(c => this.ClassFilter.IsElementIncludedInReport(c))
.OrderBy(name => name)
.ToArray();

var assembly = new Assembly(assemblyName);

Parallel.ForEach(classNames, className => this.ProcessClass(modules, files, assembly, className));
Parallel.ForEach(classes, clazz => this.ProcessClass(files, assembly, clazz));

return assembly;
}

/// <summary>
/// Processes the given class.
/// </summary>
/// <param name="modules">The modules.</param>
/// <param name="files">The files.</param>
/// <param name="assembly">The assembly.</param>
/// <param name="className">Name of the class.</param>
private void ProcessClass(XElement[] modules, XElement[] files, Assembly assembly, string className)
/// <param name="classElement">The class element.</param>
private void ProcessClass(XElement[] files, Assembly assembly, XElement classElement)
{
var assemblyElement = modules
.Where(m => m.Attribute("Name").Value.Equals(assembly.Name));

var fileIdsOfClass = assemblyElement
.Elements("Namespace")
.Elements("Type")
.Concat(assemblyElement.Elements("Type"))
.Where(c => (c.Parent.Attribute("Name").Value + "." + c.Attribute("Name").Value).Equals(className))
.Descendants("Statement")
.Select(c => c.Attribute("FileIndex").Value)
.Distinct()
.ToArray();
string className = classElement.Attribute("Name").Value;

XElement parent = classElement.Parent;

while (parent.Name == "Type")
{
className = parent.Attribute("Name").Value + "." + className;
parent = parent.Parent;
}

className = parent.Attribute("Name").Value + "." + className;

if (!this.ClassFilter.IsElementIncludedInReport(className))
{
return;
}

string[] fileIdsOfClass;

if (this.RawMode)
{
fileIdsOfClass = classElement
.Elements("Method")
.Elements("Statement")
.Select(c => c.Attribute("FileIndex").Value)
.Distinct()
.ToArray();
}
else
{
fileIdsOfClass = classElement
.Descendants("Statement")
.Select(c => c.Attribute("FileIndex").Value)
.Distinct()
.ToArray();
}

var filteredFilesOfClass = fileIdsOfClass
.Select(fileId =>
Expand All @@ -153,7 +171,7 @@ private void ProcessClass(XElement[] modules, XElement[] files, Assembly assembl

foreach (var file in filteredFilesOfClass)
{
@class.AddFile(ProcessFile(modules, file.FileId, @class, file.FilePath));
@class.AddFile(this.ProcessFile(file.FileId, classElement, file.FilePath));
}

assembly.AddClass(@class);
Expand All @@ -163,23 +181,26 @@ private void ProcessClass(XElement[] modules, XElement[] files, Assembly assembl
/// <summary>
/// Processes the file.
/// </summary>
/// <param name="modules">The modules.</param>
/// <param name="fileId">The file id.</param>
/// <param name="class">The class.</param>
/// <param name="classElement">The class element.</param>
/// <param name="filePath">The file path.</param>
/// <returns>The <see cref="CodeFile"/>.</returns>
private static CodeFile ProcessFile(XElement[] modules, string fileId, Class @class, string filePath)
private CodeFile ProcessFile(string fileId, XElement classElement, string filePath)
{
var assemblyElement = modules
.Where(m => m.Attribute("Name").Value.Equals(@class.Assembly.Name));

var methodsOfFile = assemblyElement
.Elements("Namespace")
.Elements("Type")
.Concat(assemblyElement.Elements("Type"))
.Where(c => (c.Parent.Attribute("Name").Value + "." + c.Attribute("Name").Value).Equals(@class.Name))
.Descendants("Method")
.ToArray();
XElement[] methodsOfFile;

if (this.RawMode)
{
methodsOfFile = classElement
.Elements("Method")
.ToArray();
}
else
{
methodsOfFile = classElement
.Descendants("Method")
.ToArray();
}

var statements = methodsOfFile
.Elements("Statement")
Expand Down

0 comments on commit 4444f14

Please sign in to comment.