Browse Source

Add first attempt at PdbGenerationTestRunner.

pull/1423/head
Siegfried Pammer 6 years ago
parent
commit
25c757b7cd
  1. 55
      ICSharpCode.Decompiler.Tests/DebugInfo/SequencePointTests.cs
  2. 51
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  3. 11
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  4. BIN
      ICSharpCode.Decompiler.Tests/IL/SequenceOfNestedIfs.dll
  5. BIN
      ICSharpCode.Decompiler.Tests/IL/StackTests.exe
  6. 54
      ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs
  7. 2
      ICSharpCode.Decompiler.Tests/TestCases/PdbGen/.gitignore
  8. 33
      ICSharpCode.Decompiler.Tests/TestCases/PdbGen/HelloWorld.xml
  9. 2
      ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs
  10. 1
      NuGet.config

55
ICSharpCode.Decompiler.Tests/DebugInfo/SequencePointTests.cs

@ -1,55 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.Tests.Helpers;
using ICSharpCode.Decompiler.TypeSystem;
using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests.Util
{
[TestFixture]
public class SequencePointTests
{
[Test]
public void BasicSequencePoints()
{
TestCreateSequencePoints(@"class C { void M() { int i = 0; int j = 1; } }",
"int num = 0;",
"int num2 = 1;");
}
private void TestCreateSequencePoints(string code, params string[] expectedSequencePoints)
{
var decompiler = Tester.GetDecompilerForSnippet(code);
var tree = decompiler.DecompileType(new FullTypeName("C"));
var output = new StringWriter();
tree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
TokenWriter tokenWriter = new TextWriterTokenWriter(output);
tokenWriter = new InsertMissingTokensDecorator(tokenWriter, (ILocatable)tokenWriter);
var formattingOptions = FormattingOptionsFactory.CreateSharpDevelop();
tree.AcceptVisitor(new CSharpOutputVisitor(tokenWriter, formattingOptions));
var functionsWithSequencePoints = decompiler.CreateSequencePoints(tree);
var finalText = output.ToString();
var lines = finalText.Split(new[] { output.NewLine }, StringSplitOptions.None);
var actualSequencePoints = new List<string>();
foreach (var sequencePoint in functionsWithSequencePoints.Values.First()) {
if (sequencePoint.IsHidden) {
continue;
}
var line = lines[sequencePoint.StartLine - 1];
var text = line.Substring(sequencePoint.StartColumn - 1, sequencePoint.EndColumn - sequencePoint.StartColumn);
actualSequencePoints.Add(text);
}
Assert.True(Enumerable.SequenceEqual(expectedSequencePoints, actualSequencePoints));
}
}
}

51
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -36,7 +36,10 @@ using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CSharp; using Microsoft.CSharp;
using Microsoft.DiaSymReader.Tools;
using NUnit.Framework; using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests.Helpers namespace ICSharpCode.Decompiler.Tests.Helpers
@ -345,23 +348,39 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
} }
} }
public static CSharpDecompiler GetDecompilerForSnippet(string csharpText) public static void CompileCSharpWithPdb(string assemblyName, Dictionary<string, string> sourceFiles, PdbToXmlOptions options)
{ {
var syntaxTree = SyntaxFactory.ParseSyntaxTree(csharpText); var parseOptions = new CSharpParseOptions(languageVersion: Microsoft.CodeAnalysis.CSharp.LanguageVersion.Latest);
var compilation = CSharpCompilation.Create(
"TestAssembly", List<EmbeddedText> embeddedTexts = new List<EmbeddedText>();
new[] { syntaxTree }, List<SyntaxTree> syntaxTrees = new List<SyntaxTree>();
defaultReferences.Value,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); foreach (KeyValuePair<string, string> file in sourceFiles) {
var peStream = new MemoryStream(); var sourceText = SourceText.From(file.Value, Encoding.UTF8);
var emitResult = compilation.Emit(peStream); syntaxTrees.Add(SyntaxFactory.ParseSyntaxTree(sourceText, parseOptions, file.Key));
peStream.Position = 0; embeddedTexts.Add(EmbeddedText.FromSource(file.Key, sourceText));
}
var moduleDefinition = new PEFile("TestAssembly.dll", peStream, PEStreamOptions.PrefetchEntireImage);
var resolver = new UniversalAssemblyResolver("TestAssembly.dll", false, moduleDefinition.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchEntireImage); var compilation = CSharpCompilation.Create(Path.GetFileNameWithoutExtension(assemblyName),
var decompiler = new CSharpDecompiler(moduleDefinition, resolver, new DecompilerSettings()); syntaxTrees, defaultReferences.Value,
new CSharpCompilationOptions(
return decompiler; OutputKind.DynamicallyLinkedLibrary,
platform: Platform.AnyCpu,
optimizationLevel: OptimizationLevel.Debug,
allowUnsafe: true,
deterministic: true
));
using (FileStream peStream = File.Open(assemblyName + ".dll", FileMode.OpenOrCreate, FileAccess.ReadWrite))
using (FileStream pdbStream = File.Open(assemblyName + ".pdb", FileMode.OpenOrCreate, FileAccess.ReadWrite)) {
var emitResult = compilation.Emit(peStream, pdbStream, options: new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb), embeddedTexts: embeddedTexts);
if (!emitResult.Success) {
StringBuilder b = new StringBuilder("Compiler error:");
foreach (var diag in emitResult.Diagnostics) {
b.AppendLine(diag.ToString());
}
throw new Exception(b.ToString());
}
}
} }
internal static string GetSuffix(CompilerOptions cscOptions) internal static string GetSuffix(CompilerOptions cscOptions)

