mirror of https://github.com/icsharpcode/ILSpy.git
Browse Source
A field, auto-property, or event initializer is written once at its declaration, but in IL it runs in every instance constructor that does not chain to this(...) (and static initializers run in the static constructor). The decompiler lifts the initializer from a single constructor, so its breakpoint was emitted only there and the other constructors had none. Two causes are addressed: - The lift discarded the initializer's copies in the other constructors. They are now kept on MemberInitializerInOtherConstructorsAnnotation and replayed by SequencePointBuilder, mapping the same source location onto each constructor's IL. - PortablePdbWriter only emitted methods that DebugInfoGenerator discovered through declaration syntax, so a constructor whose declaration is omitted from the output (implicit default ctor, implicit static ctor, primary ctor) dropped its generated points. Those functions are now emitted by walking the sequence-point map directly. PdbGen fixtures cover single, multiple, this()-chained, implicit, static, primary-constructor, and field-like event initializers, pinning the reconstructed breakpoint map against the C# compiler's. Assisted-by: Claude:claude-opus-4-8:Claude Codepull/3712/head
19 changed files with 379 additions and 13 deletions
@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
|
||||
using System; |
||||
|
||||
internal class MemberInitializerChainedCtors |
||||
{ |
||||
private int field = Compute(1); |
||||
|
||||
private int Property { get; } = Compute(2); |
||||
|
||||
public MemberInitializerChainedCtors() |
||||
{ |
||||
Console.WriteLine(field + Property); |
||||
} |
||||
|
||||
public MemberInitializerChainedCtors(int value) |
||||
: this() |
||||
{ |
||||
Console.WriteLine(value); |
||||
} |
||||
|
||||
private static int Compute(int value) |
||||
{ |
||||
return value; |
||||
} |
||||
|
||||
private static void Main() |
||||
{ |
||||
new MemberInitializerChainedCtors(); |
||||
new MemberInitializerChainedCtors(3); |
||||
} |
||||
} |
||||
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
0x06000001 MemberInitializerChainedCtors.get_Property |
||||
- compiler only: (7,25)-(7,29) |
||||
0x06000002 MemberInitializerChainedCtors..ctor |
||||
+ decompiler only: (10,2)-(10,3) |
||||
+ decompiler only: (5,22)-(5,32) |
||||
- compiler only: (5,2)-(5,33) |
||||
+ decompiler only: hidden after (7,34)-(7,44) |
||||
- compiler only: (9,2)-(9,40) |
||||
0x06000003 MemberInitializerChainedCtors..ctor |
||||
+ decompiler only: (16,2)-(16,3) |
||||
- compiler only: (15,5)-(15,11) |
||||
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
using System; |
||||
|
||||
internal class MemberInitializerEvents |
||||
{ |
||||
private event EventHandler Changed = Handler; |
||||
|
||||
public MemberInitializerEvents() |
||||
{ |
||||
this.Changed?.Invoke(this, EventArgs.Empty); |
||||
} |
||||
|
||||
public MemberInitializerEvents(int value) |
||||
{ |
||||
this.Changed?.Invoke(this, EventArgs.Empty); |
||||
} |
||||
|
||||
private static void Handler(object sender, EventArgs e) |
||||
{ |
||||
} |
||||
|
||||
private static void Main() |
||||
{ |
||||
new MemberInitializerEvents(); |
||||
new MemberInitializerEvents(3); |
||||
} |
||||
} |
||||
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
0x06000003 MemberInitializerEvents..ctor |
||||
+ decompiler only: (8,2)-(8,3) |
||||
+ decompiler only: (5,39)-(5,46) |
||||
+ decompiler only: hidden after (5,39)-(5,46) |
||||
- compiler only: (5,2)-(5,47) |
||||
- compiler only: (7,2)-(7,34) |
||||
+ decompiler only: hidden after (10,2)-(10,3) |
||||
0x06000004 MemberInitializerEvents..ctor |
||||
+ decompiler only: (13,2)-(13,3) |
||||
+ decompiler only: (5,39)-(5,46) |
||||
+ decompiler only: hidden after (5,39)-(5,46) |
||||
- compiler only: (5,2)-(5,47) |
||||
- compiler only: (12,2)-(12,43) |
||||
+ decompiler only: hidden after (15,2)-(15,3) |
||||
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
using System; |
||||
|
||||
internal class MemberInitializerImplicitCtor |
||||
{ |
||||
private int field = Compute(1); |
||||
|
||||
private int Property { get; } = Compute(2); |
||||
|
||||
private static int Compute(int value) |
||||
{ |
||||
return value; |
||||
} |
||||
|
||||
private static void Main() |
||||
{ |
||||
MemberInitializerImplicitCtor memberInitializerImplicitCtor = new MemberInitializerImplicitCtor(); |
||||
Console.WriteLine(memberInitializerImplicitCtor.field + memberInitializerImplicitCtor.Property); |
||||
} |
||||
} |
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
0x06000001 MemberInitializerImplicitCtor.get_Property |
||||
- compiler only: (7,25)-(7,29) |
||||
0x06000004 MemberInitializerImplicitCtor..ctor |
||||
+ decompiler only: (5,22)-(5,32) |
||||
- compiler only: (5,2)-(5,33) |
||||
+ decompiler only: hidden after (7,34)-(7,44) |
||||
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
using System; |
||||
|
||||
internal class MemberInitializerPrimaryCtor(int factor) |
||||
{ |
||||
private int field = Compute(factor); |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return field.ToString(); |
||||
} |
||||
|
||||
private static int Compute(int value) |
||||
{ |
||||
return value; |
||||
} |
||||
|
||||
private static void Main() |
||||
{ |
||||
Console.WriteLine(new MemberInitializerPrimaryCtor(3)); |
||||
} |
||||
} |
||||
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
0x06000001 MemberInitializerPrimaryCtor..ctor |
||||
+ decompiler only: (5,22)-(5,37) |
||||
+ decompiler only: hidden after (5,22)-(5,37) |
||||
- compiler only: (5,2)-(5,38) |
||||
- compiler only: (3,16)-(3,56) |
||||
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
using System; |
||||
|
||||
internal class MemberInitializerSingleCtor |
||||
{ |
||||
private int field = Compute(1); |
||||
|
||||
private int Property { get; } = Compute(2); |
||||
|
||||
public MemberInitializerSingleCtor() |
||||
{ |
||||
Console.WriteLine(field + Property); |
||||
} |
||||
|
||||
private static int Compute(int value) |
||||
{ |
||||
return value; |
||||
} |
||||
|
||||
private static void Main() |
||||
{ |
||||
new MemberInitializerSingleCtor(); |
||||
} |
||||
} |
||||
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
0x06000001 MemberInitializerSingleCtor.get_Property |
||||
- compiler only: (7,25)-(7,29) |
||||
0x06000002 MemberInitializerSingleCtor..ctor |
||||
+ decompiler only: (10,2)-(10,3) |
||||
+ decompiler only: (5,22)-(5,32) |
||||
- compiler only: (5,2)-(5,33) |
||||
+ decompiler only: hidden after (7,34)-(7,44) |
||||
- compiler only: (9,2)-(9,38) |
||||
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
using System; |
||||
|
||||
internal class MemberInitializerStaticCtor |
||||
{ |
||||
private static int field = Compute(1); |
||||
|
||||
private static int Property { get; } = Compute(2); |
||||
|
||||
private static int Compute(int value) |
||||
{ |
||||
return value; |
||||
} |
||||
|
||||
private static void Main() |
||||
{ |
||||
Console.WriteLine(field + Property); |
||||
} |
||||
} |
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
0x06000001 MemberInitializerStaticCtor.get_Property |
||||
- compiler only: (7,32)-(7,36) |
||||
0x06000005 MemberInitializerStaticCtor..cctor |
||||
+ decompiler only: (5,29)-(5,39) |
||||
- compiler only: (5,2)-(5,40) |
||||
+ decompiler only: hidden after (7,41)-(7,51) |
||||
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
using System; |
||||
|
||||
internal class MemberInitializers |
||||
{ |
||||
private int instanceField = Compute(1); |
||||
|
||||
private int InstanceProperty { get; } = Compute(2); |
||||
|
||||
public MemberInitializers() |
||||
{ |
||||
Console.WriteLine(instanceField + InstanceProperty); |
||||
} |
||||
|
||||
public MemberInitializers(int value) |
||||
{ |
||||
Console.WriteLine(instanceField + InstanceProperty + value); |
||||
} |
||||
|
||||
private static int Compute(int value) |
||||
{ |
||||
return value; |
||||
} |
||||
|
||||
private static void Main() |
||||
{ |
||||
_ = new MemberInitializers(); |
||||
_ = new MemberInitializers(3); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue