Skip to content

Commit 9a68b7e

Browse files
authored
Improve binder gen binding logic (init, member binding, polymorphism) (#91717)
* Improve binder gen binding logic (init, member minding, polymorphism) * Improve handling of types with no bindable members * Enhance bind-parse-type-from-method-param to comprehensive baseline test * Move emitter methods to the files they are used in * Address feedback regarding assertions
1 parent e21a975 commit 9a68b7e

36 files changed

+1170
-720
lines changed
Lines changed: 0 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System;
54
using System.Collections.Immutable;
6-
using System.Diagnostics;
7-
using System.Text.RegularExpressions;
85
using Microsoft.CodeAnalysis;
96
using SourceGenerators;
107

@@ -16,12 +13,6 @@ private sealed partial class Emitter
1613
{
1714
private readonly SourceProductionContext _context;
1815
private readonly SourceGenerationSpec _sourceGenSpec;
19-
20-
private bool _emitBlankLineBeforeNextStatement;
21-
private int _valueSuffixIndex;
22-
23-
private static readonly Regex s_arrayBracketsRegex = new(Regex.Escape("[]"));
24-
2516
private readonly SourceWriter _writer = new();
2617

2718
public Emitter(SourceProductionContext context, SourceGenerationSpec sourceGenSpec)
@@ -64,163 +55,6 @@ file static class {{Identifier.BindingExtensions}}
6455
_context.AddSource($"{Identifier.BindingExtensions}.g.cs", _writer.ToSourceText());
6556
}
6657

67-
private void EmitBindCoreCall(
68-
TypeSpec type,
69-
string memberAccessExpr,
70-
string configArgExpr,
71-
InitializationKind initKind,
72-
Action<string>? writeOnSuccess = null)
73-
{
74-
Debug.Assert(type.CanInitialize);
75-
76-
if (!type.NeedsMemberBinding)
77-
{
78-
EmitObjectInit(memberAccessExpr, initKind);
79-
return;
80-
}
81-
82-
string tempIdentifier = GetIncrementalIdentifier(Identifier.temp);
83-
if (initKind is InitializationKind.AssignmentWithNullCheck)
84-
{
85-
Debug.Assert(!type.IsValueType);
86-
_writer.WriteLine($"{type.DisplayString}? {tempIdentifier} = {memberAccessExpr};");
87-
EmitBindCoreCall(tempIdentifier, InitializationKind.AssignmentWithNullCheck);
88-
}
89-
else if (initKind is InitializationKind.None && type.IsValueType)
90-
{
91-
EmitBindCoreCall(tempIdentifier, InitializationKind.Declaration);
92-
_writer.WriteLine($"{memberAccessExpr} = {tempIdentifier};");
93-
}
94-
else
95-
{
96-
EmitBindCoreCall(memberAccessExpr, initKind);
97-
}
98-
99-
void EmitBindCoreCall(string instanceExpr, InitializationKind initKind)
100-
{
101-
string bindCoreCall = $@"{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configArgExpr}, ref {instanceExpr}, {Identifier.binderOptions});";
102-
EmitObjectInit(instanceExpr, initKind);
103-
_writer.WriteLine(bindCoreCall);
104-
writeOnSuccess?.Invoke(instanceExpr);
105-
}
106-
107-
void EmitObjectInit(string instanceExpr, InitializationKind initKind)
108-
{
109-
if (initKind is not InitializationKind.None)
110-
{
111-
this.EmitObjectInit(type, instanceExpr, initKind, configArgExpr);
112-
}
113-
}
114-
}
115-
116-
private void EmitBindLogicFromString(
117-
ParsableFromStringSpec type,
118-
string sectionValueExpr,
119-
string sectionPathExpr,
120-
Action<string>? writeOnSuccess,
121-
bool checkForNullSectionValue,
122-
bool useIncrementalStringValueIdentifier)
123-
{
124-
StringParsableTypeKind typeKind = type.StringParsableTypeKind;
125-
Debug.Assert(typeKind is not StringParsableTypeKind.None);
126-
127-
string nonNull_StringValue_Identifier = useIncrementalStringValueIdentifier ? GetIncrementalIdentifier(Identifier.value) : Identifier.value;
128-
string stringValueToParse_Expr = checkForNullSectionValue ? nonNull_StringValue_Identifier : sectionValueExpr;
129-
130-
string parsedValueExpr;
131-
if (typeKind is StringParsableTypeKind.AssignFromSectionValue)
132-
{
133-
parsedValueExpr = stringValueToParse_Expr;
134-
}
135-
else if (typeKind is StringParsableTypeKind.Enum)
136-
{
137-
parsedValueExpr = $"ParseEnum<{type.DisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})";
138-
}
139-
else
140-
{
141-
parsedValueExpr = $"{type.ParseMethodName}({stringValueToParse_Expr}, () => {sectionPathExpr})";
142-
}
143-
144-
if (!checkForNullSectionValue)
145-
{
146-
InvokeWriteOnSuccess();
147-
}
148-
else
149-
{
150-
EmitStartBlock($"if ({sectionValueExpr} is string {nonNull_StringValue_Identifier})");
151-
InvokeWriteOnSuccess();
152-
EmitEndBlock();
153-
}
154-
155-
void InvokeWriteOnSuccess() => writeOnSuccess?.Invoke(parsedValueExpr);
156-
}
157-
158-
private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, InitializationKind initKind, string configArgExpr)
159-
{
160-
Debug.Assert(type.CanInitialize && initKind is not InitializationKind.None);
161-
162-
string initExpr;
163-
CollectionSpec? collectionType = type as CollectionSpec;
164-
165-
string effectiveDisplayString = type.DisplayString;
166-
if (collectionType is not null)
167-
{
168-
if (collectionType is EnumerableSpec { InitializationStrategy: InitializationStrategy.Array })
169-
{
170-
initExpr = $"new {s_arrayBracketsRegex.Replace(effectiveDisplayString, "[0]", 1)}";
171-
}
172-
else
173-
{
174-
effectiveDisplayString = (collectionType.ConcreteType ?? collectionType).DisplayString;
175-
initExpr = $"new {effectiveDisplayString}()";
176-
}
177-
}
178-
else if (type.InitializationStrategy is InitializationStrategy.ParameterlessConstructor)
179-
{
180-
initExpr = $"new {effectiveDisplayString}()";
181-
}
182-
else
183-
{
184-
Debug.Assert(type.InitializationStrategy is InitializationStrategy.ParameterizedConstructor);
185-
string initMethodIdentifier = GetInitalizeMethodDisplayString(((ObjectSpec)type));
186-
initExpr = $"{initMethodIdentifier}({configArgExpr}, {Identifier.binderOptions})";
187-
}
188-
189-
if (initKind == InitializationKind.Declaration)
190-
{
191-
Debug.Assert(!memberAccessExpr.Contains("."));
192-
_writer.WriteLine($"var {memberAccessExpr} = {initExpr};");
193-
}
194-
else if (initKind == InitializationKind.AssignmentWithNullCheck)
195-
{
196-
if (collectionType is CollectionSpec
197-
{
198-
InitializationStrategy: InitializationStrategy.ParameterizedConstructor or InitializationStrategy.ToEnumerableMethod
199-
})
200-
{
201-
if (collectionType.InitializationStrategy is InitializationStrategy.ParameterizedConstructor)
202-
{
203-
_writer.WriteLine($"{memberAccessExpr} = {memberAccessExpr} is null ? {initExpr} : new {effectiveDisplayString}({memberAccessExpr});");
204-
}
205-
else
206-
{
207-
_writer.WriteLine($"{memberAccessExpr} = {memberAccessExpr} is null ? {initExpr} : {memberAccessExpr}.{collectionType.ToEnumerableMethodCall!};");
208-
}
209-
}
210-
else
211-
{
212-
_writer.WriteLine($"{memberAccessExpr} ??= {initExpr};");
213-
}
214-
}
215-
else
216-
{
217-
Debug.Assert(initKind is InitializationKind.SimpleAssignment);
218-
_writer.WriteLine($"{memberAccessExpr} = {initExpr};");
219-
}
220-
221-
return true;
222-
}
223-
22458
private void EmitInterceptsLocationAttrDecl()
22559
{
22660
_writer.WriteLine();
@@ -250,18 +84,6 @@ private void EmitUsingStatements()
25084
_writer.WriteLine($"using {@namespace};");
25185
}
25286
}
253-
254-
private void EmitIConfigurationHasValueOrChildrenCheck(bool voidReturn)
255-
{
256-
string returnPostfix = voidReturn ? string.Empty : " null";
257-
_writer.WriteLine($$"""
258-
if (!{{Identifier.HasValueOrChildren}}({{Identifier.configuration}}))
259-
{
260-
return{{returnPostfix}};
261-
}
262-
""");
263-
_writer.WriteLine();
264-
}
26587
}
26688
}
26789
}

0 commit comments

Comments
 (0)