11
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -39,6 +39,7 @@
<PackageReference Include="DiffLib" Version="2017.7.26.1241" /> <PackageReference Include="DiffLib" Version="2017.7.26.1241" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="2.10.0" /> <PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="2.10.0" />
<PackageReference Include="Microsoft.DiaSymReader.Converter.Xml" Version="1.1.0-beta1-63314-01" />
<PackageReference Include="NUnit3TestAdapter" Version="3.11.2" /> <PackageReference Include="NUnit3TestAdapter" Version="3.11.2" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" /> <PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="NUnit" Version="3.11.0" /> <PackageReference Include="NUnit" Version="3.11.0" />
@ -125,7 +126,7 @@
<Compile Include="TestCases\Pretty\NullPropagation.cs" /> <Compile Include="TestCases\Pretty\NullPropagation.cs" />
<Compile Include="TestCases\Pretty\VariableNaming.cs" /> <Compile Include="TestCases\Pretty\VariableNaming.cs" />
<Compile Include="TestCases\Pretty\VariableNamingWithoutSymbols.cs" /> <Compile Include="TestCases\Pretty\VariableNamingWithoutSymbols.cs" />
<Compile Include="DebugInfo\SequencePointTests.cs" /> <Compile Include="PdbGenerationTestRunner.cs" />
<None Include="TestCases\ILPretty\Issue1047.il" /> <None Include="TestCases\ILPretty\Issue1047.il" />
<None Include="TestCases\ILPretty\Issue959.cs" /> <None Include="TestCases\ILPretty\Issue959.cs" />
<None Include="TestCases\ILPretty\FSharpLoops_Debug.cs" /> <None Include="TestCases\ILPretty\FSharpLoops_Debug.cs" />
@ -201,6 +202,10 @@
<Compile Include="CodeSampleFileParser.cs" /> <Compile Include="CodeSampleFileParser.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="TestCases\PdbGen\HelloWorld.xml" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="TestCases\ILPretty\Issue646.il" /> <None Include="TestCases\ILPretty\Issue646.il" />
<None Include="TestCases\ILPretty\Issue379.il" /> <None Include="TestCases\ILPretty\Issue379.il" />
@ -217,4 +222,8 @@
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" /> <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="DebugInfo\" />
</ItemGroup>
</Project> </Project>

BIN
ICSharpCode.Decompiler.Tests/IL/SequenceOfNestedIfs.dll

Binary file not shown.

BIN
ICSharpCode.Decompiler.Tests/IL/StackTests.exe

Binary file not shown.

