diff --git a/ICSharpCode.Decompiler.Tests/DebugInfo/SequencePointTests.cs b/ICSharpCode.Decompiler.Tests/DebugInfo/SequencePointTests.cs deleted file mode 100644 index 1212469b9..000000000 --- a/ICSharpCode.Decompiler.Tests/DebugInfo/SequencePointTests.cs +++ /dev/null @@ -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(); - 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)); - } - } -} diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs index ace9d1ef9..4e2bf424c 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs @@ -36,7 +36,10 @@ using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Text; using Microsoft.CSharp; +using Microsoft.DiaSymReader.Tools; using NUnit.Framework; 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 sourceFiles, PdbToXmlOptions options) { - var syntaxTree = SyntaxFactory.ParseSyntaxTree(csharpText); - var compilation = CSharpCompilation.Create( - "TestAssembly", - new[] { syntaxTree }, - defaultReferences.Value, - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - var peStream = new MemoryStream(); - var emitResult = compilation.Emit(peStream); - peStream.Position = 0; - - var moduleDefinition = new PEFile("TestAssembly.dll", peStream, PEStreamOptions.PrefetchEntireImage); - var resolver = new UniversalAssemblyResolver("TestAssembly.dll", false, moduleDefinition.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchEntireImage); - var decompiler = new CSharpDecompiler(moduleDefinition, resolver, new DecompilerSettings()); - - return decompiler; + var parseOptions = new CSharpParseOptions(languageVersion: Microsoft.CodeAnalysis.CSharp.LanguageVersion.Latest); + + List embeddedTexts = new List(); + List syntaxTrees = new List(); + + foreach (KeyValuePair file in sourceFiles) { + var sourceText = SourceText.From(file.Value, Encoding.UTF8); + syntaxTrees.Add(SyntaxFactory.ParseSyntaxTree(sourceText, parseOptions, file.Key)); + embeddedTexts.Add(EmbeddedText.FromSource(file.Key, sourceText)); + } + + var compilation = CSharpCompilation.Create(Path.GetFileNameWithoutExtension(assemblyName), + syntaxTrees, defaultReferences.Value, + new CSharpCompilationOptions( + 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) diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index 76c263b9b..679c27753 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -39,6 +39,7 @@ + @@ -125,7 +126,7 @@ - + @@ -201,6 +202,10 @@ + + + + @@ -217,4 +222,8 @@ + + + + \ No newline at end of file diff --git a/ICSharpCode.Decompiler.Tests/IL/SequenceOfNestedIfs.dll b/ICSharpCode.Decompiler.Tests/IL/SequenceOfNestedIfs.dll deleted file mode 100644 index f517d4546..000000000 Binary files a/ICSharpCode.Decompiler.Tests/IL/SequenceOfNestedIfs.dll and /dev/null differ diff --git a/ICSharpCode.Decompiler.Tests/IL/StackTests.exe b/ICSharpCode.Decompiler.Tests/IL/StackTests.exe deleted file mode 100644 index db6194ad6..000000000 Binary files a/ICSharpCode.Decompiler.Tests/IL/StackTests.exe and /dev/null differ diff --git a/ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs b/ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs new file mode 100644 index 000000000..3f62b4d0f --- /dev/null +++ b/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); + } + } + } +} diff --git a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/.gitignore b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/.gitignore new file mode 100644 index 000000000..d35b79a63 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/.gitignore @@ -0,0 +1,2 @@ +/*.dll +/*.pdb diff --git a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/HelloWorld.xml b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/HelloWorld.xml new file mode 100644 index 000000000..bb58f04fa --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/HelloWorld.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs b/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs index 2eee6fd26..2b07a86de 100644 --- a/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs +++ b/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs @@ -68,7 +68,7 @@ namespace ICSharpCode.Decompiler.DebugInfo var type = reader.GetTypeDefinition(handle); // 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 }); syntaxTree.InsertChildAfter(null, new Comment(" PDB and source generated by ICSharpCode.Decompiler " + decompilerVersion.FileVersion), Roles.Comment); var sourceText = SyntaxTreeToString(syntaxTree, settings); diff --git a/NuGet.config b/NuGet.config index a2c1835ee..22c4b3475 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,5 +3,6 @@ + \ No newline at end of file