Skip to content

Commit 9295993

Browse files
committed
Merge in 'release/8.0-rc1' changes
2 parents 4bdeb72 + 034d27f commit 9295993

File tree

67 files changed

+1581
-1188
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1581
-1188
lines changed

docs/project/list-of-diagnostics.md

+2
Original file line numberDiff line numberDiff line change
@@ -270,3 +270,5 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
270270
| Suppression ID | Suppressed Diagnostic ID | Description |
271271
| :----------------------- | :----------------------- | :---------- |
272272
| __`SYSLIBSUPPRESS0001`__ | CA1822 | Do not offer to make methods static when the methods need to be instance methods for a custom marshaller shape. |
273+
| __`SYSLIBSUPPRESS0002`__ | IL2026 | ConfigurationBindingGenerator: suppress RequiresUnreferencedCode diagnostic for binding call that has been intercepted by a generated static variant. |
274+
| __`SYSLIBSUPPRESS0003`__ | IL3050 | ConfigurationBindingGenerator: suppress RequiresDynamicCode diagnostic for binding call that has been intercepted by a generated static variant. |

eng/SourceBuildPrebuiltBaseline.xml

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<UsagePattern IdentityGlob="System.Composition*/*7.*" />
1111
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.4.*" />
1212
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.5.*" />
13+
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.7.*" />
1314

1415
<!-- Allowed and pinned to major version due to https://github.com/dotnet/source-build/issues/3228 -->
1516
<UsagePattern IdentityGlob="Microsoft.NETCore.App.Crossgen2.linux-x64/*8.*" />

src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs

+49-38
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Immutable;
56
using System.Diagnostics;
67
using System.Text.RegularExpressions;
78
using Microsoft.CodeAnalysis;
@@ -17,7 +18,6 @@ private sealed partial class Emitter
1718
private readonly SourceGenerationSpec _sourceGenSpec;
1819

1920
private bool _emitBlankLineBeforeNextStatement;
20-
private bool _useFullyQualifiedNames;
2121
private int _valueSuffixIndex;
2222

2323
private static readonly Regex s_arrayBracketsRegex = new(Regex.Escape("[]"));
@@ -32,7 +32,7 @@ public Emitter(SourceProductionContext context, SourceGenerationSpec sourceGenSp
3232

3333
public void Emit()
3434
{
35-
if (!ShouldEmitBinders())
35+
if (!ShouldEmitBindingExtensions())
3636
{
3737
return;
3838
}
@@ -42,17 +42,26 @@ public void Emit()
4242
#nullable enable
4343
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
4444
""");
45-
_writer.WriteLine();
4645

47-
_useFullyQualifiedNames = true;
48-
EmitBinder_Extensions_IConfiguration();
49-
EmitBinder_Extensions_OptionsBuilder();
50-
EmitBinder_Extensions_IServiceCollection();
46+
EmitInterceptsLocationAttrDecl();
47+
48+
EmitStartBlock($"namespace {ProjectName}");
49+
EmitUsingStatements();
50+
51+
_writer.WriteLine();
52+
EmitStartBlock($$"""
53+
{{Expression.GeneratedCodeAnnotation}}
54+
file static class {{Identifier.BindingExtensions}}
55+
""");
56+
EmitBindingExtensions_IConfiguration();
57+
EmitBindingExtensions_OptionsBuilder();
58+
EmitBindingExtensions_IServiceCollection();
59+
EmitCoreBindingHelpers();
60+
EmitEndBlock(); // BindingExtensions class
5161

52-
_useFullyQualifiedNames = false;
53-
Emit_CoreBindingHelper();
62+
EmitEndBlock(); // Binding namespace.
5463

55-
_context.AddSource($"{Identifier.GeneratedConfigurationBinder}.g.cs", _writer.ToSourceText());
64+
_context.AddSource($"{Identifier.BindingExtensions}.g.cs", _writer.ToSourceText());
5665
}
5766

5867
private void EmitBindCoreCall(
@@ -74,7 +83,7 @@ private void EmitBindCoreCall(
7483
if (initKind is InitializationKind.AssignmentWithNullCheck)
7584
{
7685
Debug.Assert(!type.IsValueType);
77-
_writer.WriteLine($"{type.MinimalDisplayString}? {tempIdentifier} = {memberAccessExpr};");
86+
_writer.WriteLine($"{type.DisplayString}? {tempIdentifier} = {memberAccessExpr};");
7887
EmitBindCoreCall(tempIdentifier, InitializationKind.AssignmentWithNullCheck);
7988
}
8089
else if (initKind is InitializationKind.None && type.IsValueType)
@@ -89,9 +98,7 @@ private void EmitBindCoreCall(
8998

9099
void EmitBindCoreCall(string objExpression, InitializationKind initKind)
91100
{
92-
string methodDisplayString = GetHelperMethodDisplayString(nameof(MethodsToGen_CoreBindingHelper.BindCore));
93-
string bindCoreCall = $@"{methodDisplayString}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});";
94-
101+
string bindCoreCall = $@"{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});";
95102
EmitObjectInit(objExpression, initKind);
96103
_writer.WriteLine(bindCoreCall);
97104
writeOnSuccess?.Invoke(objExpression);
@@ -127,12 +134,11 @@ private void EmitBindLogicFromString(
127134
}
128135
else if (typeKind is StringParsableTypeKind.Enum)
129136
{
130-
parsedValueExpr = $"ParseEnum<{type.MinimalDisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})";
137+
parsedValueExpr = $"ParseEnum<{type.DisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})";
131138
}
132139
else
133140
{
134-
string helperMethodDisplayString = GetHelperMethodDisplayString(type.ParseMethodName);
135-
parsedValueExpr = $"{helperMethodDisplayString}({stringValueToParse_Expr}, () => {sectionPathExpr})";
141+
parsedValueExpr = $"{type.ParseMethodName}({stringValueToParse_Expr}, () => {sectionPathExpr})";
136142
}
137143

138144
if (!checkForNullSectionValue)
@@ -156,7 +162,7 @@ private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, Initializati
156162
string initExpr;
157163
CollectionSpec? collectionType = type as CollectionSpec;
158164

159-
string effectiveDisplayString = GetTypeDisplayString(type);
165+
string effectiveDisplayString = type.DisplayString;
160166
if (collectionType is not null)
161167
{
162168
if (collectionType is EnumerableSpec { InitializationStrategy: InitializationStrategy.Array })
@@ -165,7 +171,7 @@ private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, Initializati
165171
}
166172
else
167173
{
168-
effectiveDisplayString = GetTypeDisplayString(collectionType.ConcreteType ?? collectionType);
174+
effectiveDisplayString = (collectionType.ConcreteType ?? collectionType).DisplayString;
169175
initExpr = $"new {effectiveDisplayString}()";
170176
}
171177
}
@@ -215,36 +221,41 @@ private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, Initializati
215221
return true;
216222
}
217223

218-
private void EmitCastToIConfigurationSection()
224+
private void EmitInterceptsLocationAttrDecl()
219225
{
220-
string sectionTypeDisplayString;
221-
string exceptionTypeDisplayString;
222-
if (_useFullyQualifiedNames)
223-
{
224-
sectionTypeDisplayString = "global::Microsoft.Extensions.Configuration.IConfigurationSection";
225-
exceptionTypeDisplayString = FullyQualifiedDisplayString.InvalidOperationException;
226-
}
227-
else
228-
{
229-
sectionTypeDisplayString = Identifier.IConfigurationSection;
230-
exceptionTypeDisplayString = nameof(InvalidOperationException);
231-
}
232-
226+
_writer.WriteLine();
233227
_writer.WriteLine($$"""
234-
if ({{Identifier.configuration}} is not {{sectionTypeDisplayString}} {{Identifier.section}})
228+
namespace System.Runtime.CompilerServices
235229
{
236-
throw new {{exceptionTypeDisplayString}}();
230+
using System;
231+
using System.CodeDom.Compiler;
232+
233+
{{Expression.GeneratedCodeAnnotation}}
234+
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
235+
file sealed class InterceptsLocationAttribute : Attribute
236+
{
237+
public InterceptsLocationAttribute(string filePath, int line, int column)
238+
{
239+
}
240+
}
237241
}
238242
""");
243+
_writer.WriteLine();
244+
}
245+
246+
private void EmitUsingStatements()
247+
{
248+
foreach (string @namespace in _sourceGenSpec.Namespaces.ToImmutableSortedSet())
249+
{
250+
_writer.WriteLine($"using {@namespace};");
251+
}
239252
}
240253

241254
private void EmitIConfigurationHasValueOrChildrenCheck(bool voidReturn)
242255
{
243256
string returnPostfix = voidReturn ? string.Empty : " null";
244-
string methodDisplayString = GetHelperMethodDisplayString(Identifier.HasValueOrChildren);
245-
246257
_writer.WriteLine($$"""
247-
if (!{{methodDisplayString}}({{Identifier.configuration}}))
258+
if (!{{Identifier.HasValueOrChildren}}({{Identifier.configuration}}))
248259
{
249260
return{{returnPostfix}};
250261
}

src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs

+54-15
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
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;
45
using System.Collections.Generic;
56
using System.Collections.Immutable;
67
using System.Diagnostics;
78
using System.Diagnostics.CodeAnalysis;
89
using System.Linq;
910
using Microsoft.CodeAnalysis;
11+
using Microsoft.CodeAnalysis.Operations;
1012

1113
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
1214
{
@@ -147,7 +149,7 @@ type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error ||
147149
{
148150
// List<string> is used in generated code as a temp holder for formatting
149151
// an error for config properties that don't map to object properties.
150-
_sourceGenSpec.TypeNamespaces.Add("System.Collections.Generic");
152+
_sourceGenSpec.Namespaces.Add("System.Collections.Generic");
151153

152154
spec = CreateObjectSpec(namedType);
153155
}
@@ -169,32 +171,54 @@ type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error ||
169171
string @namespace = spec.Namespace;
170172
if (@namespace is not null and not "<global namespace>")
171173
{
172-
_sourceGenSpec.TypeNamespaces.Add(@namespace);
174+
_sourceGenSpec.Namespaces.Add(@namespace);
173175
}
174176

175177
return _createdSpecs[type] = spec;
176178
}
177179

178-
private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type)
180+
private void RegisterTypeForBindCoreMainGen(TypeSpec typeSpec)
179181
{
180-
if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet<TypeSpec>? types))
182+
if (typeSpec.NeedsMemberBinding)
181183
{
182-
_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods[method] = types = new HashSet<TypeSpec>();
184+
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreMain, typeSpec);
185+
RegisterTypeForBindCoreGen(typeSpec);
186+
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren;
183187
}
184-
185-
types.Add(type);
186-
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= method;
187188
}
188189

189-
private void RegisterTypeForBindCoreUntypedGen(TypeSpec typeSpec)
190+
private void RegisterTypeForBindCoreGen(TypeSpec typeSpec)
190191
{
191192
if (typeSpec.NeedsMemberBinding)
192193
{
193194
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, typeSpec);
194-
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreUntyped, typeSpec);
195195
}
196196
}
197197

198+
private void RegisterTypeForGetCoreGen(TypeSpec typeSpec)
199+
{
200+
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec);
201+
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren;
202+
}
203+
204+
private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type)
205+
{
206+
if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet<TypeSpec>? types))
207+
{
208+
_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods[method] = types = new HashSet<TypeSpec>();
209+
}
210+
211+
types.Add(type);
212+
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= method;
213+
}
214+
215+
/// <summary>
216+
/// Registers interceptors for root binding methods, except for ConfigurationBinder.Bind,
217+
/// which is handled by <see cref="RegisterAsInterceptor_ConfigBinder_BindMethod"/>
218+
/// </summary>
219+
private void RegisterAsInterceptor(Enum method, IInvocationOperation operation) =>
220+
_sourceGenSpec.InterceptionInfo.RegisterCacheEntry(method, new InterceptorLocationInfo(operation));
221+
198222
private static bool IsNullable(ITypeSymbol type, [NotNullWhen(true)] out ITypeSymbol? underlyingType)
199223
{
200224
if (type is INamedTypeSymbol { IsGenericType: true } genericType &&
@@ -335,7 +359,7 @@ private bool TryGetTypeSpec(ITypeSymbol type, DiagnosticDescriptor descriptor, o
335359

336360
// We want a BindCore method for List<TElement> as a temp holder for the array values. We know the element type is supported.
337361
EnumerableSpec listSpec = (GetOrCreateTypeSpec(_typeSymbols.List.Construct(arrayType.ElementType)) as EnumerableSpec)!;
338-
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, listSpec);
362+
RegisterTypeForBindCoreGen(listSpec);
339363

340364
EnumerableSpec spec = new EnumerableSpec(arrayType)
341365
{
@@ -347,7 +371,7 @@ private bool TryGetTypeSpec(ITypeSymbol type, DiagnosticDescriptor descriptor, o
347371
};
348372

349373
Debug.Assert(spec.CanInitialize);
350-
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, spec);
374+
RegisterTypeForBindCoreGen(spec);
351375

352376
return spec;
353377
}
@@ -383,7 +407,7 @@ private bool IsSupportedArrayType(ITypeSymbol type)
383407

384408
if (spec is not null)
385409
{
386-
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, spec);
410+
RegisterTypeForBindCoreGen(spec);
387411
spec.InitExceptionMessage ??= spec.ElementType.InitExceptionMessage;
388412
}
389413

@@ -442,7 +466,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k
442466
constructionStrategy = InitializationStrategy.ToEnumerableMethod;
443467
populationStrategy = CollectionPopulationStrategy.Cast_Then_Add;
444468
toEnumerableMethodCall = "ToDictionary(pair => pair.Key, pair => pair.Value)";
445-
_sourceGenSpec.TypeNamespaces.Add("System.Linq");
469+
_sourceGenSpec.Namespaces.Add("System.Linq");
446470
}
447471
else
448472
{
@@ -711,7 +735,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k
711735

712736
if (objectSpec.NeedsMemberBinding)
713737
{
714-
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, objectSpec);
738+
RegisterTypeForBindCoreGen(objectSpec);
715739
}
716740

717741
return objectSpec;
@@ -890,4 +914,19 @@ private void RegisterTypeDiagnostic(ITypeSymbol causingType, InvocationDiagnosti
890914
}
891915
}
892916
}
917+
918+
public static class ParserExtensions
919+
{
920+
public static void RegisterCacheEntry<TKey, TValue, TEntry>(this Dictionary<TKey, TValue> cache, TKey key, TEntry entry)
921+
where TKey : notnull
922+
where TValue : ICollection<TEntry>, new()
923+
{
924+
if (!cache.TryGetValue(key, out TValue? entryCollection))
925+
{
926+
cache[key] = entryCollection = new TValue();
927+
}
928+
929+
entryCollection.Add(entry);
930+
}
931+
}
893932
}

0 commit comments

Comments
 (0)