54
ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
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;
namespace ICSharpCode.Decompiler.Tests
{
[TestFixture]
public class PdbGenerationTestRunner
{
static readonly string TestCasePath = Tester.TestCasePath + "/PdbGen";
[Test, Ignore("Needs adjustments in generator")]
public void HelloWorld()
{
TestGeneratePdb();
}
private void TestGeneratePdb([CallerMemberName] string testName = null)
{
const PdbToXmlOptions options = PdbToXmlOptions.IncludeEmbeddedSources | PdbToXmlOptions.ThrowOnError | PdbToXmlOptions.IncludeTokens | PdbToXmlOptions.ResolveTokens | PdbToXmlOptions.IncludeMethodSpans;
string xmlFile = Path.Combine(TestCasePath, testName + ".xml");
string xmlContent = File.ReadAllText(xmlFile);
XDocument document = XDocument.Parse(xmlContent);
var files = document.Descendants("file").ToDictionary(f => f.Attribute("name").Value, f => f.Value);
Tester.CompileCSharpWithPdb(Path.Combine(TestCasePath, testName + ".expected"), files, options);
string peFileName = Path.Combine(TestCasePath, testName + ".expected.dll");
string pdbFileName = Path.Combine(TestCasePath, testName + ".expected.pdb");
var moduleDefinition = new PEFile(peFileName);
var resolver = new UniversalAssemblyResolver(peFileName, false, moduleDefinition.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchEntireImage);
var decompiler = new CSharpDecompiler(moduleDefinition, resolver, new DecompilerSettings());
using (FileStream pdbStream = File.Open(Path.Combine(TestCasePath, testName + ".pdb"), FileMode.OpenOrCreate, FileAccess.ReadWrite)) {
PortablePdbWriter.WritePdb(moduleDefinition, decompiler, new DecompilerSettings(), pdbStream);
pdbStream.Position = 0;
string resultFile = PdbToXmlConverter.ToXml(pdbStream, moduleDefinition.Reader.GetEntireImage().GetContent().ToArray(), options);
Assert.AreEqual(xmlContent, resultFile);
}
}
}
}

2
ICSharpCode.Decompiler.Tests/TestCases/PdbGen/.gitignore vendored

@ -0,0 +1,2 @@
/*.dll
/*.pdb

33
ICSharpCode.Decompiler.Tests/TestCases/PdbGen/HelloWorld.xml

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-16"?>
<symbols>
<files>
<file id="1" name="HelloWorld.cs" language="C#" checksumAlgorithm="SHA1" checksum="80-99-0D-B3-EA-B0-A3-72-39-A0-C5-FB-17-13-1B-CC-BF-3D-4C-AA" embeddedSourceLength="200"><![CDATA[using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.PdbGen
{
public class HelloWorld
{
public static void Hello()
{
Console.WriteLine("Hello World!");
}
}
}
]]></file>
</files>
<methods>
<method containingType="ICSharpCode.Decompiler.Tests.TestCases.PdbGen.HelloWorld" name="Hello" token="0x6000001">
<sequencePoints>
<entry offset="0x0" startLine="8" startColumn="3" endLine="8" endColumn="4" document="1" />
<entry offset="0x1" startLine="9" startColumn="4" endLine="9" endColumn="38" document="1" />
<entry offset="0xc" startLine="10" startColumn="3" endLine="10" endColumn="4" document="1" />
</sequencePoints>
<scope startOffset="0x0" endOffset="0xd" />
</method>
</methods>
<method-spans>
<method declaringType="ICSharpCode.Decompiler.Tests.TestCases.PdbGen.HelloWorld" methodName="Hello" token="0x6000001">
<document startLine="8" endLine="10" />
</method>
</method-spans>
</symbols>

2
ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs

@ -68,7 +68,7 @@ namespace ICSharpCode.Decompiler.DebugInfo
var type = reader.GetTypeDefinition(handle); var type = reader.GetTypeDefinition(handle);
// Generate syntax tree, source and checksum // Generate syntax tree, source and checksum
var name = metadata.GetOrAddDocumentName("ILSpy_Generated_" + type.GetFullTypeName(reader) + "_" + Guid.NewGuid() + ".cs"); var name = metadata.GetOrAddDocumentName(type.GetFullTypeName(reader).ReflectionName.Replace('.', Path.DirectorySeparatorChar) + ".cs");
var syntaxTree = decompiler.DecompileTypes(new[] { handle }); var syntaxTree = decompiler.DecompileTypes(new[] { handle });
syntaxTree.InsertChildAfter(null, new Comment(" PDB and source generated by ICSharpCode.Decompiler " + decompilerVersion.FileVersion), Roles.Comment); syntaxTree.InsertChildAfter(null, new Comment(" PDB and source generated by ICSharpCode.Decompiler " + decompilerVersion.FileVersion), Roles.Comment);
var sourceText = SyntaxTreeToString(syntaxTree, settings); var sourceText = SyntaxTreeToString(syntaxTree, settings);

1
NuGet.config

@ -3,5 +3,6 @@
<packageSources> <packageSources>
<add key="Nuget Official" value="https://api.nuget.org/v3/index.json" /> <add key="Nuget Official" value="https://api.nuget.org/v3/index.json" />
<add key="ILSpy" value="https://ci.appveyor.com/nuget/ilspy-masterfeed" /> <add key="ILSpy" value="https://ci.appveyor.com/nuget/ilspy-masterfeed" />
<add key="DotNet MyGet" value="https://dotnet.myget.org/F/symreader-converter/api/v3/index.json" />
</packageSources> </packageSources>
</configuration> </configuration>
Loading…
Cancel
Save