Browse Source

Add progress reporting to PortablePdbWriter

This commit adds a new parameter to PortablePdbWriter.WritePdb that
allows the caller to provide an implementation of IProgress to receive
status updates on the pdb generation process.  Currently, the progress
reports include the number of files generated so far and the total
number of files.
pull/2802/head
Andrew Crawley (US - DIAGNOSTICS) 3 years ago committed by Siegfried Pammer
parent
commit
a494bfadbe
  1. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 58
      ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs
  3. 4
      ICSharpCode.Decompiler.Tests/TestCases/PdbGen/CustomPdbId.xml
  4. 44
      ICSharpCode.Decompiler.Tests/TestCases/PdbGen/ProgressReporting.xml
  5. 31
      ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -312,6 +312,7 @@ @@ -312,6 +312,7 @@
</ItemGroup>
<ItemGroup>
<Content Include="TestCases\PdbGen\ProgressReporting.xml" />
<Content Include="TestCases\PdbGen\ForLoopTests.xml" />
<Content Include="TestCases\PdbGen\CustomPdbId.xml" />
<Content Include="TestCases\PdbGen\HelloWorld.xml" />

58
ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
@ -9,13 +8,10 @@ using System.Text; @@ -9,13 +8,10 @@ using System.Text;
using System.Xml.Linq;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Tests.Helpers;
using ICSharpCode.Decompiler.TypeSystem;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.DiaSymReader.Tools;
using NUnit.Framework;
@ -72,6 +68,60 @@ namespace ICSharpCode.Decompiler.Tests @@ -72,6 +68,60 @@ namespace ICSharpCode.Decompiler.Tests
}
}
[Test]
public void ProgressReporting()
{
// Generate a PDB for an assembly and validate that the progress reporter is called with reasonable values
(string peFileName, string pdbFileName) = CompileTestCase(nameof(ProgressReporting));
var moduleDefinition = new PEFile(peFileName);
var resolver = new UniversalAssemblyResolver(peFileName, false, moduleDefinition.Metadata.DetectTargetFrameworkId(), null, PEStreamOptions.PrefetchEntireImage);
var decompiler = new CSharpDecompiler(moduleDefinition, resolver, new DecompilerSettings());
var lastFilesWritten = 0;
var totalFiles = -1;
Action<WritePortablePdbProgress> reportFunc = progress => {
if (totalFiles == -1)
{
// Initialize value on first call
totalFiles = progress.TotalFiles;
}
Assert.AreEqual(progress.TotalFiles, totalFiles);
Assert.AreEqual(progress.FilesWritten, lastFilesWritten + 1);
lastFilesWritten = progress.FilesWritten;
};
using (FileStream pdbStream = File.Open(Path.Combine(TestCasePath, nameof(ProgressReporting) + ".pdb"), FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
pdbStream.SetLength(0);
PortablePdbWriter.WritePdb(moduleDefinition, decompiler, new DecompilerSettings(), pdbStream, noLogo: true, progress: new TestProgressReporter(reportFunc));
pdbStream.Position = 0;
var metadataReader = MetadataReaderProvider.FromPortablePdbStream(pdbStream).GetMetadataReader();
var generatedPdbId = new BlobContentId(metadataReader.DebugMetadataHeader.Id);
}
Assert.AreEqual(totalFiles, lastFilesWritten);
}
private class TestProgressReporter : IProgress<WritePortablePdbProgress>
{
private Action<WritePortablePdbProgress> reportFunc;
public TestProgressReporter(Action<WritePortablePdbProgress> reportFunc)
{
this.reportFunc = reportFunc;
}
public void Report(WritePortablePdbProgress value)
{
reportFunc(value);
}
}
private void TestGeneratePdb([CallerMemberName] string testName = null)
{
const PdbToXmlOptions options = PdbToXmlOptions.IncludeEmbeddedSources | PdbToXmlOptions.ThrowOnError | PdbToXmlOptions.IncludeTokens | PdbToXmlOptions.ResolveTokens | PdbToXmlOptions.IncludeMethodSpans;

4
ICSharpCode.Decompiler.Tests/TestCases/PdbGen/CustomPdbId.xml

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<symbols>
<files>
<file id="1" name="ICSharpCode.Decompiler.Tests.TestCases.PdbGen\HelloWorld.cs" language="C#" checksumAlgorithm="SHA256"><![CDATA[using System;
<file id="1" name="ICSharpCode.Decompiler.Tests.TestCases.PdbGen\CustomPdbId.cs" language="C#" checksumAlgorithm="SHA256"><![CDATA[using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.PdbGen;
public class HelloWorld
public class CustomPdbId
{
public static void Main(string[] args)
{

44
ICSharpCode.Decompiler.Tests/TestCases/PdbGen/ProgressReporting.xml

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<symbols>
<files>
<file id="1" name="ICSharpCode.Decompiler.Tests.TestCases.PdbGen\ProgressReporting.cs" language="C#" checksumAlgorithm="SHA256">
<![CDATA[using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.PdbGen;
public class ProgressReporting
{
public static void Main(string[] args)
{
Console.ReadKey();
Console.WriteLine("Hello World!");
Console.ReadKey();
}
}
public class Class1
{
public static void Test()
{
Console.WriteLine("Class1");
}
}
public class Class2
{
public static void Test()
{
Console.WriteLine("Class2");
}
}
public class Class3
{
public static void Test()
{
Console.WriteLine("Class3");
}
}
]]></file>
</files>
</symbols>

31
ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs

@ -28,6 +28,7 @@ using System.Reflection.Metadata.Ecma335; @@ -28,6 +28,7 @@ using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
@ -40,6 +41,12 @@ using ICSharpCode.Decompiler.Util; @@ -40,6 +41,12 @@ using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.DebugInfo
{
public struct WritePortablePdbProgress
{
public int TotalFiles { get; internal set; }
public int FilesWritten { get; internal set; }
}
public class PortablePdbWriter
{
static readonly FileVersionInfo decompilerVersion = FileVersionInfo.GetVersionInfo(typeof(CSharpDecompiler).Assembly.Location);
@ -49,7 +56,14 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -49,7 +56,14 @@ namespace ICSharpCode.Decompiler.DebugInfo
return file.Reader.ReadDebugDirectory().Any(entry => entry.Type == DebugDirectoryEntryType.CodeView);
}
public static void WritePdb(PEFile file, CSharpDecompiler decompiler, DecompilerSettings settings, Stream targetStream, bool noLogo = false, BlobContentId? pdbId = null)
public static void WritePdb(
PEFile file,
CSharpDecompiler decompiler,
DecompilerSettings settings,
Stream targetStream,
bool noLogo = false,
BlobContentId? pdbId = null,
IProgress<WritePortablePdbProgress> progress = null)
{
MetadataBuilder metadata = new MetadataBuilder();
MetadataReader reader = file.Metadata;
@ -72,10 +86,23 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -72,10 +86,23 @@ namespace ICSharpCode.Decompiler.DebugInfo
return Path.Combine(ns, WholeProjectDecompiler.CleanUpFileName(typeName.Name) + ".cs");
}
foreach (var sourceFile in reader.GetTopLevelTypeDefinitions().GroupBy(BuildFileNameFromTypeName))
var sourceFiles = reader.GetTopLevelTypeDefinitions().GroupBy(BuildFileNameFromTypeName).ToList();
WritePortablePdbProgress currentProgress = new WritePortablePdbProgress() {
TotalFiles = sourceFiles.Count,
FilesWritten = 0
};
foreach (var sourceFile in sourceFiles)
{
// Generate syntax tree
var syntaxTree = decompiler.DecompileTypes(sourceFile);
if (progress != null)
{
currentProgress.FilesWritten++;
progress.Report(currentProgress);
}
if (!syntaxTree.HasChildren)
continue;

Loading…
Cancel
Save