diff --git a/ICSharpCode.Decompiler.Tests/CLAUDE.md b/ICSharpCode.Decompiler.Tests/CLAUDE.md
index d5655de3e..7b5f72d1c 100644
--- a/ICSharpCode.Decompiler.Tests/CLAUDE.md
+++ b/ICSharpCode.Decompiler.Tests/CLAUDE.md
@@ -42,7 +42,7 @@ root `CLAUDE.md` section on the submodule).
| Ugly | `UglyTestRunner` / `Ugly/*.cs` | compile -> decompile with sugar settings disabled | sibling `.Expected.cs` file |
| Disassembler | `DisassemblerPrettyTestRunner` / `Disassembler/Pretty/*.il` | ilasm -> disassemble with our `ReflectionDisassembler` | the `.il` source (or `.expected.il`, e.g. `SortedOutput`) |
| VBPretty | `VBPrettyTestRunner` / `VBPretty/*.vb` | vbc -> decompile to C# | sibling `.cs` file |
-| PdbGen | `PdbGenerationTestRunner` / `PdbGen/*.xml` | in-proc Roslyn compile, generate portable PDB with `PortablePdbWriter`, dump both PDBs with `PdbToXmlConverter` | `.expected.xml` |
+| PdbGen | `PdbGenerationTestRunner` / `PdbGen/*.xml` | in-proc Roslyn compile (real PDB = oracle), decompile, generate portable PDB with `PortablePdbWriter`, parse both PDBs' sequence-point blobs | the compiler's PDB, projected to the visible breakpoint map (see below) |
| Roundtrip | `RoundtripAssembly` (inputs from `ILSpy-tests/`) | whole-project decompile -> MSBuild rebuild -> run original NUnit tests against the rebuilt assembly | test-run success |
| Unit tests | `TypeSystem/`, `Semantics/`, `Output/`, `Util/`, `DataFlowTest`, `Metadata/`, `ProjectDecompiler/` | plain in-process NUnit | assertions |
@@ -69,8 +69,24 @@ helper, which picks the file via `[CallerMemberName]`.
- **ILPretty / Disassembler**: add a `.il` file (assembled with the NuGet ilasm) and the
expected `.cs` (`ILPretty`) or rely on round-tripping the `.il` itself (`Disassembler`).
- **VBPretty**: add `MyTest.vb` and the expected C# decompilation `MyTest.cs`.
-- **PdbGen**: add `MyTest.xml` containing the source files inside `` elements;
- the expected PDB dump lives in `MyTest.expected.xml`.
+- **PdbGen** (the reconstructed PDB's breakpoints match the C# compiler's): add `MyTest.xml`
+ containing the source inside `` elements, written exactly as ILSpy
+ pretty-prints a *single type* (one document per type, no assembly-attribute header - the same
+ discipline as Pretty). The runner compiles it with Roslyn (whose PDB is the oracle), decompiles,
+ reconstructs a PDB, and compares only the **visible breakpoint map**: per method, the ordered
+ source locations of the non-hidden sequence points. IL offsets, hidden sequence points, local
+ scopes and the embedded source are all dropped, because the decompiler reconstructs them
+ differently and they never match byte-for-byte. The comparer also runs an oracle-free
+ well-formedness check (strictly increasing IL offsets = no duplicate/overlapping points).
+ `TestSequencePoints()` asserts the map matches the compiler exactly; for the handful of methods
+ where the decompiler legitimately diverges (e.g. it breakpoints a method's opening brace where
+ the compiler keeps it hidden), call `TestSequencePoints(knownResidual: true)`; the residual is
+ auto-derived and committed as `MyTest.residual.txt`, so improvements and regressions both flip
+ the test like a pretty diff. On a mismatch the test writes `MyTest.residual.txt.generated` and
+ fails; accept a deliberate change by re-running with `ILSPY_ACCEPT_PDB_RESIDUAL=1` set (which
+ overwrites the snapshot in place) or by copying the `.generated` file over it. `Tolerance.Lines` drops column comparison
+ for statements whose column placement differs. Nothing is hand-maintained except the `.cs`
+ source and, rarely, the residual snapshot. No `.expected.*` is committed (all regenerated).
## Conditional expectations (#if) and comparison rules
diff --git a/ICSharpCode.Decompiler.Tests/Helpers/PdbSequencePoints.cs b/ICSharpCode.Decompiler.Tests/Helpers/PdbSequencePoints.cs
new file mode 100644
index 000000000..224281327
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/Helpers/PdbSequencePoints.cs
@@ -0,0 +1,198 @@
+// Copyright (c) 2026 Siegfried Pammer
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+using System.Reflection.PortableExecutable;
+using System.Text;
+
+namespace ICSharpCode.Decompiler.Tests.Helpers
+{
+ ///
+ /// Reads the sequence points out of a portable PDB and compares two PDBs (typically the one
+ /// the original C# compiler produced versus the one PortablePdbWriter reconstructs)
+ /// at the granularity that actually matters to a debugging user: the breakpoint map.
+ ///
+ ///
+ /// The decompiler reconstructs IL ranges, hidden sequence points and local scopes from the
+ /// ILAst, so those never match the original compiler byte-for-byte. What it can and should
+ /// get right is where the visible (non-hidden) breakpoints land in the source.
+ /// The comparison therefore projects each PDB onto the ordered list of visible sequence-point
+ /// source locations per method (keyed by method-definition row, which is shared between the
+ /// PDB and the PE it describes) and reports the residual difference.
+ ///
+ static class PdbSequencePoints
+ {
+ internal readonly record struct RawSequencePoint(int Offset, bool IsHidden,
+ int StartLine, int StartColumn, int EndLine, int EndColumn)
+ {
+ /// Visible source location, formatted with or without columns.
+ public string Format(bool includeColumns)
+ {
+ return includeColumns
+ ? $"({StartLine},{StartColumn})-({EndLine},{EndColumn})"
+ : $"L{StartLine}-{EndLine}";
+ }
+ }
+
+ ///
+ /// Reads every method's sequence points (hidden ones included, in document order) from a
+ /// portable PDB, keyed by the row number of the owning method definition.
+ ///
+ public static Dictionary> Read(Stream portablePdb)
+ {
+ portablePdb.Position = 0;
+ using var provider = MetadataReaderProvider.FromPortablePdbStream(portablePdb, MetadataStreamOptions.LeaveOpen);
+ var reader = provider.GetMetadataReader();
+ var result = new Dictionary>();
+ foreach (var handle in reader.MethodDebugInformation)
+ {
+ var info = reader.GetMethodDebugInformation(handle);
+ if (info.SequencePointsBlob.IsNil)
+ continue;
+ var list = new List();
+ foreach (var sp in info.GetSequencePoints())
+ {
+ list.Add(new RawSequencePoint(sp.Offset, sp.IsHidden,
+ sp.StartLine, sp.StartColumn, sp.EndLine, sp.EndColumn));
+ }
+ if (list.Count > 0)
+ {
+ // A MethodDebugInformation row is parallel to its MethodDefinition row.
+ result[MetadataTokens.GetRowNumber(handle)] = list;
+ }
+ }
+ return result;
+ }
+
+ ///
+ /// Resolves a readable "Namespace.Type.Method" label for each method-definition row,
+ /// for use in comparison failure messages.
+ ///
+ public static Dictionary ReadMethodNames(string peFileName)
+ {
+ using var peStream = File.OpenRead(peFileName);
+ using var peReader = new PEReader(peStream);
+ var md = peReader.GetMetadataReader();
+ var names = new Dictionary();
+ foreach (var handle in md.MethodDefinitions)
+ {
+ var method = md.GetMethodDefinition(handle);
+ var type = md.GetTypeDefinition(method.GetDeclaringType());
+ string typeName = md.GetString(type.Name);
+ if (!type.Namespace.IsNil && md.GetString(type.Namespace) is { Length: > 0 } ns)
+ typeName = ns + "." + typeName;
+ names[MetadataTokens.GetRowNumber(handle)] = typeName + "." + md.GetString(method.Name);
+ }
+ return names;
+ }
+
+ ///
+ /// Compares the visible breakpoint maps of two PDBs and returns the residual difference as
+ /// a deterministic, human-readable report. An empty string means the maps are identical.
+ ///
+ /// PDB used as the oracle (the original compiler's PDB).
+ /// PDB under test (the decompiler's reconstruction).
+ /// Row-to-label map from .
+ ///
+ /// When true, breakpoints must match on line and column; when false, only the
+ /// line span is compared (use for methods where the decompiler's column placement within a
+ /// statement legitimately differs).
+ ///
+ public static string CompareBreakpointMaps(
+ Dictionary> expected,
+ Dictionary> actual,
+ Dictionary methodNames,
+ bool includeColumns)
+ {
+ var report = new StringBuilder();
+ foreach (int row in expected.Keys.Union(actual.Keys).OrderBy(r => r))
+ {
+ var expectedPoints = Visible(expected, row, includeColumns);
+ var actualPoints = Visible(actual, row, includeColumns);
+
+ var expectedOnly = MultisetDifference(expectedPoints, actualPoints);
+ var actualOnly = MultisetDifference(actualPoints, expectedPoints);
+ if (expectedOnly.Count == 0 && actualOnly.Count == 0)
+ continue;
+
+ methodNames.TryGetValue(row, out var name);
+ report.Append($"0x{0x06000000 | row:x8} {name}").Append('\n');
+ foreach (var p in expectedOnly.OrderBy(p => p))
+ report.Append(" - compiler only: ").Append(p).Append('\n');
+ foreach (var p in actualOnly.OrderBy(p => p))
+ report.Append(" + decompiler only: ").Append(p).Append('\n');
+ }
+ return report.ToString();
+ }
+
+ static List Visible(Dictionary> map, int row, bool includeColumns)
+ {
+ if (!map.TryGetValue(row, out var list))
+ return new List();
+ return list.Where(sp => !sp.IsHidden).Select(sp => sp.Format(includeColumns)).ToList();
+ }
+
+ static List MultisetDifference(List a, List b)
+ {
+ var counts = new Dictionary();
+ foreach (var x in b)
+ counts[x] = counts.GetValueOrDefault(x) + 1;
+ var result = new List();
+ foreach (var x in a)
+ {
+ if (counts.TryGetValue(x, out int c) && c > 0)
+ counts[x] = c - 1;
+ else
+ result.Add(x);
+ }
+ return result;
+ }
+
+ ///
+ /// Checks that the decompiler's own PDB is structurally well-formed, independent of any
+ /// oracle: within each method the sequence points' IL offsets must be strictly increasing,
+ /// i.e. no duplicate or overlapping sequence points (a duplicate is exactly the failure
+ /// that aborts PortablePdbWriter in debug builds). Returns the offending methods, or
+ /// an empty string when well-formed.
+ ///
+ public static string CheckWellFormed(
+ Dictionary> pdb,
+ Dictionary methodNames)
+ {
+ var report = new StringBuilder();
+ foreach (int row in pdb.Keys.OrderBy(r => r))
+ {
+ var list = pdb[row];
+ for (int i = 1; i < list.Count; i++)
+ {
+ if (list[i].Offset <= list[i - 1].Offset)
+ {
+ methodNames.TryGetValue(row, out var name);
+ report.Append($"0x{0x06000000 | row:x8} {name}: non-increasing IL offset 0x{list[i].Offset:x} after 0x{list[i - 1].Offset:x}").Append('\n');
+ break;
+ }
+ }
+ }
+ return report.ToString();
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs b/ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs
index e2661e557..8719e4cc8 100644
--- a/ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs
@@ -5,7 +5,6 @@ using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
-using System.Text;
using System.Xml.Linq;
using ICSharpCode.Decompiler.CSharp;
@@ -13,8 +12,6 @@ using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Tests.Helpers;
-using Microsoft.DiaSymReader.Tools;
-
using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests
@@ -24,31 +21,41 @@ namespace ICSharpCode.Decompiler.Tests
{
static readonly string TestCasePath = Tester.TestCasePath + "/PdbGen";
+ ///
+ /// How strictly a reconstructed breakpoint must match the original compiler's.
+ ///
+ enum Tolerance
+ {
+ /// Visible breakpoints must match on source line and column.
+ LinesAndColumns,
+ /// Only the source line span must match; column placement may differ.
+ Lines
+ }
+
[Test]
public void HelloWorld()
{
- TestGeneratePdb();
+ TestSequencePoints();
}
[Test]
- [Ignore("Missing nested local scopes for loops, differences in IL ranges")]
public void ForLoopTests()
{
- TestGeneratePdb();
+ TestSequencePoints();
}
[Test]
- [Ignore("Differences in IL ranges")]
public void LambdaCapturing()
{
- TestGeneratePdb();
+ // The decompiler emits one extra visible breakpoint that the C# compiler keeps hidden;
+ // the recorded residual pins that known, deliberate difference.
+ TestSequencePoints(knownResidual: true);
}
[Test]
- [Ignore("Duplicate sequence points for local function")]
public void Members()
{
- TestGeneratePdb();
+ TestSequencePoints(knownResidual: true);
}
[Test]
@@ -194,41 +201,78 @@ namespace ICSharpCode.Decompiler.Tests
}
}
- private void TestGeneratePdb([CallerMemberName] string testName = null)
+ ///
+ /// Compiles the fixture with the C# compiler (producing a real PDB used as the oracle),
+ /// decompiles it and reconstructs a PDB with , then compares
+ /// the two PDBs' visible breakpoint maps. The decompiler reconstructs IL ranges, hidden
+ /// sequence points and local scopes differently from the compiler, so the comparison drops
+ /// those and asserts only on the source location of each visible (non-hidden) sequence point.
+ ///
+ ///
+ /// Whether visible breakpoints must match on column as well as line.
+ ///
+ ///
+ /// When false, the breakpoint map must match the compiler exactly (after the projection
+ /// above). When true, the residual difference must match the committed
+ /// <testName>.residual.txt snapshot - this pins the known imperfections the
+ /// decompiler cannot yet reproduce, so an improvement or a regression both flip the test and
+ /// prompt a deliberate snapshot update (the same accept-the-diff workflow as the pretty tests).
+ ///
+ private void TestSequencePoints(Tolerance tolerance = Tolerance.LinesAndColumns, bool knownResidual = false,
+ [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 peFileName, string pdbFileName) = CompileTestCase(testName);
- 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());
- using (FileStream pdbStream = File.Open(Path.Combine(TestCasePath, testName + ".pdb"), FileMode.OpenOrCreate, FileAccess.ReadWrite))
+ var module = new PEFile(peFileName);
+ var resolver = new UniversalAssemblyResolver(peFileName, false, module.Metadata.DetectTargetFrameworkId(), null, PEStreamOptions.PrefetchEntireImage);
+ var decompiler = new CSharpDecompiler(module, resolver, new DecompilerSettings());
+
+ using var generatedPdb = new MemoryStream();
+ new PortablePdbWriter { NoLogo = true }
+ .WritePdb(module, decompiler, new DecompilerSettings(), generatedPdb);
+
+ var methodNames = PdbSequencePoints.ReadMethodNames(peFileName);
+ var actual = PdbSequencePoints.Read(generatedPdb);
+ Dictionary> expected;
+ using (var compilerPdb = File.OpenRead(pdbFileName))
+ expected = PdbSequencePoints.Read(compilerPdb);
+
+ // Oracle-free structural check on the decompiler's own PDB.
+ string wellFormed = PdbSequencePoints.CheckWellFormed(actual, methodNames);
+ Assert.That(wellFormed, Is.Empty, "the reconstructed PDB is not well-formed:\n" + wellFormed);
+
+ string residual = PdbSequencePoints.CompareBreakpointMaps(
+ expected, actual, methodNames, includeColumns: tolerance == Tolerance.LinesAndColumns);
+
+ if (knownResidual)
{
- pdbStream.SetLength(0);
- new PortablePdbWriter { NoLogo = true }
- .WritePdb(moduleDefinition, decompiler, new DecompilerSettings(), pdbStream);
- pdbStream.Position = 0;
- using (Stream peStream = File.OpenRead(peFileName))
- using (Stream expectedPdbStream = File.OpenRead(pdbFileName))
+ string snapshotFile = Path.Combine(TestCasePath, testName + ".residual.txt");
+ string expectedResidual = File.Exists(snapshotFile)
+ ? File.ReadAllText(snapshotFile).Replace("\r\n", "\n")
+ : "";
+ if (residual != expectedResidual)
{
- using (StreamWriter writer = new StreamWriter(Path.ChangeExtension(pdbFileName, ".xml"), false, Encoding.UTF8))
+ // Setting ILSPY_ACCEPT_PDB_RESIDUAL=1 accepts the new residual in place, so a
+ // deliberate change is committed by re-running the test with the variable set
+ // rather than by hand-copying files.
+ if (Environment.GetEnvironmentVariable("ILSPY_ACCEPT_PDB_RESIDUAL") == "1")
{
- PdbToXmlConverter.ToXml(writer, expectedPdbStream, peStream, options);
+ File.WriteAllText(snapshotFile, residual);
}
- peStream.Position = 0;
- using (StreamWriter writer = new StreamWriter(Path.ChangeExtension(xmlFile, ".generated.xml"), false, Encoding.UTF8))
+ else
{
- PdbToXmlConverter.ToXml(writer, pdbStream, peStream, options);
+ File.WriteAllText(snapshotFile + ".generated", residual);
+ Assert.Fail($"the breakpoint-map residual changed; review the difference and, if intended, "
+ + $"accept it by re-running this test with ILSPY_ACCEPT_PDB_RESIDUAL=1 set (or copy "
+ + $"'{testName}.residual.txt.generated' over '{testName}.residual.txt')."
+ + $"\n\nExpected:\n{expectedResidual}\nActual:\n{residual}");
}
}
}
- string expectedFileName = Path.ChangeExtension(xmlFile, ".expected.xml");
- ProcessXmlFile(expectedFileName);
- string generatedFileName = Path.ChangeExtension(xmlFile, ".generated.xml");
- ProcessXmlFile(generatedFileName);
- CodeAssert.AreEqual(Normalize(expectedFileName), Normalize(generatedFileName));
+ else
+ {
+ Assert.That(residual, Is.Empty, "the reconstructed breakpoint map differs from the compiler's:\n" + residual);
+ }
}
private (string peFileName, string pdbFileName) CompileTestCase(string testName)
@@ -244,41 +288,5 @@ namespace ICSharpCode.Decompiler.Tests
return (peFileName, pdbFileName);
}
-
- private void ProcessXmlFile(string fileName)
- {
- var document = XDocument.Load(fileName);
- foreach (var file in document.Descendants("file"))
- {
- file.Attribute("checksum").Remove();
- file.Attribute("embeddedSourceLength")?.Remove();
- var name = file.Attribute("name");
- if (name != null)
- {
- // Generated document names use the platform's directory separator;
- // the expected files were produced on Windows.
- name.Value = name.Value.Replace('/', '\\');
- }
- file.ReplaceNodes(new XCData(file.Value.Replace("\uFEFF", "")));
- }
- document.Save(fileName, SaveOptions.None);
- }
-
- private string Normalize(string inputFileName)
- {
- return File.ReadAllText(inputFileName).Replace("\r\n", "\n").Replace("\r", "\n");
- }
- }
-
- class StringWriterWithEncoding : StringWriter
- {
- readonly Encoding encoding;
-
- public StringWriterWithEncoding(Encoding encoding)
- {
- this.encoding = encoding ?? throw new ArgumentNullException("encoding");
- }
-
- public override Encoding Encoding => encoding;
}
}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/.gitignore b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/.gitignore
index ae2ac11dc..96f4c7ba8 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/.gitignore
+++ b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/.gitignore
@@ -2,3 +2,4 @@
/*.pdb
/*.expected.xml
/*.generated.xml
+/*.residual.txt.generated
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/ForLoopTests.xml b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/ForLoopTests.xml
index 492f58104..39e8fc01e 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/ForLoopTests.xml
+++ b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/ForLoopTests.xml
@@ -28,45 +28,4 @@ public class ForLoopTests
}
]]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/HelloWorld.xml b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/HelloWorld.xml
index 90f2d542b..e0708da65 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/HelloWorld.xml
+++ b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/HelloWorld.xml
@@ -16,20 +16,4 @@ public class HelloWorld
}
]]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/LambdaCapturing.residual.txt b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/LambdaCapturing.residual.txt
new file mode 100644
index 000000000..e30fd63ec
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/LambdaCapturing.residual.txt
@@ -0,0 +1,2 @@
+0x06000001 ICSharpCode.Decompiler.Tests.TestCases.PdbGen.LambdaCapturing.Main
+ + decompiler only: (8,2)-(8,3)
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/LambdaCapturing.xml b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/LambdaCapturing.xml
index ac478edb0..5446ad889 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/LambdaCapturing.xml
+++ b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/LambdaCapturing.xml
@@ -21,42 +21,4 @@ public class LambdaCapturing
}
]]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/Members.residual.txt b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/Members.residual.txt
new file mode 100644
index 000000000..54e218660
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/Members.residual.txt
@@ -0,0 +1,6 @@
+0x0600000b C..ctor
+ - compiler only: (50,2)-(50,12)
+ + decompiler only: (51,2)-(51,3)
+0x0600000c C.Finalize
+ - compiler only: (56,2)-(56,3)
+ - compiler only: (57,2)-(57,3)
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/Members.xml b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/Members.xml
index 8e25eed1c..7c35954e4 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/Members.xml
+++ b/ICSharpCode.Decompiler.Tests/TestCases/PdbGen/Members.xml
@@ -1,95 +1,86 @@
-
- 42;
- private int Property
- {
- get
+ private int Property
+ {
+ get
{
return 0;
}
- set
+ set
{
}
- }
+ }
- private C this[int index] => null;
+ private C this[int index] => null;
- private C this[string s]
- {
- get
+ private C this[string s]
+ {
+ get
{
return null;
}
- set
+ set
{
}
- }
+ }
- public event Action Event
- {
- add
- {
- }
- remove
- {
- }
- }
+ public event Action Event
+ {
+ add
+ {
+ }
+ remove
+ {
+ }
+ }
- public static implicit operator C(int i)
- {
- return null;
- }
+ public static implicit operator C(int i)
+ {
+ return null;
+ }
- static C()
- {
- }
+ static C()
+ {
+ }
- public C()
- {
+ public C()
+ {
Console.WriteLine();
- }
-
- ~C()
- {
- }
+ }
- void IDisposable.Dispose()
- {
- }
+ ~C()
+ {
+ }
- private static void Main()
- {
- C c = new C();
+ void IDisposable.Dispose()
+ {
+ }
- c.Event += delegate
+ private static void Main()
+ {
+ C c = new C();
+ c.Event += delegate
{
};
- _ = c.Property;
- _ = c.ExpressionProperty;
- _ = c[0];
- _ = c[""];
-
- _ = (C)1;
-
- Local();
-
- static void Local()
- {
+ _ = c.Property;
+ _ = c.ExpressionProperty;
+ _ = c[0];
+ _ = c[""];
+ _ = (C)1;
+ Local();
+ static void Local()
+ {
Console.WriteLine();
- }
- }
+ }
+ }
}
]]>
-
-
-
-
-
\ No newline at end of file
+