Skip to content

Commit 752dfcb

Browse files
committed
Add field forwarding in UnionStructSourceGenerator; fix incremental generator
1 parent 9fbd730 commit 752dfcb

File tree

7 files changed

+311
-72
lines changed

7 files changed

+311
-72
lines changed

Medicine.SourceGenerator.Tests~/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@
4343
SingletonSourceGeneratorTest.Case,
4444
UnionSourceGeneratorTest.Case,
4545
UnionSourceGeneratorTest.NoDerivedHeaderCase,
46+
UnionSourceGeneratorTest.HeaderFieldForwardingCase,
4647
UnionNestedSourceGeneratorTest.Case,
48+
UnionNestedSourceGeneratorTest.HeaderFieldForwardingCase,
4749
UnmanagedAccessSourceGeneratorTest.Case,
4850
WrapValueEnumerableSourceGeneratorTest.Case,
4951
ConstantsSourceGeneratorTest.Case,

Medicine.SourceGenerator.Tests~/SourceGeneratorTests/UnionNestedSourceGeneratorTest.cs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
using Microsoft.CodeAnalysis;
2+
13
static class UnionNestedSourceGeneratorTest
24
{
35
public static readonly DiagnosticTest Case =
46
new("Union generator supports nested [UnionHeader] families", Run);
57

8+
public static readonly DiagnosticTest HeaderFieldForwardingCase =
9+
new("Union generator forwards nested header fields to [Union] structs", RunHeaderFieldForwarding);
10+
611
static void Run()
712
=> SourceGeneratorTester.AssertGeneratesSource(
813
source: """
@@ -47,4 +52,81 @@ public partial struct RangeWeaponState : WeaponState.IDerivedWeapon
4752
""",
4853
generator: new UnionStructSourceGenerator()
4954
);
55+
56+
static void RunHeaderFieldForwarding()
57+
{
58+
var compilation = RoslynHarness.CreateCompilation(
59+
Stubs.Core,
60+
"""
61+
using Medicine;
62+
63+
[UnionHeader]
64+
public partial struct RootState
65+
{
66+
public interface IDerived
67+
{
68+
bool IsReady(int value);
69+
}
70+
71+
public TypeIDs TypeID;
72+
}
73+
74+
[UnionHeader]
75+
public partial struct ChildState
76+
{
77+
public interface IDerivedChild : RootState.IDerived
78+
{
79+
bool CanRun(int value);
80+
}
81+
82+
public RootState Header;
83+
public int Counter;
84+
}
85+
86+
[Union(1)]
87+
public partial struct ChildAState : ChildState.IDerivedChild
88+
{
89+
public ChildState Header;
90+
public bool IsReady(int value) => true;
91+
public bool CanRun(int value) => true;
92+
}
93+
94+
static class Usage
95+
{
96+
public static int Run()
97+
{
98+
var child = new ChildAState();
99+
child.Counter = 9;
100+
return child.Counter;
101+
}
102+
}
103+
"""
104+
);
105+
106+
var run = RoslynHarness.RunGenerators(
107+
compilation,
108+
[new UnionStructSourceGenerator()],
109+
[]
110+
);
111+
112+
RoslynHarness.AssertDoesNotContainDiagnostic(
113+
diagnostics: run.GeneratorDiagnostics,
114+
id: "MED911",
115+
because: "nested header-field forwarding should not throw in generator"
116+
);
117+
118+
var missingForwardingMembers = run.CompilationDiagnostics
119+
.Where(x => x.Severity == DiagnosticSeverity.Error)
120+
.Where(x => x.Id is "CS1061")
121+
.Where(x => x.GetMessage().Contains("Counter", StringComparison.Ordinal))
122+
.ToArray();
123+
124+
if (missingForwardingMembers.Length == 0)
125+
return;
126+
127+
throw new InvalidOperationException(
128+
"Expected nested [Union] structs to expose nested [UnionHeader] fields via generated forwarding properties." + Environment.NewLine +
129+
$"Actual diagnostics:{Environment.NewLine}{RoslynHarness.FormatDiagnostics(missingForwardingMembers)}"
130+
);
131+
}
50132
}

Medicine.SourceGenerator.Tests~/SourceGeneratorTests/UnionSourceGeneratorTest.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ static class UnionSourceGeneratorTest
88
public static readonly DiagnosticTest NoDerivedHeaderCase =
99
new("Union generator supports [UnionHeader] without derived [Union] structs", RunNoDerivedHeader);
1010

11+
public static readonly DiagnosticTest HeaderFieldForwardingCase =
12+
new("Union generator forwards header fields to [Union] structs", RunHeaderFieldForwarding);
13+
1114
static void Run()
1215
=> SourceGeneratorTester.AssertGeneratesSource(
1316
source: """
@@ -88,4 +91,74 @@ [new UnionStructSourceGenerator()],
8891
$"Actual diagnostics:{Environment.NewLine}{RoslynHarness.FormatDiagnostics(typeIdResolutionErrors)}"
8992
);
9093
}
94+
95+
static void RunHeaderFieldForwarding()
96+
{
97+
var compilation = RoslynHarness.CreateCompilation(
98+
Stubs.Core,
99+
"""
100+
using Medicine;
101+
102+
[UnionHeader]
103+
public partial struct ContractUnion
104+
{
105+
public interface Interface
106+
{
107+
int Value { get; }
108+
}
109+
110+
public TypeIDs TypeID;
111+
public int Version;
112+
public bool Enabled;
113+
}
114+
115+
[Union(1)]
116+
public partial struct ContractUnionA : ContractUnion.Interface
117+
{
118+
public ContractUnion Header;
119+
public int Value => 42;
120+
}
121+
122+
static class Usage
123+
{
124+
public static int Run()
125+
{
126+
var item = new ContractUnionA();
127+
item.Version = 7;
128+
item.Enabled = true;
129+
return item.Version + (item.Enabled ? 1 : 0);
130+
}
131+
}
132+
"""
133+
);
134+
135+
var run = RoslynHarness.RunGenerators(
136+
compilation,
137+
[new UnionStructSourceGenerator()],
138+
[]
139+
);
140+
141+
RoslynHarness.AssertDoesNotContainDiagnostic(
142+
diagnostics: run.GeneratorDiagnostics,
143+
id: "MED911",
144+
because: "header-field forwarding should not throw in generator"
145+
);
146+
147+
var missingForwardingMembers = run.CompilationDiagnostics
148+
.Where(x => x.Severity == DiagnosticSeverity.Error)
149+
.Where(x => x.Id is "CS1061")
150+
.Where(x =>
151+
x.GetMessage().Contains("Version", StringComparison.Ordinal) ||
152+
x.GetMessage().Contains("Enabled", StringComparison.Ordinal)
153+
)
154+
.ToArray();
155+
156+
if (missingForwardingMembers.Length == 0)
157+
return;
158+
159+
throw new InvalidOperationException(
160+
"Expected [Union] structs to expose [UnionHeader] fields via generated forwarding properties." + Environment.NewLine +
161+
$"Actual diagnostics:{Environment.NewLine}{RoslynHarness.FormatDiagnostics(missingForwardingMembers)}"
162+
);
163+
}
91164
}
11 KB
Binary file not shown.

0 commit comments

Comments
 (0)