[release/8.0-rc1] Use Roslyn interceptors feature in binder gen (#90835)
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sat, 19 Aug 2023 16:13:47 +0000 (09:13 -0700)
committerGitHub <noreply@github.com>
Sat, 19 Aug 2023 16:13:47 +0000 (09:13 -0700)
* Use Roslyn interceptors feature in binder gen

* Fix polymorphic issue and address feedback

* Fix source build issue

* Revert changes to options gen

* Fix

* Work around source build issue

Co-authored-by: Eric StJohn <ericstj@microsoft.com>
---------

Co-authored-by: Layomi Akinrinade <laakinri@microsoft.com>
Co-authored-by: Eric StJohn <ericstj@microsoft.com>
67 files changed:
docs/project/list-of-diagnostics.md
eng/SourceBuildPrebuiltBaseline.xml
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs [new file with mode: 0644]
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs [moved from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelper.cs with 83% similarity]
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs [new file with mode: 0644]
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ParsableFromStringSpec.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.Options.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj
src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj
src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj
src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj

index 4f78e9e..579b8d1 100644 (file)
@@ -270,3 +270,5 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
 | Suppression ID           | Suppressed Diagnostic ID | Description |
 | :----------------------- | :----------------------- | :---------- |
 | __`SYSLIBSUPPRESS0001`__ | CA1822                   | Do not offer to make methods static when the methods need to be instance methods for a custom marshaller shape. |
+| __`SYSLIBSUPPRESS0002`__ | IL2026                   | ConfigurationBindingGenerator: suppress RequiresUnreferencedCode diagnostic for binding call that has been intercepted by a generated static variant. |
+| __`SYSLIBSUPPRESS0003`__ | IL3050                   | ConfigurationBindingGenerator: suppress RequiresDynamicCode diagnostic for binding call that has been intercepted by a generated static variant. |
index 74f6be9..46dd745 100644 (file)
@@ -10,6 +10,7 @@
     <UsagePattern IdentityGlob="System.Composition*/*7.*" />
     <UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.4.*" />
     <UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.5.*" />
+    <UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.7.*" />
 
     <!-- Allowed and pinned to major version due to https://github.com/dotnet/source-build/issues/3228 -->
     <UsagePattern IdentityGlob="Microsoft.NETCore.App.Crossgen2.linux-x64/*8.*" />
index a40cf29..756e10b 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
+using System.Collections.Immutable;
 using System.Diagnostics;
 using System.Text.RegularExpressions;
 using Microsoft.CodeAnalysis;
@@ -17,7 +18,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             private readonly SourceGenerationSpec _sourceGenSpec;
 
             private bool _emitBlankLineBeforeNextStatement;
-            private bool _useFullyQualifiedNames;
             private int _valueSuffixIndex;
 
             private static readonly Regex s_arrayBracketsRegex = new(Regex.Escape("[]"));
@@ -32,7 +32,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
             public void Emit()
             {
-                if (!ShouldEmitBinders())
+                if (!ShouldEmitBindingExtensions())
                 {
                     return;
                 }
@@ -42,17 +42,26 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     #nullable enable
                     #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
                     """);
-                _writer.WriteLine();
 
-                _useFullyQualifiedNames = true;
-                EmitBinder_Extensions_IConfiguration();
-                EmitBinder_Extensions_OptionsBuilder();
-                EmitBinder_Extensions_IServiceCollection();
+                EmitInterceptsLocationAttrDecl();
+
+                EmitStartBlock($"namespace {ProjectName}");
+                EmitUsingStatements();
+
+                _writer.WriteLine();
+                EmitStartBlock($$"""
+                    {{Expression.GeneratedCodeAnnotation}}
+                    file static class {{Identifier.BindingExtensions}}
+                    """);
+                EmitBindingExtensions_IConfiguration();
+                EmitBindingExtensions_OptionsBuilder();
+                EmitBindingExtensions_IServiceCollection();
+                EmitCoreBindingHelpers();
+                EmitEndBlock(); // BindingExtensions class
 
-                _useFullyQualifiedNames = false;
-                Emit_CoreBindingHelper();
+                EmitEndBlock(); // Binding namespace.
 
-                _context.AddSource($"{Identifier.GeneratedConfigurationBinder}.g.cs", _writer.ToSourceText());
+                _context.AddSource($"{Identifier.BindingExtensions}.g.cs", _writer.ToSourceText());
             }
 
             private void EmitBindCoreCall(
@@ -74,7 +83,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 if (initKind is InitializationKind.AssignmentWithNullCheck)
                 {
                     Debug.Assert(!type.IsValueType);
-                    _writer.WriteLine($"{type.MinimalDisplayString}? {tempIdentifier} = {memberAccessExpr};");
+                    _writer.WriteLine($"{type.DisplayString}? {tempIdentifier} = {memberAccessExpr};");
                     EmitBindCoreCall(tempIdentifier, InitializationKind.AssignmentWithNullCheck);
                 }
                 else if (initKind is InitializationKind.None && type.IsValueType)
@@ -89,9 +98,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 void EmitBindCoreCall(string objExpression, InitializationKind initKind)
                 {
-                    string methodDisplayString = GetHelperMethodDisplayString(nameof(MethodsToGen_CoreBindingHelper.BindCore));
-                    string bindCoreCall = $@"{methodDisplayString}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});";
-
+                    string bindCoreCall = $@"{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});";
                     EmitObjectInit(objExpression, initKind);
                     _writer.WriteLine(bindCoreCall);
                     writeOnSuccess?.Invoke(objExpression);
@@ -127,12 +134,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 }
                 else if (typeKind is StringParsableTypeKind.Enum)
                 {
-                    parsedValueExpr = $"ParseEnum<{type.MinimalDisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})";
+                    parsedValueExpr = $"ParseEnum<{type.DisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})";
                 }
                 else
                 {
-                    string helperMethodDisplayString = GetHelperMethodDisplayString(type.ParseMethodName);
-                    parsedValueExpr = $"{helperMethodDisplayString}({stringValueToParse_Expr}, () => {sectionPathExpr})";
+                    parsedValueExpr = $"{type.ParseMethodName}({stringValueToParse_Expr}, () => {sectionPathExpr})";
                 }
 
                 if (!checkForNullSectionValue)
@@ -156,7 +162,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 string initExpr;
                 CollectionSpec? collectionType = type as CollectionSpec;
 
-                string effectiveDisplayString = GetTypeDisplayString(type);
+                string effectiveDisplayString = type.DisplayString;
                 if (collectionType is not null)
                 {
                     if (collectionType is EnumerableSpec { InitializationStrategy: InitializationStrategy.Array })
@@ -165,7 +171,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     }
                     else
                     {
-                        effectiveDisplayString = GetTypeDisplayString(collectionType.ConcreteType ?? collectionType);
+                        effectiveDisplayString = (collectionType.ConcreteType ?? collectionType).DisplayString;
                         initExpr = $"new {effectiveDisplayString}()";
                     }
                 }
@@ -215,36 +221,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return true;
             }
 
-            private void EmitCastToIConfigurationSection()
+            private void EmitInterceptsLocationAttrDecl()
             {
-                string sectionTypeDisplayString;
-                string exceptionTypeDisplayString;
-                if (_useFullyQualifiedNames)
-                {
-                    sectionTypeDisplayString = "global::Microsoft.Extensions.Configuration.IConfigurationSection";
-                    exceptionTypeDisplayString = FullyQualifiedDisplayString.InvalidOperationException;
-                }
-                else
-                {
-                    sectionTypeDisplayString = Identifier.IConfigurationSection;
-                    exceptionTypeDisplayString = nameof(InvalidOperationException);
-                }
-
+                _writer.WriteLine();
                 _writer.WriteLine($$"""
-                    if ({{Identifier.configuration}} is not {{sectionTypeDisplayString}} {{Identifier.section}})
+                    namespace System.Runtime.CompilerServices
                     {
-                        throw new {{exceptionTypeDisplayString}}();
+                        using System;
+                        using System.CodeDom.Compiler;
+
+                        {{Expression.GeneratedCodeAnnotation}}
+                        [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+                        file sealed class InterceptsLocationAttribute : Attribute
+                        {
+                            public InterceptsLocationAttribute(string filePath, int line, int column)
+                            {
+                            }
+                        }
                     }
                     """);
+                _writer.WriteLine();
+            }
+
+            private void EmitUsingStatements()
+            {
+                foreach (string @namespace in _sourceGenSpec.Namespaces.ToImmutableSortedSet())
+                {
+                    _writer.WriteLine($"using {@namespace};");
+                }
             }
 
             private void EmitIConfigurationHasValueOrChildrenCheck(bool voidReturn)
             {
                 string returnPostfix = voidReturn ? string.Empty : " null";
-                string methodDisplayString = GetHelperMethodDisplayString(Identifier.HasValueOrChildren);
-
                 _writer.WriteLine($$"""
-                    if (!{{methodDisplayString}}({{Identifier.configuration}}))
+                    if (!{{Identifier.HasValueOrChildren}}({{Identifier.configuration}}))
                     {
                         return{{returnPostfix}};
                     }
index b0f53ef..64db4eb 100644 (file)
@@ -1,12 +1,14 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System;
 using System.Collections.Generic;
 using System.Collections.Immutable;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Operations;
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
@@ -147,7 +149,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 {
                     // List<string> is used in generated code as a temp holder for formatting
                     // an error for config properties that don't map to object properties.
-                    _sourceGenSpec.TypeNamespaces.Add("System.Collections.Generic");
+                    _sourceGenSpec.Namespaces.Add("System.Collections.Generic");
 
                     spec = CreateObjectSpec(namedType);
                 }
@@ -169,32 +171,54 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 string @namespace = spec.Namespace;
                 if (@namespace is not null and not "<global namespace>")
                 {
-                    _sourceGenSpec.TypeNamespaces.Add(@namespace);
+                    _sourceGenSpec.Namespaces.Add(@namespace);
                 }
 
                 return _createdSpecs[type] = spec;
             }
 
-            private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type)
+            private void RegisterTypeForBindCoreMainGen(TypeSpec typeSpec)
             {
-                if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet<TypeSpec>? types))
+                if (typeSpec.NeedsMemberBinding)
                 {
-                    _sourceGenSpec.TypesForGen_CoreBindingHelper_Methods[method] = types = new HashSet<TypeSpec>();
+                    RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreMain, typeSpec);
+                    RegisterTypeForBindCoreGen(typeSpec);
+                    _sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren;
                 }
-
-                types.Add(type);
-                _sourceGenSpec.MethodsToGen_CoreBindingHelper |= method;
             }
 
-            private void RegisterTypeForBindCoreUntypedGen(TypeSpec typeSpec)
+            private void RegisterTypeForBindCoreGen(TypeSpec typeSpec)
             {
                 if (typeSpec.NeedsMemberBinding)
                 {
                     RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, typeSpec);
-                    RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreUntyped, typeSpec);
                 }
             }
 
+            private void RegisterTypeForGetCoreGen(TypeSpec typeSpec)
+            {
+                RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec);
+                _sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren;
+            }
+
+            private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type)
+            {
+                if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet<TypeSpec>? types))
+                {
+                    _sourceGenSpec.TypesForGen_CoreBindingHelper_Methods[method] = types = new HashSet<TypeSpec>();
+                }
+
+                types.Add(type);
+                _sourceGenSpec.MethodsToGen_CoreBindingHelper |= method;
+            }
+
+            /// <summary>
+            /// Registers interceptors for root binding methods, except for ConfigurationBinder.Bind,
+            /// which is handled by <see cref="RegisterAsInterceptor_ConfigBinder_BindMethod"/>
+            /// </summary>
+            private void RegisterAsInterceptor(Enum method, IInvocationOperation operation) =>
+                _sourceGenSpec.InterceptionInfo.RegisterCacheEntry(method, new InterceptorLocationInfo(operation));
+
             private static bool IsNullable(ITypeSymbol type, [NotNullWhen(true)] out ITypeSymbol? underlyingType)
             {
                 if (type is INamedTypeSymbol { IsGenericType: true } genericType &&
@@ -335,7 +359,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 // We want a BindCore method for List<TElement> as a temp holder for the array values. We know the element type is supported.
                 EnumerableSpec listSpec = (GetOrCreateTypeSpec(_typeSymbols.List.Construct(arrayType.ElementType)) as EnumerableSpec)!;
-                RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, listSpec);
+                RegisterTypeForBindCoreGen(listSpec);
 
                 EnumerableSpec spec = new EnumerableSpec(arrayType)
                 {
@@ -347,7 +371,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 };
 
                 Debug.Assert(spec.CanInitialize);
-                RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, spec);
+                RegisterTypeForBindCoreGen(spec);
 
                 return spec;
             }
@@ -383,7 +407,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 if (spec is not null)
                 {
-                    RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, spec);
+                    RegisterTypeForBindCoreGen(spec);
                     spec.InitExceptionMessage ??= spec.ElementType.InitExceptionMessage;
                 }
 
@@ -442,7 +466,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     constructionStrategy = InitializationStrategy.ToEnumerableMethod;
                     populationStrategy = CollectionPopulationStrategy.Cast_Then_Add;
                     toEnumerableMethodCall = "ToDictionary(pair => pair.Key, pair => pair.Value)";
-                    _sourceGenSpec.TypeNamespaces.Add("System.Linq");
+                    _sourceGenSpec.Namespaces.Add("System.Linq");
                 }
                 else
                 {
@@ -711,7 +735,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 if (objectSpec.NeedsMemberBinding)
                 {
-                    RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, objectSpec);
+                    RegisterTypeForBindCoreGen(objectSpec);
                 }
 
                 return objectSpec;
@@ -890,4 +914,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
     }
+
+    public static class ParserExtensions
+    {
+        public static void RegisterCacheEntry<TKey, TValue, TEntry>(this Dictionary<TKey, TValue> cache, TKey key, TEntry entry)
+            where TKey : notnull
+            where TValue : ICollection<TEntry>, new()
+        {
+            if (!cache.TryGetValue(key, out TValue? entryCollection))
+            {
+                cache[key] = entryCollection = new TValue();
+            }
+
+            entryCollection.Add(entry);
+        }
+    }
 }
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs
new file mode 100644 (file)
index 0000000..1315875
--- /dev/null
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Operations;
+
+namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
+{
+    public sealed partial class ConfigurationBindingGenerator
+    {
+        /// <summary>
+        /// Supresses false-positive diagnostics emitted by the linker
+        /// when analyzing binding invocations that we have intercepted.
+        /// Workaround for https://github.com/dotnet/roslyn/issues/68669.
+        /// </summary>
+        [DiagnosticAnalyzer(LanguageNames.CSharp)]
+        public sealed class Suppressor : DiagnosticSuppressor
+        {
+            private const string Justification = "The target method has been intercepted by a generated static variant.";
+
+            /// <summary>
+            /// Suppression descriptor for IL2026: Members attributed with RequiresUnreferencedCode may break when trimming.
+            /// </summary>
+            private static readonly SuppressionDescriptor RUCDiagnostic = new(id: "SYSLIBSUPPRESS0002", suppressedDiagnosticId: "IL2026", Justification);
+
+            /// <summary>
+            /// Suppression descriptor for IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as native AOT.
+            /// </summary>
+            private static readonly SuppressionDescriptor RDCDiagnostic = new(id: "SYSLIBSUPPRESS0003", suppressedDiagnosticId: "IL3050", Justification);
+
+            public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions => ImmutableArray.Create(RUCDiagnostic, RDCDiagnostic);
+
+            public override void ReportSuppressions(SuppressionAnalysisContext context)
+            {
+                foreach (Diagnostic diagnostic in context.ReportedDiagnostics)
+                {
+                    string diagnosticId = diagnostic.Id;
+
+                    if (diagnosticId != RDCDiagnostic.SuppressedDiagnosticId && diagnosticId != RUCDiagnostic.SuppressedDiagnosticId)
+                    {
+                        continue;
+                    }
+
+                    Location location = diagnostic.AdditionalLocations.Count > 0
+                        ? diagnostic.AdditionalLocations[0]
+                        : diagnostic.Location;
+
+                    bool shouldSuppressDiagnostic =
+                        location.SourceTree is SyntaxTree sourceTree &&
+                        sourceTree.GetRoot().FindNode(location.SourceSpan) is SyntaxNode syntaxNode &&
+                        BinderInvocation.IsCandidateSyntaxNode(syntaxNode) &&
+                        context.GetSemanticModel(sourceTree)
+                            .GetOperation((InvocationExpressionSyntax)syntaxNode, context.CancellationToken) is IInvocationOperation operation &&
+                        BinderInvocation.IsBindingOperation(operation);
+
+                    if (shouldSuppressDiagnostic)
+                    {
+                        SuppressionDescriptor targetSuppression = diagnosticId == RUCDiagnostic.SuppressedDiagnosticId
+                                ? RUCDiagnostic
+                                : RDCDiagnostic;
+                        context.ReportSuppression(Suppression.Create(targetSuppression, diagnostic));
+                    }
+                }
+            }
+        }
+    }
+}
index 70da582..fbca2dd 100644 (file)
@@ -5,7 +5,6 @@
 using System.Collections.Immutable;
 using Microsoft.CodeAnalysis;
 using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
@@ -15,7 +14,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     [Generator]
     public sealed partial class ConfigurationBindingGenerator : IIncrementalGenerator
     {
-        internal const string ProjectName = "Microsoft.Extensions.Configuration.Binder.SourceGeneration";
+        private static readonly string ProjectName = Emitter.s_assemblyName.Name;
 
         public void Initialize(IncrementalGeneratorInitializationContext context)
         {
@@ -42,9 +41,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             context.RegisterSourceOutput(inputData, (spc, source) => Execute(source.Item1, source.Item2, spc));
         }
 
-        /// <summary>
-        /// Generates source code to optimize binding with ConfigurationBinder.
-        /// </summary>
         private static void Execute(CompilationData compilationData, ImmutableArray<BinderInvocation> inputCalls, SourceProductionContext context)
         {
             if (inputCalls.IsDefaultOrEmpty)
@@ -73,7 +69,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
             public CompilationData(CSharpCompilation compilation)
             {
-                LanguageVersionIsSupported = compilation.LanguageVersion >= LanguageVersion.CSharp11;
+                // We don't have a CSharp21 value available yet. Polyfill the value here for forward compat, rather than use the LangugeVersion.Preview enum value.
+                // https://github.com/dotnet/roslyn/blob/168689931cb4e3150641ec2fb188a64ce4b3b790/src/Compilers/CSharp/Portable/LanguageVersion.cs#L218-L232
+                const int LangVersion_CSharp12 = 1200;
+                LanguageVersionIsSupported = (int)compilation.LanguageVersion >= LangVersion_CSharp12;
+
                 if (LanguageVersionIsSupported)
                 {
                     TypeSymbols = new KnownTypeSymbols(compilation);
index c10e607..6406488 100644 (file)
@@ -2,9 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using Microsoft.CodeAnalysis;
+using SourceGenerators;
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
@@ -14,91 +12,84 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         {
             private bool ShouldEmitMethods(MethodsToGen_ConfigurationBinder methods) => (_sourceGenSpec.MethodsToGen_ConfigurationBinder & methods) != 0;
 
-            private void EmitBinder_Extensions_IConfiguration()
+            private void EmitBindingExtensions_IConfiguration()
             {
-                Debug.Assert(_sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods.Count <= 3 &&
-                    !_sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods.Keys.Any(overload => (overload & MethodsToGen_ConfigurationBinder.Bind) is 0));
-
                 if (!ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Any))
                 {
                     return;
                 }
 
-                _emitBlankLineBeforeNextStatement = false;
-                EmitRootBindingClassStartBlock(Identifier.GeneratedConfigurationBinder);
-
+                EmitBindingExtStartRegion(Identifier.IConfiguration);
                 EmitGetMethods();
                 EmitGetValueMethods();
                 EmitBindMethods_ConfigurationBinder();
-
-                EmitEndBlock();
-                _emitBlankLineBeforeNextStatement = true;
+                EmitBindingExtEndRegion();
             }
 
             private void EmitGetMethods()
             {
-                const string expressionForGetCore = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.GetCore)}";
+                const string expressionForGetCore = nameof(MethodsToGen_CoreBindingHelper.GetCore);
                 const string documentation = "Attempts to bind the configuration instance to a new instance of type T.";
 
                 if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_T))
                 {
-                    StartMethodDefinition(documentation);
-                    _writer.WriteLine($"public static T? {Identifier.Get}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}) => " +
+                    StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_T, documentation);
+                    _writer.WriteLine($"public static T? {Identifier.Get}<T>(this {Identifier.IConfiguration} {Identifier.configuration}) => " +
                         $"(T?)({expressionForGetCore}({Identifier.configuration}, typeof(T), {Identifier.configureOptions}: null) ?? default(T));");
                 }
 
                 if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_T_BinderOptions))
                 {
-                    StartMethodDefinition(documentation);
-                    _writer.WriteLine($"public static T? {Identifier.Get}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}) => " +
+                    StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_T_BinderOptions, documentation);
+                    _writer.WriteLine($"public static T? {Identifier.Get}<T>(this {Identifier.IConfiguration} {Identifier.configuration}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}) => " +
                         $"(T?)({expressionForGetCore}({Identifier.configuration}, typeof(T), {Identifier.configureOptions}) ?? default(T));");
                 }
 
                 if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf))
                 {
-                    StartMethodDefinition(documentation);
-                    _writer.WriteLine($"public static object? {Identifier.Get}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}) => " +
+                    StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_TypeOf, documentation);
+                    _writer.WriteLine($"public static object? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}) => " +
                         $"{expressionForGetCore}({Identifier.configuration}, {Identifier.type}, {Identifier.configureOptions}: null);");
                 }
 
                 if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions))
                 {
-                    StartMethodDefinition(documentation);
-                    _writer.WriteLine($"public static object? {Identifier.Get}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}) => " +
+                    StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions, documentation);
+                    _writer.WriteLine($"public static object? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}) => " +
                         $"{expressionForGetCore}({Identifier.configuration}, {Identifier.type}, {Identifier.configureOptions});");
                 }
             }
 
             private void EmitGetValueMethods()
             {
-                const string expressionForGetValueCore = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}";
+                const string expressionForGetValueCore = $"{Identifier.BindingExtensions}.{nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}";
                 const string documentation = "Extracts the value with the specified key and converts it to the specified type.";
 
                 if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_T_key))
                 {
-                    StartMethodDefinition(documentation);
-                    _writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, string {Identifier.key}) => " +
+                    StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_T_key, documentation);
+                    _writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {Identifier.IConfiguration} {Identifier.configuration}, string {Identifier.key}) => " +
                         $"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? default(T));");
                 }
 
                 if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_T_key_defaultValue))
                 {
-                    StartMethodDefinition(documentation);
-                    _writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, string {Identifier.key}, T {Identifier.defaultValue}) => " +
+                    StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_T_key_defaultValue, documentation);
+                    _writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {Identifier.IConfiguration} {Identifier.configuration}, string {Identifier.key}, T {Identifier.defaultValue}) => " +
                         $"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? {Identifier.defaultValue});");
                 }
 
                 if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key))
                 {
-                    StartMethodDefinition(documentation);
-                    _writer.WriteLine($"public static object? {Identifier.GetValue}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, string {Identifier.key}) => " +
+                    StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key, documentation);
+                    _writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key}) => " +
                         $"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key});");
                 }
 
                 if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue))
                 {
-                    StartMethodDefinition(documentation);
-                    _writer.WriteLine($"public static object? {Identifier.GetValue}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, string {Identifier.key}, object? {Identifier.defaultValue}) => " +
+                    StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue, documentation);
+                    _writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key}, object? {Identifier.defaultValue}) => " +
                         $"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key}) ?? {Identifier.defaultValue};");
                 }
             }
@@ -110,72 +101,71 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     return;
                 }
 
-                Dictionary<MethodsToGen_ConfigurationBinder, HashSet<TypeSpec>> types = _sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods;
+                string objParamExpr = $"object? {Identifier.obj}";
 
-                if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_instance, out HashSet<TypeSpec>? typeSpecs))
+                if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance))
                 {
-                    foreach (TypeSpec type in typeSpecs)
-                    {
-                        EmitMethodImplementation(
-                            type,
-                            additionalParams: GetObjParameter(type),
-                            configExpression: Identifier.configuration,
-                            configureOptions: false);
-                    }
+                    EmitMethods(
+                        MethodsToGen_ConfigurationBinder.Bind_instance,
+                        additionalParams: objParamExpr,
+                        configExpression: Identifier.configuration,
+                        configureOptions: false);
                 }
 
-                if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions, out typeSpecs))
+                if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions))
                 {
-                    foreach (TypeSpec type in typeSpecs)
-                    {
-                        EmitMethodImplementation(
-                            type,
-                            additionalParams: $"{GetObjParameter(type)}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}",
-                            configExpression: Identifier.configuration,
-                            configureOptions: true);
-                    }
+                    EmitMethods(
+                        MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions,
+                        additionalParams: $"{objParamExpr}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}",
+                        configExpression: Identifier.configuration,
+                        configureOptions: true);
                 }
 
-                if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_key_instance, out typeSpecs))
+                if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_key_instance))
                 {
-                    foreach (TypeSpec type in typeSpecs)
-                    {
-                        EmitMethodImplementation(
-                            type,
-                            additionalParams: $"string {Identifier.key}, {GetObjParameter(type)}",
-                            configExpression: $"{Expression.configurationGetSection}({Identifier.key})",
-                            configureOptions: false);
-                    }
+                    EmitMethods(
+                        MethodsToGen_ConfigurationBinder.Bind_key_instance,
+                        additionalParams: $"string {Identifier.key}, {objParamExpr}",
+                        configExpression: $"{Expression.configurationGetSection}({Identifier.key})",
+                        configureOptions: false);
                 }
 
-                void EmitMethodImplementation(TypeSpec type, string additionalParams, string configExpression, bool configureOptions)
+                void EmitMethods(MethodsToGen_ConfigurationBinder method, string additionalParams, string configExpression, bool configureOptions)
                 {
-                    string binderOptionsArg = configureOptions ? $"{Expression.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null";
-
-                    string returnExpression;
-                    if (type.CanInitialize)
+                    foreach (KeyValuePair<TypeSpec, List<InterceptorLocationInfo>> pair in _sourceGenSpec.InterceptionInfo_ConfigBinder.GetOverloadInfo(method))
                     {
-                        returnExpression = type.NeedsMemberBinding
-                            ? $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configExpression}, ref {Identifier.obj}, {binderOptionsArg})"
-                            : "{ }";
+                        (TypeSpec type, List<InterceptorLocationInfo> interceptorInfoList) = (pair.Key, pair.Value);
+
+                        EmitBlankLineIfRequired();
+                        _writer.WriteLine($"/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>");
+                        EmitInterceptsLocationAnnotations(interceptorInfoList);
+                        EmitStartBlock($"public static void {Identifier.Bind}_{type.DisplayString.ToIdentifierSubstring()}(this {Identifier.IConfiguration} {Identifier.configuration}, {additionalParams})");
+
+                        if (!EmitInitException(type) && type.NeedsMemberBinding)
+                        {
+                            string binderOptionsArg = configureOptions ? $"{Identifier.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null";
+
+                            EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
+                            if (!type.IsValueType)
+                            {
+                                EmitCheckForNullArgument_WithBlankLine(Identifier.obj);
+                            }
+                            _writer.WriteLine($$"""
+                                var {{Identifier.typedObj}} = ({{type.EffectiveType.DisplayString}}){{Identifier.obj}};
+                                {{nameof(MethodsToGen_CoreBindingHelper.BindCore)}}({{configExpression}}, ref {{Identifier.typedObj}}, {{binderOptionsArg}});
+                                """);
+                        }
+
+                        EmitEndBlock();
                     }
-                    else
-                    {
-                        returnExpression = GetInitException(type.InitExceptionMessage);
-                    }
-
-                    StartMethodDefinition("Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.");
-                    _writer.WriteLine($"public static void {Identifier.Bind}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {additionalParams}) => "
-                        + $"{returnExpression};");
                 }
-
-                string GetObjParameter(TypeSpec type) => $"{type.FullyQualifiedDisplayString} {Identifier.obj}";
             }
 
-            private void StartMethodDefinition(string documentation)
+            private void StartMethodDefinition(MethodsToGen_ConfigurationBinder method, string documentation)
             {
                 EmitBlankLineIfRequired();
                 _writer.WriteLine($"/// <summary>{documentation}</summary>");
+                EmitInterceptsLocationAnnotations(method);
             }
         }
     }
@@ -3,10 +3,10 @@
 
 using System;
 using System.Collections.Generic;
-using System.Collections.Immutable;
 using System.Diagnostics;
 using System.Linq;
 using Microsoft.CodeAnalysis;
+using SourceGenerators;
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
@@ -16,41 +16,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         {
             private bool ShouldEmitMethods(MethodsToGen_CoreBindingHelper methods) => (_sourceGenSpec.MethodsToGen_CoreBindingHelper & methods) != 0;
 
-            private void Emit_CoreBindingHelper()
+            private void EmitCoreBindingHelpers()
             {
                 Debug.Assert(_emitBlankLineBeforeNextStatement);
-                _writer.WriteLine();
-                _emitBlankLineBeforeNextStatement = false;
-
-                EmitStartBlock($"namespace {ProjectName}");
-                EmitHelperUsingStatements();
-
-                _writer.WriteLine();
-
-                EmitStartBlock($$"""
-                    /// <summary>Provide core binding logic.</summary>
-                    {{GetGeneratedCodeAttributeSrc()}}
-                    file static class {{Identifier.CoreBindingHelper}}
-                    """);
-
+                EmitBindingExtStartRegion("Core binding");
                 EmitConfigurationKeyCaches();
                 EmitGetCoreMethod();
                 EmitGetValueCoreMethod();
-                EmitBindCoreUntypedMethod();
+                EmitBindCoreMainMethod();
                 EmitBindCoreMethods();
                 EmitInitializeMethods();
                 EmitHelperMethods();
-
-                EmitEndBlock(); // End helper class.
-                EmitEndBlock(); // End namespace.
-            }
-
-            private void EmitHelperUsingStatements()
-            {
-                foreach (string @namespace in _sourceGenSpec.TypeNamespaces.ToImmutableSortedSet())
-                {
-                    _writer.WriteLine($"using {@namespace};");
-                }
+                EmitBindingExtEndRegion();
             }
 
             private void EmitConfigurationKeyCaches()
@@ -60,6 +37,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     return;
                 }
 
+                EmitBlankLineIfRequired();
+
                 foreach (TypeSpec type in targetTypes)
                 {
                     if (type is not ObjectSpec objectType)
@@ -73,10 +52,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                     string configKeysSource = string.Join(", ", keys);
                     string fieldName = GetConfigKeyCacheFieldName(objectType);
-                    _writer.WriteLine($@"private readonly static Lazy<{MinimalDisplayString.HashSetOfString}> {fieldName} = new(() => new {MinimalDisplayString.HashSetOfString}(StringComparer.OrdinalIgnoreCase) {{ {configKeysSource} }});");
+                    _writer.WriteLine($@"private readonly static Lazy<{TypeDisplayString.HashSetOfString}> {fieldName} = new(() => new {TypeDisplayString.HashSetOfString}(StringComparer.OrdinalIgnoreCase) {{ {configKeysSource} }});");
                 }
-
-                _emitBlankLineBeforeNextStatement = true;
             }
 
             private void EmitGetCoreMethod()
@@ -96,16 +73,24 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 EmitIConfigurationHasValueOrChildrenCheck(voidReturn: false);
 
+                bool isFirstType = true;
                 foreach (TypeSpec type in types)
                 {
                     TypeSpec effectiveType = type.EffectiveType;
                     TypeSpecKind kind = effectiveType.SpecKind;
+                    string conditionKindExpr = GetConditionKindExpr(ref isFirstType);
 
-                    EmitStartBlock($"if (type == typeof({type.MinimalDisplayString}))");
+                    EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))");
 
                     if (effectiveType is ParsableFromStringSpec stringParsableType)
                     {
-                        EmitCastToIConfigurationSection();
+                        _writer.WriteLine($$"""
+                            if ({{Identifier.configuration}} is not {{Identifier.IConfigurationSection}} {{Identifier.section}})
+                            {
+                                throw new {{Identifier.InvalidOperationException}}();
+                            }
+                            """);
+
                         EmitBindLogicFromString(
                             stringParsableType,
                             Expression.sectionValue,
@@ -121,9 +106,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     }
 
                     EmitEndBlock();
-                    _writer.WriteLine();
                 }
 
+                _writer.WriteLine();
                 Emit_NotSupportedException_TypeNotDetectedAsInput();
                 EmitEndBlock();
                 _emitBlankLineBeforeNextStatement = true;
@@ -152,9 +137,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 _writer.WriteLine();
 
+                bool isFirstType = true;
                 foreach (TypeSpec type in targetTypes)
                 {
-                    EmitStartBlock($"if ({Identifier.type} == typeof({type.MinimalDisplayString}))");
+                    string conditionKindExpr = GetConditionKindExpr(ref isFirstType);
+                    EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))");
 
                     EmitBindLogicFromString(
                         (ParsableFromStringSpec)type.EffectiveType,
@@ -165,51 +152,48 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                         useIncrementalStringValueIdentifier: false);
 
                     EmitEndBlock();
-                    _writer.WriteLine();
                 }
 
+                _writer.WriteLine();
                 _writer.WriteLine("return null;");
                 EmitEndBlock();
                 _emitBlankLineBeforeNextStatement = true;
             }
 
-            private void EmitBindCoreUntypedMethod()
+            private void EmitBindCoreMainMethod()
             {
-                if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(MethodsToGen_CoreBindingHelper.BindCoreUntyped, out HashSet<TypeSpec>? targetTypes))
+                if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(MethodsToGen_CoreBindingHelper.BindCoreMain, out HashSet<TypeSpec>? targetTypes))
                 {
                     return;
                 }
 
                 EmitBlankLineIfRequired();
-
-                EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}(this {Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.obj}, Type {Identifier.type}, {MinimalDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})");
-
+                EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}({Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.obj}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})");
                 EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
-
+                EmitCheckForNullArgument_WithBlankLine(Identifier.obj);
+                EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true);
                 _writer.WriteLine($"{Identifier.BinderOptions}? {Identifier.binderOptions} = {Identifier.GetBinderOptions}({Identifier.configureOptions});");
                 _writer.WriteLine();
 
-                EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true);
-
+                bool isFirstType = true;
                 foreach (TypeSpec type in targetTypes)
                 {
-                    EmitStartBlock($"if (type == typeof({type.MinimalDisplayString}))");
-
                     TypeSpec effectiveType = type.EffectiveType;
+                    string conditionKindExpr = GetConditionKindExpr(ref isFirstType);
+
+                    EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))");
                     if (!EmitInitException(effectiveType))
                     {
-                        _writer.WriteLine($"var {Identifier.temp} = ({effectiveType.MinimalDisplayString}){Identifier.obj};");
+                        _writer.WriteLine($"var {Identifier.temp} = ({effectiveType.DisplayString}){Identifier.obj};");
                         EmitBindCoreCall(type, Identifier.temp, Identifier.configuration, InitializationKind.None);
                         _writer.WriteLine($"return;");
                     }
-
                     EmitEndBlock();
-                    _writer.WriteLine();
                 }
 
+                _writer.WriteLine();
                 Emit_NotSupportedException_TypeNotDetectedAsInput();
                 EmitEndBlock();
-                _emitBlankLineBeforeNextStatement = true;
             }
 
             private void EmitBindCoreMethods()
@@ -231,11 +215,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             {
                 Debug.Assert(type.CanInitialize);
 
-                string objParameterExpression = $"ref {type.MinimalDisplayString} {Identifier.obj}";
+                string objParameterExpression = $"ref {type.DisplayString} {Identifier.obj}";
                 EmitStartBlock(@$"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCore)}({Identifier.IConfiguration} {Identifier.configuration}, {objParameterExpression}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
 
-                EmitCheckForNullArgument_WithBlankLine_IfRequired(type.IsValueType);
-
                 TypeSpec effectiveType = type.EffectiveType;
                 if (effectiveType is EnumerableSpec enumerable)
                 {
@@ -281,9 +263,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 List<ParameterSpec> ctorParams = type.ConstructorParameters;
                 IEnumerable<PropertySpec> initOnlyProps = type.Properties.Values.Where(prop => prop is { SetOnInit: true });
                 List<string> ctorArgList = new();
-                string displayString = type.MinimalDisplayString;
+                string displayString = type.DisplayString;
 
-                EmitStartBlock($"public static {type.MinimalDisplayString} {GetInitalizeMethodDisplayString(type)}({Identifier.IConfiguration} {Identifier.configuration}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
+                EmitStartBlock($"public static {type.DisplayString} {GetInitalizeMethodDisplayString(type)}({Identifier.IConfiguration} {Identifier.configuration}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
                 _emitBlankLineBeforeNextStatement = false;
 
                 foreach (ParameterSpec parameter in ctorParams)
@@ -335,7 +317,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     TypeSpec memberType = member.Type;
                     bool errorOnFailedBinding = member.ErrorOnFailedBinding;
 
-                    string parsedMemberIdentifierDeclarationPrefix = $"{memberType.MinimalDisplayString} {member.Name}";
+                    string parsedMemberIdentifierDeclarationPrefix = $"{memberType.DisplayString} {member.Name}";
                     string parsedMemberIdentifier;
 
                     if (memberType is ParsableFromStringSpec { StringParsableTypeKind: StringParsableTypeKind.AssignFromSectionValue })
@@ -344,7 +326,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                         if (errorOnFailedBinding)
                         {
-                            string condition = $@" if ({Identifier.configuration}[""{member.ConfigurationKeyName}""] is not {memberType.MinimalDisplayString} {member.Name})";
+                            string condition = $@" if ({Identifier.configuration}[""{member.ConfigurationKeyName}""] is not {memberType.DisplayString} {member.Name})";
                             EmitThrowBlock(condition);
                             _writer.WriteLine();
                             return;
@@ -393,40 +375,42 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                         _writer.WriteLine($$"""
                             {{condition}}
                             {
-                                throw new {{GetInvalidOperationDisplayName()}}("{{string.Format(ExceptionMessages.ParameterHasNoMatchingConfig, type.Name, member.Name)}}");
+                                throw new {{Identifier.InvalidOperationException}}("{{string.Format(ExceptionMessages.ParameterHasNoMatchingConfig, type.Name, member.Name)}}");
                             }
                             """);
                 }
             }
+
             private void EmitHelperMethods()
             {
+                // Emitted if we are to bind objects with complex members, or if we're emitting BindCoreMain or GetCore methods.
+                bool emitAsConfigWithChildren = ShouldEmitMethods(MethodsToGen_CoreBindingHelper.AsConfigWithChildren);
+
                 if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCore))
                 {
+                    EmitBlankLineIfRequired();
                     EmitValidateConfigurationKeysMethod();
                 }
 
-                if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreUntyped | MethodsToGen_CoreBindingHelper.GetCore))
+                if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreMain | MethodsToGen_CoreBindingHelper.GetCore))
                 {
-                    _writer.WriteLine();
+                    // HasValueOrChildren references this method.
+                    Debug.Assert(emitAsConfigWithChildren);
+                    EmitBlankLineIfRequired();
                     EmitHasValueOrChildrenMethod();
-                    _writer.WriteLine();
-                    EmitAsConfigWithChildrenMethod();
-                    _emitBlankLineBeforeNextStatement = true;
                 }
-                else if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.AsConfigWithChildren))
+
+                if (emitAsConfigWithChildren)
                 {
-                    _writer.WriteLine();
+                    EmitBlankLineIfRequired();
                     EmitAsConfigWithChildrenMethod();
-                    _emitBlankLineBeforeNextStatement = true;
                 }
 
-                if (ShouldEmitMethods(
-                    MethodsToGen_CoreBindingHelper.BindCoreUntyped | MethodsToGen_CoreBindingHelper.GetCore) ||
+                if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreMain | MethodsToGen_CoreBindingHelper.GetCore) ||
                     ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions))
                 {
-                    _writer.WriteLine();
+                    EmitBlankLineIfRequired();
                     EmitGetBinderOptionsHelper();
-                    _emitBlankLineBeforeNextStatement = true;
                 }
 
                 bool enumTypeExists = false;
@@ -458,17 +442,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 EmitBlankLineIfRequired();
                 _writer.WriteLine($$"""
                     /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
-                    public static void {{Identifier.ValidateConfigurationKeys}}(Type {{Identifier.type}}, {{MinimalDisplayString.LazyHashSetOfString}} {{keysIdentifier}}, {{Identifier.IConfiguration}} {{Identifier.configuration}}, {{Identifier.BinderOptions}}? {{Identifier.binderOptions}})
+                    public static void {{Identifier.ValidateConfigurationKeys}}(Type {{Identifier.type}}, {{TypeDisplayString.LazyHashSetOfString}} {{keysIdentifier}}, {{Identifier.IConfiguration}} {{Identifier.configuration}}, {{Identifier.BinderOptions}}? {{Identifier.binderOptions}})
                     {
                         if ({{Identifier.binderOptions}}?.{{Identifier.ErrorOnUnknownConfiguration}} is true)
                         {
-                            {{MinimalDisplayString.ListOfString}}? {{Identifier.temp}} = null;
+                            {{TypeDisplayString.ListOfString}}? {{Identifier.temp}} = null;
                     
                             foreach ({{Identifier.IConfigurationSection}} {{Identifier.section}} in {{Identifier.configuration}}.{{Identifier.GetChildren}}())
                             {
                                 if (!{{keysIdentifier}}.Value.Contains({{Expression.sectionKey}}))
                                 {
-                                    ({{Identifier.temp}} ??= new {{MinimalDisplayString.ListOfString}}()).Add($"'{{{Expression.sectionKey}}}'");
+                                    ({{Identifier.temp}} ??= new {{TypeDisplayString.ListOfString}}()).Add($"'{{{Expression.sectionKey}}}'");
                                 }
                             }
 
@@ -490,7 +474,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                         {
                             return true;
                         }
-                        return {{Identifier.AsConfigWithChildren}}({{Identifier.configuration}}) is not null;
+                        return {{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}}({{Identifier.configuration}}) is not null;
                     }
                     """);
             }
@@ -498,7 +482,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             private void EmitAsConfigWithChildrenMethod()
             {
                 _writer.WriteLine($$"""
-                    public static {{Identifier.IConfiguration}}? {{Identifier.AsConfigWithChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}})
+                    public static {{Identifier.IConfiguration}}? {{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}})
                     {
                         foreach ({{Identifier.IConfigurationSection}} _ in {{Identifier.configuration}}.{{Identifier.GetChildren}}())
                         {
@@ -512,7 +496,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             private void EmitGetBinderOptionsHelper()
             {
                 _writer.WriteLine($$"""
-                    public static {{Identifier.BinderOptions}}? {{Identifier.GetBinderOptions}}({{MinimalDisplayString.NullableActionOfBinderOptions}} {{Identifier.configureOptions}})
+                    public static {{Identifier.BinderOptions}}? {{Identifier.GetBinderOptions}}({{TypeDisplayString.NullableActionOfBinderOptions}} {{Identifier.configureOptions}})
                     {
                         if ({{Identifier.configureOptions}} is null)
                         {
@@ -524,7 +508,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                         if ({{Identifier.binderOptions}}.BindNonPublicProperties)
                         {
-                            throw new global::System.NotSupportedException($"{{string.Format(ExceptionMessages.CannotSpecifyBindNonPublicProperties)}}");
+                            throw new NotSupportedException($"{{string.Format(ExceptionMessages.CannotSpecifyBindNonPublicProperties)}}");
                         }
 
                         return {{Identifier.binderOptions}};
@@ -534,7 +518,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
             private void EmitEnumParseMethod()
             {
-                string innerExceptionTypeDisplayString = _useFullyQualifiedNames ? "global::System.Exception" : "Exception";
                 string exceptionArg1 = string.Format(ExceptionMessages.FailedBinding, $"{{{Identifier.getPath}()}}", $"{{typeof(T)}}");
 
                 _writer.WriteLine($$"""
@@ -548,9 +531,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                                 return Enum.Parse<T>(value, ignoreCase: true);
                             #endif
                         }
-                        catch ({{innerExceptionTypeDisplayString}} {{Identifier.exception}})
+                        catch ({{Identifier.Exception}} {{Identifier.exception}})
                         {
-                            throw new {{GetInvalidOperationDisplayName()}}($"{{exceptionArg1}}", {{Identifier.exception}});
+                            throw new {{Identifier.InvalidOperationException}}($"{{exceptionArg1}}", {{Identifier.exception}});
                         }
                     }
                     """);
@@ -558,29 +541,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
             private void EmitPrimitiveParseMethod(ParsableFromStringSpec type)
             {
-                string innerExceptionTypeDisplayString;
-                string cultureInfoTypeDisplayString;
-                string numberStylesTypeDisplayString;
-
-                if (_useFullyQualifiedNames)
-                {
-                    innerExceptionTypeDisplayString = "global::System.Exception";
-                    cultureInfoTypeDisplayString = "global::System.Globalization.CultureInfo";
-                    numberStylesTypeDisplayString = "global::System.Globalization.NumberStyles";
-                }
-                else
-                {
-                    innerExceptionTypeDisplayString = "Exception";
-                    cultureInfoTypeDisplayString = "CultureInfo";
-                    numberStylesTypeDisplayString = "NumberStyles";
-                }
-
                 StringParsableTypeKind typeKind = type.StringParsableTypeKind;
-                string typeDisplayString = type.MinimalDisplayString;
-
-                string invariantCultureExpression = $"{cultureInfoTypeDisplayString}.InvariantCulture";
+                string typeDisplayString = type.DisplayString;
 
+                string invariantCultureExpression = $"{Identifier.CultureInfo}.InvariantCulture";
                 string parsedValueExpr;
+
                 switch (typeKind)
                 {
                     case StringParsableTypeKind.Enum:
@@ -592,12 +558,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                         break;
                     case StringParsableTypeKind.Integer:
                         {
-                            parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {numberStylesTypeDisplayString}.Integer, {invariantCultureExpression})";
+                            parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {Identifier.NumberStyles}.Integer, {invariantCultureExpression})";
                         }
                         break;
                     case StringParsableTypeKind.Float:
                         {
-                            parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {numberStylesTypeDisplayString}.Float, {invariantCultureExpression})";
+                            parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {Identifier.NumberStyles}.Float, {invariantCultureExpression})";
                         }
                         break;
                     case StringParsableTypeKind.Parse:
@@ -612,7 +578,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                         break;
                     case StringParsableTypeKind.CultureInfo:
                         {
-                            parsedValueExpr = $"{cultureInfoTypeDisplayString}.GetCultureInfo({Identifier.value})";
+                            parsedValueExpr = $"{Identifier.CultureInfo}.GetCultureInfo({Identifier.value})";
                         }
                         break;
                     case StringParsableTypeKind.Uri:
@@ -635,9 +601,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     {
                         return {{parsedValueExpr}};
                     }
-                    catch ({{innerExceptionTypeDisplayString}} {{Identifier.exception}})
+                    catch ({{Identifier.Exception}} {{Identifier.exception}})
                     {
-                        throw new {{GetInvalidOperationDisplayName()}}($"{{exceptionArg1}}", {{Identifier.exception}});
+                        throw new {{Identifier.InvalidOperationException}}($"{{exceptionArg1}}", {{Identifier.exception}});
                     }
                     """);
             }
@@ -722,13 +688,13 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                         if (keyType.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue)
                         {
                             // Save value to local to avoid parsing twice - during look-up and during add.
-                            _writer.WriteLine($"{keyType.MinimalDisplayString} {Identifier.key} = {parsedKeyExpr};");
+                            _writer.WriteLine($"{keyType.DisplayString} {Identifier.key} = {parsedKeyExpr};");
                             parsedKeyExpr = Identifier.key;
                         }
 
                         bool isValueType = elementType.IsValueType;
                         string expressionForElementIsNotNull = $"{Identifier.element} is not null";
-                        string elementTypeDisplayString = elementType.MinimalDisplayString + (elementType.IsValueType ? string.Empty : "?");
+                        string elementTypeDisplayString = elementType.DisplayString + (elementType.IsValueType ? string.Empty : "?");
 
                         string expressionForElementExists = $"{objIdentifier}.{Identifier.TryGetValue}({parsedKeyExpr}, out {elementTypeDisplayString} {Identifier.element})";
                         string conditionToUseExistingElement = expressionForElementExists;
@@ -749,7 +715,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                             // we need to copy its contents into a new instance & then append/bind to that.
 
                             string initExpression = collectionSpec.InitializationStrategy is InitializationStrategy.ParameterizedConstructor
-                                ? $"new {collectionSpec.ConcreteType.MinimalDisplayString}({Identifier.element})"
+                                ? $"new {collectionSpec.ConcreteType.DisplayString}({Identifier.element})"
                                 : $"{Identifier.element}.{collectionSpec.ToEnumerableMethodCall!}";
 
                             _writer.WriteLine($$"""
@@ -773,7 +739,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 Debug.Assert(type.NeedsMemberBinding);
 
                 string keyCacheFieldName = GetConfigKeyCacheFieldName(type);
-                string validateMethodCallExpr = $"{Identifier.ValidateConfigurationKeys}(typeof({type.MinimalDisplayString}), {keyCacheFieldName}, {Identifier.configuration}, {Identifier.binderOptions});";
+                string validateMethodCallExpr = $"{Identifier.ValidateConfigurationKeys}(typeof({type.DisplayString}), {keyCacheFieldName}, {Identifier.configuration}, {Identifier.binderOptions});";
                 _writer.WriteLine(validateMethodCallExpr);
 
                 foreach (PropertySpec property in type.Properties.Values)
@@ -781,7 +747,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     bool noSetter_And_IsReadonly = !property.CanSet && property.Type is CollectionSpec { InitializationStrategy: InitializationStrategy.ParameterizedConstructor };
                     if (property.ShouldBind() && !noSetter_And_IsReadonly)
                     {
-                        string containingTypeRef = property.IsStatic ? type.MinimalDisplayString : Identifier.obj;
+                        string containingTypeRef = property.IsStatic ? type.DisplayString : Identifier.obj;
                         EmitBindImplForMember(
                             property,
                             memberAccessExpr: $"{containingTypeRef}.{property.Name}",
@@ -832,7 +798,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     return true;
                 }
 
-                string sectionValidationCall = $"{Identifier.AsConfigWithChildren}({sectionParseExpr})";
+                string sectionValidationCall = $"{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}({sectionParseExpr})";
                 string sectionIdentifier = GetIncrementalIdentifier(Identifier.section);
 
                 EmitStartBlock($"if ({sectionValidationCall} is {Identifier.IConfigurationSection} {sectionIdentifier})");
@@ -869,14 +835,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     }
 
                     Debug.Assert(canSet);
-                    string effectiveMemberTypeDisplayString = effectiveMemberType.MinimalDisplayString;
+                    string effectiveMemberTypeDisplayString = effectiveMemberType.DisplayString;
                     initKind = InitializationKind.None;
 
                     if (memberType.SpecKind is TypeSpecKind.Nullable)
                     {
                         string nullableTempIdentifier = GetIncrementalIdentifier(Identifier.temp);
 
-                        _writer.WriteLine($"{memberType.MinimalDisplayString} {nullableTempIdentifier} = {memberAccessExpr};");
+                        _writer.WriteLine($"{memberType.DisplayString} {nullableTempIdentifier} = {memberAccessExpr};");
 
                         _writer.WriteLine(
                             $"{effectiveMemberTypeDisplayString} {tempIdentifier} = {nullableTempIdentifier}.{Identifier.HasValue} ? {nullableTempIdentifier}.{Identifier.Value} : new {effectiveMemberTypeDisplayString}();");
@@ -924,7 +890,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 {
                     objIdentifier = Identifier.temp;
                     _writer.WriteLine($$"""
-                        if ({{Identifier.obj}} is not {{type.PopulationCastType!.MinimalDisplayString}} {{objIdentifier}})
+                        if ({{Identifier.obj}} is not {{type.PopulationCastType!.DisplayString}} {{objIdentifier}})
                         {
                             return;
                         }
@@ -936,20 +902,31 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             private void Emit_Foreach_Section_In_ConfigChildren_StartBlock() =>
                 EmitStartBlock($"foreach ({Identifier.IConfigurationSection} {Identifier.section} in {Identifier.configuration}.{Identifier.GetChildren}())");
 
+            private void Emit_NotSupportedException_TypeNotDetectedAsInput() =>
+                _writer.WriteLine(@$"throw new NotSupportedException($""{string.Format(ExceptionMessages.TypeNotDetectedAsInput, "{type}")}"");");
+
             private static string GetSectionPathFromConfigurationExpression(string configurationKeyName)
                 => $@"{GetSectionFromConfigurationExpression(configurationKeyName)}.{Identifier.Path}";
 
             private static string GetSectionFromConfigurationExpression(string configurationKeyName, bool addQuotes = true)
             {
                 string argExpr = addQuotes ? $@"""{configurationKeyName}""" : configurationKeyName;
-                return $@"{Expression.configurationGetSection}({argExpr})";
+                return $@"{Identifier.configuration}.{Identifier.GetSection}({argExpr})";
             }
 
-            private static string GetConfigKeyCacheFieldName(ObjectSpec type) =>
-                $"s_configKeys_{type.DisplayStringWithoutSpecialCharacters}";
+            private static string GetConditionKindExpr(ref bool isFirstType)
+            {
+                if (isFirstType)
+                {
+                    isFirstType = false;
+                    return "if";
+                }
 
-            private void Emit_NotSupportedException_TypeNotDetectedAsInput() =>
-                _writer.WriteLine(@$"throw new global::System.NotSupportedException($""{string.Format(ExceptionMessages.TypeNotDetectedAsInput, "{type}")}"");");
+                return "else if";
+            }
+
+            private static string GetConfigKeyCacheFieldName(ObjectSpec type) =>
+                $"s_configKeys_{type.DisplayString.ToIdentifierSubstring()}";
         }
     }
 }
index e0e6a36..bad56b7 100644 (file)
@@ -1,6 +1,8 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System;
+using System.Collections.Generic;
 using System.Diagnostics;
 using System.Reflection;
 
@@ -10,7 +12,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     {
         private sealed partial class Emitter
         {
-            private static readonly AssemblyName s_assemblyName = typeof(Emitter).Assembly.GetName();
+            private string? _emittedExtsTargetType;
+
+            internal static readonly AssemblyName s_assemblyName = typeof(ConfigurationBindingGenerator).Assembly.GetName();
 
             private enum InitializationKind
             {
@@ -26,29 +30,13 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 public const string sectionPath = "section.Path";
                 public const string sectionValue = "section.Value";
 
-                public const string GetBinderOptions = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{Identifier.GetBinderOptions}";
-            }
-
-            private static class FullyQualifiedDisplayString
-            {
-                public const string ActionOfBinderOptions = $"global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>";
-                public const string AddSingleton = $"{ServiceCollectionServiceExtensions}.AddSingleton";
-                public const string ConfigurationChangeTokenSource = "global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource";
-                public const string CoreBindingHelper = $"global::{ProjectName}.{Identifier.CoreBindingHelper}";
-                public const string IConfiguration = "global::Microsoft.Extensions.Configuration.IConfiguration";
-                public const string IConfigurationSection = IConfiguration + "Section";
-                public const string IOptionsChangeTokenSource = "global::Microsoft.Extensions.Options.IOptionsChangeTokenSource";
-                public const string InvalidOperationException = "global::System.InvalidOperationException";
-                public const string IServiceCollection = "global::Microsoft.Extensions.DependencyInjection.IServiceCollection";
-                public const string NotSupportedException = "global::System.NotSupportedException";
-                public const string OptionsBuilderOfTOptions = $"global::Microsoft.Extensions.Options.OptionsBuilder<{Identifier.TOptions}>";
-                public const string ServiceCollectionServiceExtensions = "global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions";
-                public const string Type = $"global::System.Type";
+                public static string GeneratedCodeAnnotation = $@"[GeneratedCode(""{s_assemblyName.Name}"", ""{s_assemblyName.Version}"")]";
             }
 
-            private static class MinimalDisplayString
+            private static class TypeDisplayString
             {
                 public const string NullableActionOfBinderOptions = "Action<BinderOptions>?";
+                public const string OptionsBuilderOfTOptions = $"OptionsBuilder<{Identifier.TOptions}>";
                 public const string HashSetOfString = "HashSet<string>";
                 public const string LazyHashSetOfString = "Lazy<HashSet<string>>";
                 public const string ListOfString = "List<string>";
@@ -75,6 +63,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 public const string services = nameof(services);
                 public const string temp = nameof(temp);
                 public const string type = nameof(type);
+                public const string typedObj = nameof(typedObj);
                 public const string validateKeys = nameof(validateKeys);
                 public const string value = nameof(value);
 
@@ -82,21 +71,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 public const string AddSingleton = nameof(AddSingleton);
                 public const string Any = nameof(Any);
                 public const string Array = nameof(Array);
-                public const string AsConfigWithChildren = nameof(AsConfigWithChildren);
                 public const string Bind = nameof(Bind);
                 public const string BinderOptions = nameof(BinderOptions);
+                public const string BindingExtensions = nameof(BindingExtensions);
+                public const string ConfigurationChangeTokenSource = nameof(ConfigurationChangeTokenSource);
                 public const string Configure = nameof(Configure);
                 public const string CopyTo = nameof(CopyTo);
                 public const string ContainsKey = nameof(ContainsKey);
-                public const string CoreBindingHelper = nameof(CoreBindingHelper);
                 public const string Count = nameof(Count);
                 public const string CultureInfo = nameof(CultureInfo);
                 public const string CultureNotFoundException = nameof(CultureNotFoundException);
                 public const string Enum = nameof(Enum);
                 public const string ErrorOnUnknownConfiguration = nameof(ErrorOnUnknownConfiguration);
-                public const string GeneratedConfigurationBinder = nameof(GeneratedConfigurationBinder);
-                public const string GeneratedOptionsBuilderBinder = nameof(GeneratedOptionsBuilderBinder);
-                public const string GeneratedServiceCollectionBinder = nameof(GeneratedServiceCollectionBinder);
+                public const string Exception = nameof(Exception);
                 public const string Get = nameof(Get);
                 public const string GetBinderOptions = nameof(GetBinderOptions);
                 public const string GetChildren = nameof(GetChildren);
@@ -108,9 +95,13 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 public const string IConfiguration = nameof(IConfiguration);
                 public const string IConfigurationSection = nameof(IConfigurationSection);
                 public const string Int32 = "int";
+                public const string InterceptsLocation = nameof(InterceptsLocation);
                 public const string InvalidOperationException = nameof(InvalidOperationException);
                 public const string InvariantCulture = nameof(InvariantCulture);
+                public const string IOptionsChangeTokenSource = nameof(IOptionsChangeTokenSource);
+                public const string IServiceCollection = nameof(IServiceCollection);
                 public const string Length = nameof(Length);
+                public const string NumberStyles = nameof(NumberStyles);
                 public const string Parse = nameof(Parse);
                 public const string Path = nameof(Path);
                 public const string Resize = nameof(Resize);
@@ -118,17 +109,66 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 public const string TOptions = nameof(TOptions);
                 public const string TryCreate = nameof(TryCreate);
                 public const string TryGetValue = nameof(TryGetValue);
-                public const string TryParse = nameof(TryParse);
+                public const string Type = nameof(Type);
                 public const string Uri = nameof(Uri);
                 public const string ValidateConfigurationKeys = nameof(ValidateConfigurationKeys);
                 public const string Value = nameof(Value);
             }
 
-            private bool ShouldEmitBinders() =>
+            private bool ShouldEmitBindingExtensions() =>
                 ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Any) ||
                 ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any) ||
                 ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any);
 
+            private void EmitInterceptsLocationAnnotations(Enum generatedBindingOverload)
+            {
+                // The only time a generated binding method won't have any locations to
+                // intercept is when either of these methods are used as helpers for
+                // other generated OptionsBuilder or ServiceCollection binding extensions.
+                bool interceptsCalls = _sourceGenSpec.InterceptionInfo.TryGetValue(generatedBindingOverload, out List<InterceptorLocationInfo>? infoList);
+                Debug.Assert(interceptsCalls ||
+                    generatedBindingOverload is MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions ||
+                    generatedBindingOverload is MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions);
+
+                if (interceptsCalls)
+                {
+                    EmitInterceptsLocationAnnotations(infoList);
+                }
+            }
+
+            private void EmitInterceptsLocationAnnotations(List<InterceptorLocationInfo> infoList)
+            {
+                foreach (InterceptorLocationInfo info in infoList)
+                {
+                    _writer.WriteLine($@"[{Identifier.InterceptsLocation}Attribute(@""{info.FilePath}"", {info.LineNumber}, {info.CharacterNumber})]");
+                }
+            }
+
+            private void EmitBindingExtStartRegion(string targetType)
+            {
+                Debug.Assert(_emittedExtsTargetType is null);
+
+                EmitBlankLineIfRequired();
+                _emittedExtsTargetType = targetType;
+                EmitBindingExtRegionText(isStart: true);
+                _emitBlankLineBeforeNextStatement = false;
+            }
+
+            private void EmitBindingExtEndRegion()
+            {
+                Debug.Assert(_emittedExtsTargetType is not null);
+
+                EmitBindingExtRegionText(isStart: false);
+                _emittedExtsTargetType = null;
+                _emitBlankLineBeforeNextStatement = true;
+            }
+
+            private void EmitBindingExtRegionText(bool isStart)
+            {
+                string endSource = isStart ? string.Empty : "end";
+                _writer.WriteLine($"#{endSource}region {_emittedExtsTargetType} extensions.");
+            }
+
             /// <summary>
             /// Starts a block of source code.
             /// </summary>
@@ -171,24 +211,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 _emitBlankLineBeforeNextStatement = true;
             }
 
-            private void EmitCheckForNullArgument_WithBlankLine_IfRequired(bool isValueType)
-            {
-                if (!isValueType)
-                {
-                    EmitCheckForNullArgument_WithBlankLine(Identifier.obj);
-                }
-            }
-
             private void EmitCheckForNullArgument_WithBlankLine(string paramName)
             {
-                string exceptionTypeDisplayString = _useFullyQualifiedNames
-                    ? "global::System.ArgumentNullException"
-                    : "ArgumentNullException";
-
                 _writer.WriteLine($$"""
                     if ({{paramName}} is null)
                     {
-                        throw new {{exceptionTypeDisplayString}}(nameof({{paramName}}));
+                        throw new ArgumentNullException(nameof({{paramName}}));
                     }
                     """);
 
@@ -201,51 +229,28 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 if (!type.CanInitialize)
                 {
-                    _writer.WriteLine(GetInitException(type.InitExceptionMessage) + ";");
+                    _writer.WriteLine($@"throw new {Identifier.InvalidOperationException}(""{type.InitExceptionMessage}"");");
                     return true;
                 }
 
                 return false;
             }
 
-            private void EmitRootBindingClassStartBlock(string className)
-            {
-                EmitBlankLineIfRequired();
-                EmitStartBlock($$"""
-                    /// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-                    {{GetGeneratedCodeAttributeSrc()}}
-                    internal static class {{className}}
-                    """);
-
-                _emitBlankLineBeforeNextStatement = false;
-            }
-
-            private string GetGeneratedCodeAttributeSrc()
-            {
-                string attributeRefExpr = _useFullyQualifiedNames ? $"global::System.CodeDom.Compiler.GeneratedCodeAttribute" : "GeneratedCode";
-                return $@"[{attributeRefExpr}(""{s_assemblyName.Name}"", ""{s_assemblyName.Version}"")]";
-            }
-
-            private string GetInitException(string message) => $@"throw new {GetInvalidOperationDisplayName()}(""{message}"")";
-
             private string GetIncrementalIdentifier(string prefix) => $"{prefix}{_valueSuffixIndex++}";
 
-            private string GetInitalizeMethodDisplayString(ObjectSpec type) =>
-                GetHelperMethodDisplayString($"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.DisplayStringWithoutSpecialCharacters}");
-
-            private string GetTypeDisplayString(TypeSpec type) => _useFullyQualifiedNames ? type.FullyQualifiedDisplayString : type.MinimalDisplayString;
-
-            private string GetHelperMethodDisplayString(string methodName)
-            {
-                if (_useFullyQualifiedNames)
-                {
-                    methodName = FullyQualifiedDisplayString.CoreBindingHelper + "." + methodName;
-                }
-
-                return methodName;
-            }
-
-            private string GetInvalidOperationDisplayName() => _useFullyQualifiedNames ? FullyQualifiedDisplayString.InvalidOperationException : Identifier.InvalidOperationException;
+            private static string GetInitalizeMethodDisplayString(ObjectSpec type) =>
+                $"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.DisplayString.ToIdentifierSubstring()}";
         }
     }
+
+    internal static class EmitterExtensions
+    {
+        public static string ToIdentifierSubstring(this string typeDisplayName) =>
+            typeDisplayName
+                .Replace("[]", nameof(Array))
+                .Replace(", ", string.Empty)
+                .Replace(".", string.Empty)
+                .Replace("<", string.Empty)
+                .Replace(">", string.Empty);
+    }
 }
index 71d0b69..d491981 100644 (file)
@@ -9,19 +9,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         {
             private bool ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder methods) => (_sourceGenSpec.MethodsToGen_OptionsBuilderExt & methods) != 0;
 
-            private void EmitBinder_Extensions_OptionsBuilder()
+            private void EmitBindingExtensions_OptionsBuilder()
             {
                 if (!ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any))
                 {
                     return;
                 }
 
-                EmitRootBindingClassStartBlock(Identifier.GeneratedOptionsBuilderBinder);
-
+                EmitBindingExtStartRegion(TypeDisplayString.OptionsBuilderOfTOptions);
                 EmitBindMethods_Extensions_OptionsBuilder();
                 EmitBindConfigurationMethod();
-
-                EmitEndBlock();
+                EmitBindingExtEndRegion();
             }
 
             private void EmitBindMethods_Extensions_OptionsBuilder()
@@ -32,24 +30,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 }
 
                 const string documentation = @"/// <summary>Registers a configuration instance which <typeparamref name=""TOptions""/> will bind against.</summary>";
-                const string paramList = $"{FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}";
+                const string paramList = $"{Identifier.IConfiguration} {Identifier.configuration}";
 
                 if (ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Bind_T))
                 {
-                    EmitMethodStartBlock("Bind", paramList, documentation);
-                    _writer.WriteLine($"return global::{Identifier.GeneratedOptionsBuilderBinder}.Bind({Identifier.optionsBuilder}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
+                    EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder.Bind_T, "Bind", paramList, documentation);
+                    _writer.WriteLine($"return Bind({Identifier.optionsBuilder}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
                     EmitEndBlock();
                 }
 
                 EmitMethodStartBlock(
+                    MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions,
                     "Bind",
-                    paramList + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}",
+                    paramList + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}",
                     documentation);
 
                 EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder);
 
                 _writer.WriteLine($$"""
-                    global::{{Identifier.GeneratedServiceCollectionBinder}}.{{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.configuration}}, {{Identifier.configureOptions}});
+                    {{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.configuration}}, {{Identifier.configureOptions}});
                     return {{Identifier.optionsBuilder}};
                     """);
 
@@ -63,19 +62,20 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     return;
                 }
 
-                const string documentation = $@"/// <summary>Registers the dependency injection container to bind <typeparamref name=""TOptions""/> against the <see cref=""{FullyQualifiedDisplayString.IConfiguration}""/> obtained from the DI service provider.</summary>";
-                string paramList = $"string {Identifier.configSectionPath}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions} = null";
+                const string documentation = $@"/// <summary>Registers the dependency injection container to bind <typeparamref name=""TOptions""/> against the <see cref=""{Identifier.IConfiguration}""/> obtained from the DI service provider.</summary>";
+                string paramList = $"string {Identifier.configSectionPath}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions} = null";
 
-                EmitMethodStartBlock("BindConfiguration", paramList, documentation);
+                EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration, "BindConfiguration", paramList, documentation);
 
                 EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder);
                 EmitCheckForNullArgument_WithBlankLine(Identifier.configSectionPath);
 
-                EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{FullyQualifiedDisplayString.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>");
-
+                EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{Identifier.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>");
+                EmitCheckForNullArgument_WithBlankLine(Identifier.obj);
+                EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
                 _writer.WriteLine($$"""
-                    {{FullyQualifiedDisplayString.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, global::System.StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}});
-                    {{FullyQualifiedDisplayString.CoreBindingHelper}}.{{nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}});
+                    {{Identifier.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}});
+                    {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}});
                     """);
 
                 EmitEndBlock(endBraceTrailingSource: ");");
@@ -83,20 +83,20 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 _writer.WriteLine();
 
                 _writer.WriteLine($$"""
-                    {{FullyQualifiedDisplayString.AddSingleton}}<{{FullyQualifiedDisplayString.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>, {{FullyQualifiedDisplayString.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>>({{Identifier.optionsBuilder}}.{{Identifier.Services}});
+                    {{Identifier.optionsBuilder}}.{{Identifier.Services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>, {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>>();
                     return {{Identifier.optionsBuilder}};
                     """);
 
                 EmitEndBlock();
             }
 
-            private void EmitMethodStartBlock(string methodName, string paramList, string documentation)
+            private void EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder method, string methodName, string paramList, string documentation)
             {
-                paramList = $"this {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {Identifier.optionsBuilder}, {paramList}";
-
+                paramList = $"this {TypeDisplayString.OptionsBuilderOfTOptions} {Identifier.optionsBuilder}, {paramList}";
                 EmitBlankLineIfRequired();
                 _writer.WriteLine(documentation);
-                EmitStartBlock($"public static {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {methodName}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
+                EmitInterceptsLocationAnnotations(method);
+                EmitStartBlock($"public static {TypeDisplayString.OptionsBuilderOfTOptions} {methodName}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
             }
         }
     }
index f4cd480..0348eb5 100644 (file)
@@ -9,71 +9,72 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         {
             private bool ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection methods) => (_sourceGenSpec.MethodsToGen_ServiceCollectionExt & methods) != 0;
 
-            private void EmitBinder_Extensions_IServiceCollection()
+            private void EmitBindingExtensions_IServiceCollection()
             {
                 if (!ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any))
                 {
                     return;
                 }
 
-                EmitRootBindingClassStartBlock(Identifier.GeneratedServiceCollectionBinder);
+                EmitBindingExtStartRegion(Identifier.IServiceCollection);
+                EmitConfigureMethods();
+                EmitBindingExtEndRegion();
+            }
 
+            private void EmitConfigureMethods()
+            {
                 const string defaultNameExpr = "string.Empty";
-                const string configureMethodString = $"global::{Identifier.GeneratedServiceCollectionBinder}.{Identifier.Configure}";
-                string configParam = $"{FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}";
+                string configParam = $"{Identifier.IConfiguration} {Identifier.configuration}";
 
                 if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T))
                 {
-                    EmitStartMethod(configParam);
-                    _writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
+                    EmitStartMethod(MethodsToGen_Extensions_ServiceCollection.Configure_T, configParam);
+                    _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
                     EmitEndBlock();
                 }
 
                 if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_name))
                 {
                     EmitStartMethod(
+                        MethodsToGen_Extensions_ServiceCollection.Configure_T_name,
                         paramList: $"string? {Identifier.name}, " + configParam);
-                    _writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
+                    _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
                     EmitEndBlock();
                 }
 
                 if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions))
                 {
                     EmitStartMethod(
-                        paramList: configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}");
-                    _writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions});");
+                        MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions,
+                        paramList: configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}");
+                    _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions});");
                     EmitEndBlock();
                 }
 
                 // Core Configure method that the other overloads call.
                 // Like the others, it is public API that could be called directly by users.
                 // So, it is always generated whenever a Configure overload is called.
-                string optionsNamespaceName = "global::Microsoft.Extensions.Options";
-                string bindCoreUntypedDisplayString = GetHelperMethodDisplayString(nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped));
+                string optionsNamespaceName = "Microsoft.Extensions.Options";
 
-                EmitStartMethod(paramList: $"string? {Identifier.name}, " + configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}");
+                EmitStartMethod(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, paramList: $"string? {Identifier.name}, " + configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}");
                 EmitCheckForNullArgument_WithBlankLine(Identifier.services);
                 EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
                 _writer.WriteLine($$"""
-                    global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}});
-                    {{FullyQualifiedDisplayString.AddSingleton}}<{{FullyQualifiedDisplayString.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>({{Identifier.services}}, new {{FullyQualifiedDisplayString.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}}));
-                    return {{FullyQualifiedDisplayString.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>({{Identifier.services}}, new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{bindCoreUntypedDisplayString}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}})));
+                    OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}});
+                    {{Identifier.services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>(new {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}}));
+                    return {{Identifier.services}}.{{Identifier.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>(new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}){{Identifier.configureOptions}})));
                     """);
                 EmitEndBlock();
-
-                EmitEndBlock();
-                _emitBlankLineBeforeNextStatement = true;
             }
 
-            private void EmitStartMethod(string paramList)
+            private void EmitStartMethod(MethodsToGen_Extensions_ServiceCollection overload, string paramList)
             {
-                paramList = $"this {FullyQualifiedDisplayString.IServiceCollection} {Identifier.services}, {paramList}";
+                paramList = $"this {Identifier.IServiceCollection} {Identifier.services}, {paramList}";
 
                 EmitBlankLineIfRequired();
-                EmitStartBlock($$"""
-                    /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
-                    public static {{FullyQualifiedDisplayString.IServiceCollection}} {{Identifier.Configure}}<{{Identifier.TOptions}}>({{paramList}}) where {{Identifier.TOptions}} : class
-                    """);
+                _writer.WriteLine("/// <summary>Registers a configuration instance which TOptions will bind against.</summary>");
+                EmitInterceptsLocationAnnotations(overload);
+                EmitStartBlock($"public static {Identifier.IServiceCollection} {Identifier.Configure}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
             }
         }
     }
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs
new file mode 100644 (file)
index 0000000..d1dc4f4
--- /dev/null
@@ -0,0 +1,90 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Operations;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
+{
+    internal sealed record InterceptorLocationInfo
+    {
+        public InterceptorLocationInfo(IInvocationOperation operation)
+        {
+            SyntaxNode operationSyntax = operation.Syntax;
+            TextSpan operationSpan = operationSyntax.Span;
+            SyntaxTree operationSyntaxTree = operationSyntax.SyntaxTree;
+
+            FilePath = GetInterceptorFilePath(operationSyntaxTree, operation.SemanticModel?.Compilation.Options.SourceReferenceResolver);
+
+            FileLinePositionSpan span = operationSyntaxTree.GetLineSpan(operationSpan);
+            LineNumber = span.StartLinePosition.Line + 1;
+
+            // Calculate the character offset to the end of the binding invocation detected.
+            int invocationLength = ((MemberAccessExpressionSyntax)((InvocationExpressionSyntax)operationSyntax).Expression).Expression.Span.Length;
+            CharacterNumber = span.StartLinePosition.Character + invocationLength + 2;
+        }
+
+        public string FilePath { get; }
+        public int LineNumber { get; }
+        public int CharacterNumber { get; }
+
+        // Utilize the same logic used by the interceptors API for resolving the source mapped value of a path.
+        // https://github.com/dotnet/roslyn/blob/f290437fcc75dad50a38c09e0977cce13a64f5ba/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs#L1063-L1064
+        private static string GetInterceptorFilePath(SyntaxTree tree, SourceReferenceResolver? resolver) =>
+            resolver?.NormalizePath(tree.FilePath, baseFilePath: null) ?? tree.FilePath;
+    }
+
+    internal sealed record ConfigurationBinderInterceptorInfo
+    {
+        private OverloadInterceptorInfo? _bind_Instance;
+        private OverloadInterceptorInfo? _bind_instance_BinderOptions;
+        private OverloadInterceptorInfo? _bind_key_instance;
+
+        public void RegisterOverloadInfo(MethodsToGen_ConfigurationBinder overload, TypeSpec type, IInvocationOperation operation)
+        {
+            OverloadInterceptorInfo overloadInfo = DetermineOverload(overload, initIfNull: true);
+            overloadInfo.RegisterLocationInfo(type, operation);
+        }
+
+        public OverloadInterceptorInfo GetOverloadInfo(MethodsToGen_ConfigurationBinder overload) =>
+            DetermineOverload(overload, initIfNull: false) ?? throw new ArgumentNullException(nameof(overload));
+
+        private OverloadInterceptorInfo? DetermineOverload(MethodsToGen_ConfigurationBinder overload, bool initIfNull)
+        {
+            return overload switch
+            {
+                MethodsToGen_ConfigurationBinder.Bind_instance => InitIfNull(ref _bind_Instance),
+                MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions => InitIfNull(ref _bind_instance_BinderOptions),
+                MethodsToGen_ConfigurationBinder.Bind_key_instance => InitIfNull(ref _bind_key_instance),
+                _ => throw new InvalidOperationException(nameof(overload)),
+            };
+
+            OverloadInterceptorInfo InitIfNull(ref OverloadInterceptorInfo? info)
+            {
+                if (initIfNull)
+                {
+                    info ??= new OverloadInterceptorInfo();
+                }
+
+                return info;
+            }
+        }
+    }
+
+    internal sealed record OverloadInterceptorInfo : IEnumerable<KeyValuePair<TypeSpec, List<InterceptorLocationInfo>>>
+    {
+        private readonly Dictionary<TypeSpec, List<InterceptorLocationInfo>> _typeInterceptionInfo = new();
+
+        public void RegisterLocationInfo(TypeSpec type, IInvocationOperation operation) =>
+            _typeInterceptionInfo.RegisterCacheEntry(type, new InterceptorLocationInfo(operation));
+
+        public IEnumerator<KeyValuePair<TypeSpec, List<InterceptorLocationInfo>>> GetEnumerator() => _typeInterceptionInfo.GetEnumerator();
+
+        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+    }
+}
index 7b40f19..2c582b2 100644 (file)
@@ -10,11 +10,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     {
         None = 0x0,
         BindCore = 0x1,
-        BindCoreUntyped = 0x2,
-        GetCore = 0x4,
-        GetValueCore = 0x8,
+        GetCore = 0x2,
+        GetValueCore = 0x4,
+        BindCoreMain = 0x8,
         Initialize = 0x10,
-        AsConfigWithChildren = 0x20,
+        HasValueOrChildren = 0x20,
+        AsConfigWithChildren = 0x40,
     }
 
     /// <summary>
index 5547865..ad7c4c0 100644 (file)
@@ -40,7 +40,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(name);
         }
 
-        private static bool IsBindingOperation(IInvocationOperation operation)
+        public static bool IsBindingOperation(IInvocationOperation operation)
         {
             if (operation.TargetMethod is not IMethodSymbol
                 {
index a663c44..e24ce11 100644 (file)
@@ -102,15 +102,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 if (GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec)
                 {
-                    Dictionary<MethodsToGen_ConfigurationBinder, HashSet<TypeSpec>> types = _sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods;
-
-                    if (!types.TryGetValue(overload, out HashSet<TypeSpec>? typeSpecs))
-                    {
-                        types[overload] = typeSpecs = new HashSet<TypeSpec>();
-                    }
-
-                    _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
-                    typeSpecs.Add(typeSpec);
+                    RegisterAsInterceptor_ConfigBinder_BindMethod(overload, typeSpec, invocation.Operation);
                 }
 
                 static ITypeSymbol? ResolveType(IOperation conversionOperation) =>
@@ -184,8 +176,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 if (GetTargetTypeForRootInvocation(type, invocation.Location) is TypeSpec typeSpec)
                 {
-                    _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
-                    RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec);
+                    RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation);
+                    RegisterTypeForGetCoreGen(typeSpec);
                 }
 
             }
@@ -253,10 +245,27 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 if (IsParsableFromString(effectiveType, out _) &&
                     GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec)
                 {
-                    _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
+                    RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation);
                     RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetValueCore, typeSpec);
                 }
             }
+
+            private void RegisterAsInterceptor_ConfigBinder(MethodsToGen_ConfigurationBinder overload, IInvocationOperation operation)
+            {
+                _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
+                RegisterAsInterceptor(overload, operation);
+            }
+
+            /// <summary>
+            /// Registers generated Bind methods as interceptors. This is done differently from other root
+            /// methods <see cref="RegisterAsInterceptor(Enum, IInvocationOperation)"/> because we need to
+            /// explicitly account for the type to bind, to avoid type-check issues for polymorphic objects.
+            /// </summary>
+            private void RegisterAsInterceptor_ConfigBinder_BindMethod(MethodsToGen_ConfigurationBinder overload, TypeSpec typeSpec, IInvocationOperation operation)
+            {
+                _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
+                _sourceGenSpec.InterceptionInfo_ConfigBinder.RegisterOverloadInfo(overload, typeSpec, operation);
+            }
         }
     }
 }
index d01e80d..a62e63c 100644 (file)
@@ -34,9 +34,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     return;
                 }
 
-                // We are going to emit calls to APIs on IServiceCollection.
-                _sourceGenSpec.TypeNamespaces.Add("Microsoft.Extensions.DependencyInjection");
-
                 if (targetMethod.Name is "Bind")
                 {
                     RegisterBindInvocation(invocation, typeSpec);
@@ -61,20 +58,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     return;
                 }
 
-                if (paramCount is 2)
-                {
-                    _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.Bind_T;
-                }
-                else if (paramCount is 3 && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type))
+                MethodsToGen_Extensions_OptionsBuilder overload = paramCount switch
                 {
-                    _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions;
-                }
-                else
+                    2 => MethodsToGen_Extensions_OptionsBuilder.Bind_T,
+                    3 when SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type) =>
+                        MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions,
+                    _ => MethodsToGen_Extensions_OptionsBuilder.None
+                };
+
+                if (overload is not MethodsToGen_Extensions_OptionsBuilder.None)
                 {
-                    return;
+                    RegisterAsInterceptor_OptionsBuilder(overload, operation);
+                    RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec);
                 }
-
-                RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec);
             }
 
             private void ParseBindConfigurationInvocation(BinderInvocation invocation, TypeSpec typeSpec)
@@ -85,12 +81,26 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 int paramCount = @params.Length;
                 Debug.Assert(paramCount >= 2);
 
-                if (paramCount is 3 && @params[1].Type.SpecialType is SpecialType.System_String && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type))
+                if (paramCount is 3 &&
+                    @params[1].Type.SpecialType is SpecialType.System_String &&
+                    SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type))
                 {
-                    _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions;
-                    RegisterTypeForBindCoreUntypedGen(typeSpec);
+                    RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions, invocation.Operation);
+                    RegisterTypeForBindCoreMainGen(typeSpec);
                 }
             }
+
+            private void RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder overload, IInvocationOperation operation)
+            {
+                _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= overload;
+                RegisterAsInterceptor(overload, operation);
+
+                // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource.
+                _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options");
+
+                // Emitting refs to OptionsBuilder<T>.
+                _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection");
+            }
         }
     }
 }
index 02c75b4..c356b29 100644 (file)
@@ -79,12 +79,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 }
 
                 RegisterTypeForMethodGen(overload, typeSpec);
+                RegisterAsInterceptor(overload, operation);
             }
 
             private void RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, TypeSpec typeSpec)
             {
                 _sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload;
-                RegisterTypeForBindCoreUntypedGen(typeSpec);
+                _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection");
+                RegisterTypeForBindCoreMainGen(typeSpec);
             }
         }
     }
index 785a18c..5b10a6f 100644 (file)
@@ -11,6 +11,8 @@
 
   <ItemGroup>
     <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(MicrosoftCodeAnalysisVersion_LatestVS)" PrivateAssets="all" />
+    <!-- if MicrosoftCodeAnalysisVersion_LatestVS is still at 4.5.0 (eg: not source build) then update to a newer version. Remove this when we are able to update the value of MicrosoftCodeAnalysisVersion_LatestVS --> 
+    <PackageReference Update="Microsoft.CodeAnalysis.CSharp.Workspaces" Condition="'$(MicrosoftCodeAnalysisVersion_LatestVS)' == '4.5.0'"  Version="4.7.0-3.23314.3" />
   </ItemGroup>
 
   <ItemGroup>
     <Compile Include="ConfigurationBindingGenerator.cs" />
     <Compile Include="ConfigurationBindingGenerator.Emitter.cs" />
     <Compile Include="ConfigurationBindingGenerator.Parser.cs" />
+    <Compile Include="ConfigurationBindingGenerator.Suppressor.cs" />
     <Compile Include="Helpers\Emitter\ConfigurationBinder.cs" />
-    <Compile Include="Helpers\Emitter\CoreBindingHelper.cs" />
+    <Compile Include="Helpers\Emitter\CoreBindingHelpers.cs" />
     <Compile Include="Helpers\Emitter\ExceptionMessages.cs" />
     <Compile Include="Helpers\Emitter\Helpers.cs" />
     <Compile Include="Helpers\Emitter\OptionsBuilderConfigurationExtensions.cs" />
     <Compile Include="Helpers\Emitter\OptionsConfigurationServiceCollectionExtensions.cs" />
+    <Compile Include="Helpers\InterceptorLocationInfo.cs" />
     <Compile Include="Helpers\MethodsToGen.cs" />
     <Compile Include="Helpers\Parser\BinderInvocation.cs" />
     <Compile Include="Helpers\Parser\ConfigurationBinder.cs" />
index 1696ee0..8cc0ba6 100644 (file)
@@ -22,10 +22,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public List<ParameterSpec> ConstructorParameters { get; } = new();
 
-        private string _displayStringWithoutSpecialCharacters;
-        public string DisplayStringWithoutSpecialCharacters =>
-            _displayStringWithoutSpecialCharacters ??= $"{MinimalDisplayString.Replace(".", string.Empty).Replace("<", string.Empty).Replace(">", string.Empty)}";
-
         public override bool NeedsMemberBinding => CanInitialize &&
             Properties.Values.Count > 0 &&
             Properties.Values.Any(p => p.ShouldBind());
index 6b5bb5b..e19e3e6 100644 (file)
@@ -24,7 +24,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 _parseMethodName ??= StringParsableTypeKind is StringParsableTypeKind.ByteArray
                     ? "ParseByteArray"
                     // MinimalDisplayString.Length is certainly > 2.
-                    : $"Parse{(char.ToUpper(MinimalDisplayString[0]) + MinimalDisplayString.Substring(1)).Replace(".", "")}";
+                    : $"Parse{(char.ToUpper(DisplayString[0]) + DisplayString.Substring(1)).Replace(".", "")}";
 
                 return _parseMethodName;
             }
index 88c4b24..760d57b 100644 (file)
@@ -1,21 +1,25 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System;
 using System.Collections.Generic;
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
     internal sealed record SourceGenerationSpec
     {
+        public Dictionary<Enum, List<InterceptorLocationInfo>> InterceptionInfo { get; } = new();
+        public ConfigurationBinderInterceptorInfo InterceptionInfo_ConfigBinder { get; } = new();
+
         public Dictionary<MethodsToGen_CoreBindingHelper, HashSet<TypeSpec>> TypesForGen_CoreBindingHelper_Methods { get; } = new();
-        public Dictionary<MethodsToGen_ConfigurationBinder, HashSet<TypeSpec>> TypesForGen_ConfigurationBinder_BindMethods { get; } = new();
 
         public HashSet<ParsableFromStringSpec> PrimitivesForHelperGen { get; } = new();
-        public HashSet<string> TypeNamespaces { get; } = new()
+        public HashSet<string> Namespaces { get; } = new()
         {
             "System",
             "System.CodeDom.Compiler",
             "System.Globalization",
+            "System.Runtime.CompilerServices",
             "Microsoft.Extensions.Configuration",
         };
 
index 6a6292b..6f5e26b 100644 (file)
@@ -17,17 +17,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         {
             IsValueType = type.IsValueType;
             Namespace = type.ContainingNamespace?.ToDisplayString();
-            FullyQualifiedDisplayString = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
-            MinimalDisplayString = type.ToDisplayString(s_minimalDisplayFormat);
-            Name = Namespace + "." + MinimalDisplayString.Replace(".", "+");
+            DisplayString = type.ToDisplayString(s_minimalDisplayFormat);
+            Name = Namespace + "." + DisplayString.Replace(".", "+");
             IsInterface = type.TypeKind is TypeKind.Interface;
         }
 
         public string Name { get; }
 
-        public string FullyQualifiedDisplayString { get; }
-
-        public string MinimalDisplayString { get; }
+        public string DisplayString { get; }
 
         public string? Namespace { get; }
 
index 3019139..3978cba 100644 (file)
     <value>The collection element type is not supported: '{0}'.</value>
   </data>
   <data name="Language VersionIsNotSupportedMessageFormat" xml:space="preserve">
-    <value>The project's language version has to be at least 'C# 11'.</value>
+    <value>The project's language version has to be at least 'C# 12'.</value>
   </data>
   <data name="LanguageVersionIsNotSupportedTitle" xml:space="preserve">
-    <value>Language version is required to be at least C# 11</value>
+    <value>Language version is required to be at least C# 12</value>
   </data>
   <data name="MissingPublicInstanceConstructor" xml:space="preserve">
     <value>Cannot create instance of type '{0}' because it is missing a public instance constructor.</value>
index e248c54..c6672ea 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">Jazyková verze projektu musí být alespoň C# 11</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">Jazyková verze projektu musí být alespoň C# 11</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">Verze jazyka musí být alespoň C# 11</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">Verze jazyka musí být alespoň C# 11</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index 1fa8475..5f35306 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">Die Sprachversion des Projekts muss mindestens „C# 11“ sein</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">Die Sprachversion des Projekts muss mindestens „C# 11“ sein</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">Die Sprachversion muss mindestens C# 11 sein</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">Die Sprachversion muss mindestens C# 11 sein</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index c52b231..cd54149 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">La versión del lenguaje del proyecto debe ser al menos "C# 11".</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">La versión del lenguaje del proyecto debe ser al menos "C# 11".</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">La versión del lenguaje debe ser al menos C# 11</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">La versión del lenguaje debe ser al menos C# 11</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index 19362d7..b1c0753 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">La version de langage du projet doit être au moins « C# 11 ».</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">La version de langage du projet doit être au moins « C# 11 ».</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">La version du langage doit être au moins C# 11</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">La version du langage doit être au moins C# 11</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index f418a83..27d10a7 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">La versione del linguaggio del progetto deve essere almeno 'C# 11'.</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">La versione del linguaggio del progetto deve essere almeno 'C# 11'.</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">La versione del linguaggio deve essere almeno C# 11</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">La versione del linguaggio deve essere almeno C# 11</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index ba59cfb..24621bc 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">プロジェクトの言語バージョンは少なくとも 'C# 11' である必要があります。</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">プロジェクトの言語バージョンは少なくとも 'C# 11' である必要があります。</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">言語バージョンは少なくとも C# 11 である必要があります</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">言語バージョンは少なくとも C# 11 である必要があります</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index 10b9b10..217a0cd 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">프로젝트의 언어 버전은 'C# 11' 이상이어야 합니다.</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">프로젝트의 언어 버전은 'C# 11' 이상이어야 합니다.</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">언어 버전은 C# 11 이상이어야 합니다.</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">언어 버전은 C# 11 이상이어야 합니다.</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index 2b558c5..0b24813 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">Wersja językowa projektu musi mieć wartość co najmniej „C# 11”.</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">Wersja językowa projektu musi mieć wartość co najmniej „C# 11”.</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">Wymagana jest wersja językowa co najmniej C# 11</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">Wymagana jest wersja językowa co najmniej C# 11</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index 9d2a51c..0ad700e 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">A versão do idioma do projeto deve ser no mínimo 'C# 11'.</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">A versão do idioma do projeto deve ser no mínimo 'C# 11'.</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">A versão do idioma deve ser pelo menos C# 11</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">A versão do idioma deve ser pelo menos C# 11</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index 1ed03c5..5e53330 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">Версия языка проекта должна быть не ниже "C# 11".</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">Версия языка проекта должна быть не ниже "C# 11".</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">Версия языка должна быть не ниже C# 11</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">Версия языка должна быть не ниже C# 11</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index 8a6dbf7..cfaea48 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">Projenin dil sürümü en az 'C# 11' olmalıdır.</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">Projenin dil sürümü en az 'C# 11' olmalıdır.</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">Dil sürümünün en az C# 11 olması gerekir</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">Dil sürümünün en az C# 11 olması gerekir</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index 9d0c0eb..3dfb711 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">项目的语言版本必须至少为 "C# 11"。</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">项目的语言版本必须至少为 "C# 11"。</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">语言版本必须至少为 C# 11</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">语言版本必须至少为 C# 11</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index dc6ded6..9917b18 100644 (file)
         <note />
       </trans-unit>
       <trans-unit id="Language VersionIsNotSupportedMessageFormat">
-        <source>The project's language version has to be at least 'C# 11'.</source>
-        <target state="translated">專案的語言版本必須至少為 'C# 11'。</target>
+        <source>The project's language version has to be at least 'C# 12'.</source>
+        <target state="needs-review-translation">專案的語言版本必須至少為 'C# 11'。</target>
         <note />
       </trans-unit>
       <trans-unit id="LanguageVersionIsNotSupportedTitle">
-        <source>Language version is required to be at least C# 11</source>
-        <target state="translated">語言版本要求至少為 C#11</target>
+        <source>Language version is required to be at least C# 12</source>
+        <target state="needs-review-translation">語言版本要求至少為 C#11</target>
         <note />
       </trans-unit>
       <trans-unit id="MissingPublicInstanceConstructor">
index 56dddc6..eea0109 100644 (file)
@@ -8,7 +8,6 @@ using System.Diagnostics;
 using System.Globalization;
 using System.Linq;
 using System.Reflection;
-using System.Text;
 #if BUILDING_SOURCE_GENERATOR_TESTS
 using Microsoft.Extensions.Configuration;
 #endif
@@ -2037,6 +2036,7 @@ if (!System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Launc
             ValidateGeolocation(obj);
         }
 
+#if !BUILDING_SOURCE_GENERATOR_TESTS
         [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
         public void TraceSwitchTest()
         {
@@ -2056,6 +2056,7 @@ if (!System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Launc
             Assert.Equal("Info", ts.Value);
 #endif // NETCOREAPP
         }
+#endif
 
         private void ValidateGeolocation(IGeolocation location)
         {
index 2149dca..528847c 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
-    public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -18,11 +25,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.Collections.Generic;
     using System.Globalization;
     using System.Linq;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 12, 17)]
+        public static T? Get<T>(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "IReadOnlyList", "IReadOnlyDictionary" });
 
         public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
@@ -46,16 +60,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return obj;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary<string, int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -67,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.CustomList obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -83,11 +87,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -99,11 +98,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref ICollection<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -115,11 +109,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref IReadOnlyList<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             if (obj is not ICollection<int> temp)
             {
                 return;
@@ -136,11 +125,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -152,11 +136,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref IDictionary<string, int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -168,11 +147,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary<string, int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             if (obj is not IDictionary<string, int> temp)
             {
                 return;
@@ -189,11 +163,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClassWithCustomCollections), s_configKeys_ProgramMyClassWithCustomCollections, configuration, binderOptions);
 
             if (AsConfigWithChildren(configuration.GetSection("CustomDictionary")) is IConfigurationSection section1)
@@ -229,6 +198,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -281,7 +251,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -298,5 +268,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 406e8db..36ac12f 100644 (file)
@@ -2,18 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
-    public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null);
-
-    /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
-    public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions));
+    using System;
+    using System.CodeDom.Compiler;
 
-    /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
-    public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration.GetSection(key), ref obj, binderOptions: null);
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -23,20 +24,72 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
-        private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 13, 18)]
+        public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj)
+        {
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
 
-        public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
+            if (obj is null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
+
+            var typedObj = (Program.MyClass)obj;
+            BindCore(configuration, ref typedObj, binderOptions: null);
+        }
+
+        /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 14, 24)]
+        public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action<BinderOptions>? configureOptions)
+        {
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
+            if (obj is null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
+
+            var typedObj = (Program.MyClass)obj;
+            BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions));
+        }
+
+        /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 15, 24)]
+        public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj)
         {
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
             if (obj is null)
             {
                 throw new ArgumentNullException(nameof(obj));
             }
 
+            var typedObj = (Program.MyClass)obj;
+            BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null);
+        }
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
+        private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
+
+        public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
+        {
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -48,11 +101,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -64,11 +112,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null))
@@ -81,11 +124,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -120,6 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -163,7 +202,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -180,5 +219,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 106e017..02fb069 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
-    public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null);
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
-        private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
-
-        public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 12, 20)]
+        public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj)
         {
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
             if (obj is null)
             {
                 throw new ArgumentNullException(nameof(obj));
             }
 
+            var typedObj = (Program.MyClass)obj;
+            BindCore(configuration, ref typedObj, binderOptions: null);
+        }
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
+        private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
+
+        public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
+        {
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null))
@@ -75,11 +88,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -156,5 +165,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index a1cb7d6..4703980 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
-    public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions));
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
-        private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
-
-        public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 12, 20)]
+        public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action<BinderOptions>? configureOptions)
         {
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
             if (obj is null)
             {
                 throw new ArgumentNullException(nameof(obj));
             }
 
+            var typedObj = (Program.MyClass)obj;
+            BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions));
+        }
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
+        private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
+
+        public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
+        {
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null))
@@ -75,11 +88,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -157,7 +166,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -174,5 +183,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index f3ee8a9..9937129 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
-    public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration.GetSection(key), ref obj, binderOptions: null);
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
-        private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
-
-        public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 12, 20)]
+        public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj)
         {
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
             if (obj is null)
             {
                 throw new ArgumentNullException(nameof(obj));
             }
 
+            var typedObj = (Program.MyClass)obj;
+            BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null);
+        }
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
+        private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
+
+        public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
+        {
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null))
@@ -75,11 +88,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -156,5 +165,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index fb71c70..3e6ce14 100644 (file)
@@ -2,21 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
-    public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
-
-    /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
-    public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T));
-
-    /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
-    public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions: null);
+    using System;
+    using System.CodeDom.Compiler;
 
-    /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
-    public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions);
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -26,11 +24,30 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 12, 38)]
+        public static T? Get<T>(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
+
+        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 14, 36)]
+        public static T? Get<T>(this IConfiguration configuration, Action<BinderOptions>? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T));
+
+        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 13, 36)]
+        public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null);
+
+        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 15, 36)]
+        public static object? Get(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions) => GetCore(configuration, type, configureOptions);
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
 
@@ -54,24 +71,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 BindCore(configuration, ref obj, binderOptions);
                 return obj;
             }
-
-            if (type == typeof(Program.MyClass2))
+            else if (type == typeof(Program.MyClass2))
             {
                 var obj = new Program.MyClass2();
                 BindCore(configuration, ref obj, binderOptions);
                 return obj;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -83,11 +94,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             var temp2 = new List<int>();
             BindCore(configuration, ref temp2, binderOptions);
             int originalCount = obj.Length;
@@ -97,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -113,11 +114,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -154,11 +150,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
 
             if (configuration["MyInt"] is string value15)
@@ -167,6 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -219,7 +211,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -236,5 +228,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index c9d49fa..e4bcaf6 100644 (file)
@@ -2,21 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
-    public static T? GetValue<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? default(T));
-
-    /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
-    public static T? GetValue<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? defaultValue);
-
-    /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
-    public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key);
+    using System;
+    using System.CodeDom.Compiler;
 
-    /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
-    public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key, object? defaultValue) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key) ?? defaultValue;
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -25,11 +23,30 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System;
     using System.CodeDom.Compiler;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 13, 18)]
+        public static T? GetValue<T>(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T));
+
+        /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 16, 24)]
+        public static T? GetValue<T>(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue);
+
+        /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 14, 24)]
+        public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key);
+
+        /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 17, 24)]
+        public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue;
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
         {
             if (configuration is null)
@@ -48,18 +65,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             {
                 return ParseInt(value, () => section.Path);
             }
-
-            if (type == typeof(bool?))
+            else if (type == typeof(bool?))
             {
                 return ParseBool(value, () => section.Path);
             }
-
-            if (type == typeof(byte[]))
+            else if (type == typeof(byte[]))
             {
                 return ParseByteArray(value, () => section.Path);
             }
-
-            if (type == typeof(CultureInfo))
+            else if (type == typeof(CultureInfo))
             {
                 return ParseCultureInfo(value, () => section.Path);
             }
@@ -114,5 +128,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 17c963b..2438cf5 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
-    public static T? GetValue<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? default(T));
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System;
     using System.CodeDom.Compiler;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 10, 20)]
+        public static T? GetValue<T>(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T));
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
         {
             if (configuration is null)
@@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 1148109..e6db24d 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
-    public static T? GetValue<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? defaultValue);
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System;
     using System.CodeDom.Compiler;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 12, 20)]
+        public static T? GetValue<T>(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue);
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
         {
             if (configuration is null)
@@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index c833b20..a36f9fa 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
-    public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key);
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System;
     using System.CodeDom.Compiler;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 10, 20)]
+        public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key);
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
         {
             if (configuration is null)
@@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(bool)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index f773f79..356f6bb 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
-    public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key, object? defaultValue) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key) ?? defaultValue;
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System;
     using System.CodeDom.Compiler;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 11, 20)]
+        public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue;
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
         {
             if (configuration is null)
@@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index de8201f..85d0901 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
-    public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 11, 40)]
+        public static T? Get<T>(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
 
         public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
@@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return obj;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -66,11 +75,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             var temp1 = new List<int>();
             BindCore(configuration, ref temp1, binderOptions);
             int originalCount = obj.Length;
@@ -80,11 +84,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -96,11 +95,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -135,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -187,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -204,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 34fadac..d394cc7 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
-    public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T));
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 11, 40)]
+        public static T? Get<T>(this IConfiguration configuration, Action<BinderOptions>? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T));
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
 
         public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
@@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return obj;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -66,11 +75,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             var temp1 = new List<int>();
             BindCore(configuration, ref temp1, binderOptions);
             int originalCount = obj.Length;
@@ -80,11 +84,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -96,11 +95,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -135,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -187,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -204,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 16a98c9..83cd885 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
-    public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions: null);
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 11, 40)]
+        public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null);
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
 
         public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
@@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return obj;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
 
             if (configuration["MyInt"] is string value1)
@@ -63,6 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -115,7 +125,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -132,5 +142,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 8d1ee9e..91714c8 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
-    public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions);
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 11, 20)]
+        public static object? Get(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions) => GetCore(configuration, type, configureOptions);
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
 
         public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
@@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return obj;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
 
             if (configuration["MyInt"] is string value1)
@@ -63,6 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -115,7 +125,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -132,5 +142,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index a74dbfd..88b3503 100644 (file)
@@ -2,31 +2,18 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedOptionsBuilderBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Registers the dependency injection container to bind <typeparamref name="TOptions"/> against the <see cref="global::Microsoft.Extensions.Configuration.IConfiguration"/> obtained from the DI service provider.</summary>
-    public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> BindConfiguration<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, string configSectionPath, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions = null) where TOptions : class
-    {
-        if (optionsBuilder is null)
-        {
-            throw new global::System.ArgumentNullException(nameof(optionsBuilder));
-        }
+    using System;
+    using System.CodeDom.Compiler;
 
-        if (configSectionPath is null)
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
         {
-            throw new global::System.ArgumentNullException(nameof(configSectionPath));
         }
-
-        optionsBuilder.Configure<global::Microsoft.Extensions.Configuration.IConfiguration>((obj, configuration) =>
-        {
-            global::Microsoft.Extensions.Configuration.IConfiguration section = string.Equals(string.Empty, configSectionPath, global::System.StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath);
-            global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(section, obj, typeof(TOptions), configureOptions);
-        });
-
-        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>, global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>>(optionsBuilder.Services);
-        return optionsBuilder;
     }
 }
 
@@ -34,31 +21,74 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
     using Microsoft.Extensions.Configuration;
     using Microsoft.Extensions.DependencyInjection;
+    using Microsoft.Extensions.Options;
     using System;
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region OptionsBuilder<TOptions> extensions.
+        /// <summary>Registers the dependency injection container to bind <typeparamref name="TOptions"/> against the <see cref="IConfiguration"/> obtained from the DI service provider.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 12, 24)]
+        public static OptionsBuilder<TOptions> BindConfiguration<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, string configSectionPath, Action<BinderOptions>? configureOptions = null) where TOptions : class
+        {
+            if (optionsBuilder is null)
+            {
+                throw new ArgumentNullException(nameof(optionsBuilder));
+            }
+
+            if (configSectionPath is null)
+            {
+                throw new ArgumentNullException(nameof(configSectionPath));
+            }
+
+            optionsBuilder.Configure<IConfiguration>((obj, configuration) =>
+            {
+                if (obj is null)
+                {
+                    throw new ArgumentNullException(nameof(obj));
+                }
+
+                if (configuration is null)
+                {
+                    throw new ArgumentNullException(nameof(configuration));
+                }
+
+                IConfiguration section = string.Equals(string.Empty, configSectionPath, StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath);
+                BindCoreMain(section, obj, typeof(TOptions), configureOptions);
+            });
+
+            optionsBuilder.Services.AddSingleton<IOptionsChangeTokenSource<TOptions>, ConfigurationChangeTokenSource<TOptions>>();
+            return optionsBuilder;
+        }
+        #endregion OptionsBuilder<TOptions> extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
 
-        public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
+        public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
         {
             if (configuration is null)
             {
                 throw new ArgumentNullException(nameof(configuration));
             }
 
-            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+            if (obj is null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
 
             if (!HasValueOrChildren(configuration))
             {
                 return;
             }
 
+            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+
             if (type == typeof(Program.MyClass))
             {
                 var temp = (Program.MyClass)obj;
@@ -66,16 +96,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -87,11 +112,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -110,6 +130,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -162,7 +183,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -179,5 +200,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index ac53b58..633196e 100644 (file)
@@ -2,49 +2,18 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedOptionsBuilderBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
-    public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> Bind<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class
-    {
-        return global::GeneratedOptionsBuilderBinder.Bind(optionsBuilder, configuration, configureOptions: null);
-    }
-
-    /// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
-    public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> Bind<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
-    {
-        if (optionsBuilder is null)
-        {
-            throw new global::System.ArgumentNullException(nameof(optionsBuilder));
-        }
-
-        global::GeneratedServiceCollectionBinder.Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
-        return optionsBuilder;
-    }
-}
+    using System;
+    using System.CodeDom.Compiler;
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedServiceCollectionBinder
-{
-    /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
-    public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
     {
-        if (services is null)
-        {
-            throw new global::System.ArgumentNullException(nameof(services));
-        }
-
-        if (configuration is null)
+        public InterceptsLocationAttribute(string filePath, int line, int column)
         {
-            throw new global::System.ArgumentNullException(nameof(configuration));
         }
-
-        global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
-        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
-        return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
     }
 }
 
@@ -52,31 +21,79 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
     using Microsoft.Extensions.Configuration;
     using Microsoft.Extensions.DependencyInjection;
+    using Microsoft.Extensions.Options;
     using System;
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region OptionsBuilder<TOptions> extensions.
+        /// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 15, 24)]
+        public static OptionsBuilder<TOptions> Bind<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, IConfiguration configuration) where TOptions : class
+        {
+            return Bind(optionsBuilder, configuration, configureOptions: null);
+        }
+
+        /// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
+        public static OptionsBuilder<TOptions> Bind<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
+        {
+            if (optionsBuilder is null)
+            {
+                throw new ArgumentNullException(nameof(optionsBuilder));
+            }
+
+            Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
+            return optionsBuilder;
+        }
+        #endregion OptionsBuilder<TOptions> extensions.
+
+        #region IServiceCollection extensions.
+        /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
+        public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
+        {
+            if (services is null)
+            {
+                throw new ArgumentNullException(nameof(services));
+            }
+
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
+            OptionsServiceCollectionExtensions.AddOptions(services);
+            services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
+            return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
+        }
+        #endregion IServiceCollection extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
 
-        public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
+        public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
         {
             if (configuration is null)
             {
                 throw new ArgumentNullException(nameof(configuration));
             }
 
-            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+            if (obj is null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
 
             if (!HasValueOrChildren(configuration))
             {
                 return;
             }
 
+            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+
             if (type == typeof(Program.MyClass))
             {
                 var temp = (Program.MyClass)obj;
@@ -84,16 +101,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -105,11 +117,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -128,6 +135,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -180,7 +188,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -197,5 +205,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index fd3ec70..fb5b4b4 100644 (file)
@@ -2,43 +2,18 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedOptionsBuilderBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
-    public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> Bind<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
-    {
-        if (optionsBuilder is null)
-        {
-            throw new global::System.ArgumentNullException(nameof(optionsBuilder));
-        }
-
-        global::GeneratedServiceCollectionBinder.Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
-        return optionsBuilder;
-    }
-}
+    using System;
+    using System.CodeDom.Compiler;
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedServiceCollectionBinder
-{
-    /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
-    public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
     {
-        if (services is null)
-        {
-            throw new global::System.ArgumentNullException(nameof(services));
-        }
-
-        if (configuration is null)
+        public InterceptsLocationAttribute(string filePath, int line, int column)
         {
-            throw new global::System.ArgumentNullException(nameof(configuration));
         }
-
-        global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
-        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
-        return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
     }
 }
 
@@ -46,31 +21,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
     using Microsoft.Extensions.Configuration;
     using Microsoft.Extensions.DependencyInjection;
+    using Microsoft.Extensions.Options;
     using System;
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region OptionsBuilder<TOptions> extensions.
+        /// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 15, 24)]
+        public static OptionsBuilder<TOptions> Bind<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
+        {
+            if (optionsBuilder is null)
+            {
+                throw new ArgumentNullException(nameof(optionsBuilder));
+            }
+
+            Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
+            return optionsBuilder;
+        }
+        #endregion OptionsBuilder<TOptions> extensions.
+
+        #region IServiceCollection extensions.
+        /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
+        public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
+        {
+            if (services is null)
+            {
+                throw new ArgumentNullException(nameof(services));
+            }
+
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
+            OptionsServiceCollectionExtensions.AddOptions(services);
+            services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
+            return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
+        }
+        #endregion IServiceCollection extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
 
-        public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
+        public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
         {
             if (configuration is null)
             {
                 throw new ArgumentNullException(nameof(configuration));
             }
 
-            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+            if (obj is null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
 
             if (!HasValueOrChildren(configuration))
             {
                 return;
             }
 
+            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+
             if (type == typeof(Program.MyClass))
             {
                 var temp = (Program.MyClass)obj;
@@ -78,16 +95,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -99,11 +111,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -122,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -174,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -191,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 5d30288..1bf1104 100644 (file)
@@ -2,12 +2,19 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedConfigurationBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
-    public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null);
+    using System;
+    using System.CodeDom.Compiler;
+
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
+        {
+        }
+    }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
@@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
-        private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" });
-
-        public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
+        #region IConfiguration extensions.
+        /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 13, 16)]
+        public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj)
         {
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
             if (obj is null)
             {
                 throw new ArgumentNullException(nameof(obj));
             }
 
+            var typedObj = (Program.MyClass)obj;
+            BindCore(configuration, ref typedObj, binderOptions: null);
+        }
+        #endregion IConfiguration extensions.
+
+        #region Core binding extensions.
+        private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" });
+
+        public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
+        {
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             if (configuration["Prop0"] is string value0)
@@ -168,6 +191,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -517,5 +541,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte[])}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 461f605..7f626f0 100644 (file)
@@ -2,64 +2,84 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedServiceCollectionBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
-    public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class
-    {
-        return global::GeneratedServiceCollectionBinder.Configure<TOptions>(services, string.Empty, configuration, configureOptions: null);
-    }
+    using System;
+    using System.CodeDom.Compiler;
 
-    /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
-    public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
     {
-        if (services is null)
-        {
-            throw new global::System.ArgumentNullException(nameof(services));
-        }
-
-        if (configuration is null)
+        public InterceptsLocationAttribute(string filePath, int line, int column)
         {
-            throw new global::System.ArgumentNullException(nameof(configuration));
         }
-
-        global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
-        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
-        return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
     }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
     using Microsoft.Extensions.Configuration;
+    using Microsoft.Extensions.DependencyInjection;
     using System;
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IServiceCollection extensions.
+        /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
+        public static IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration configuration) where TOptions : class
+        {
+            return Configure<TOptions>(services, string.Empty, configuration, configureOptions: null);
+        }
+
+        /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
+        public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
+        {
+            if (services is null)
+            {
+                throw new ArgumentNullException(nameof(services));
+            }
+
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
+            OptionsServiceCollectionExtensions.AddOptions(services);
+            services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
+            return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
+        }
+        #endregion IServiceCollection extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
 
-        public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
+        public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
         {
             if (configuration is null)
             {
                 throw new ArgumentNullException(nameof(configuration));
             }
 
-            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+            if (obj is null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
 
             if (!HasValueOrChildren(configuration))
             {
                 return;
             }
 
+            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+
             if (type == typeof(Program.MyClass))
             {
                 var temp = (Program.MyClass)obj;
@@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -88,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
 
             if (configuration["MyInt"] is string value1)
@@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 var value = new Program.MyClass2();
@@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -134,11 +134,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index a57f652..5848c24 100644 (file)
@@ -2,64 +2,84 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedServiceCollectionBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
-    public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
-    {
-        return global::GeneratedServiceCollectionBinder.Configure<TOptions>(services, string.Empty, configuration, configureOptions);
-    }
+    using System;
+    using System.CodeDom.Compiler;
 
-    /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
-    public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
     {
-        if (services is null)
-        {
-            throw new global::System.ArgumentNullException(nameof(services));
-        }
-
-        if (configuration is null)
+        public InterceptsLocationAttribute(string filePath, int line, int column)
         {
-            throw new global::System.ArgumentNullException(nameof(configuration));
         }
-
-        global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
-        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
-        return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
     }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
     using Microsoft.Extensions.Configuration;
+    using Microsoft.Extensions.DependencyInjection;
     using System;
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IServiceCollection extensions.
+        /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
+        public static IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
+        {
+            return Configure<TOptions>(services, string.Empty, configuration, configureOptions);
+        }
+
+        /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
+        public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
+        {
+            if (services is null)
+            {
+                throw new ArgumentNullException(nameof(services));
+            }
+
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
+            OptionsServiceCollectionExtensions.AddOptions(services);
+            services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
+            return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
+        }
+        #endregion IServiceCollection extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
 
-        public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
+        public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
         {
             if (configuration is null)
             {
                 throw new ArgumentNullException(nameof(configuration));
             }
 
-            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+            if (obj is null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
 
             if (!HasValueOrChildren(configuration))
             {
                 return;
             }
 
+            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+
             if (type == typeof(Program.MyClass))
             {
                 var temp = (Program.MyClass)obj;
@@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -88,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
 
             if (configuration["MyInt"] is string value1)
@@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 var value = new Program.MyClass2();
@@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -134,11 +134,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 66975c3..91226d7 100644 (file)
@@ -2,64 +2,84 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedServiceCollectionBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
-    public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class
-    {
-        return global::GeneratedServiceCollectionBinder.Configure<TOptions>(services, name, configuration, configureOptions: null);
-    }
+    using System;
+    using System.CodeDom.Compiler;
 
-    /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
-    public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
     {
-        if (services is null)
-        {
-            throw new global::System.ArgumentNullException(nameof(services));
-        }
-
-        if (configuration is null)
+        public InterceptsLocationAttribute(string filePath, int line, int column)
         {
-            throw new global::System.ArgumentNullException(nameof(configuration));
         }
-
-        global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
-        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
-        return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
     }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
     using Microsoft.Extensions.Configuration;
+    using Microsoft.Extensions.DependencyInjection;
     using System;
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IServiceCollection extensions.
+        /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
+        public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration) where TOptions : class
+        {
+            return Configure<TOptions>(services, name, configuration, configureOptions: null);
+        }
+
+        /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
+        public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
+        {
+            if (services is null)
+            {
+                throw new ArgumentNullException(nameof(services));
+            }
+
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
+            OptionsServiceCollectionExtensions.AddOptions(services);
+            services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
+            return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
+        }
+        #endregion IServiceCollection extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
 
-        public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
+        public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
         {
             if (configuration is null)
             {
                 throw new ArgumentNullException(nameof(configuration));
             }
 
-            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+            if (obj is null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
 
             if (!HasValueOrChildren(configuration))
             {
                 return;
             }
 
+            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+
             if (type == typeof(Program.MyClass))
             {
                 var temp = (Program.MyClass)obj;
@@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -88,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
 
             if (configuration["MyInt"] is string value1)
@@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 var value = new Program.MyClass2();
@@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -134,11 +134,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 0263ef1..8c9ccaa 100644 (file)
@@ -2,58 +2,78 @@
 #nullable enable
 #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
 
-/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
-[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-internal static class GeneratedServiceCollectionBinder
+namespace System.Runtime.CompilerServices
 {
-    /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
-    public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
-    {
-        if (services is null)
-        {
-            throw new global::System.ArgumentNullException(nameof(services));
-        }
+    using System;
+    using System.CodeDom.Compiler;
 
-        if (configuration is null)
+    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
+    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+    file sealed class InterceptsLocationAttribute : Attribute
+    {
+        public InterceptsLocationAttribute(string filePath, int line, int column)
         {
-            throw new global::System.ArgumentNullException(nameof(configuration));
         }
-
-        global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
-        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
-        return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
     }
 }
 
 namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
     using Microsoft.Extensions.Configuration;
+    using Microsoft.Extensions.DependencyInjection;
     using System;
     using System.CodeDom.Compiler;
     using System.Collections.Generic;
     using System.Globalization;
+    using System.Runtime.CompilerServices;
 
-    /// <summary>Provide core binding logic.</summary>
     [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
-    file static class CoreBindingHelper
+    file static class BindingExtensions
     {
+        #region IServiceCollection extensions.
+        /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
+        [InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
+        public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
+        {
+            if (services is null)
+            {
+                throw new ArgumentNullException(nameof(services));
+            }
+
+            if (configuration is null)
+            {
+                throw new ArgumentNullException(nameof(configuration));
+            }
+
+            OptionsServiceCollectionExtensions.AddOptions(services);
+            services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
+            return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
+        }
+        #endregion IServiceCollection extensions.
+
+        #region Core binding extensions.
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
         private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
 
-        public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
+        public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
         {
             if (configuration is null)
             {
                 throw new ArgumentNullException(nameof(configuration));
             }
 
-            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+            if (obj is null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
 
             if (!HasValueOrChildren(configuration))
             {
                 return;
             }
 
+            BinderOptions? binderOptions = GetBinderOptions(configureOptions);
+
             if (type == typeof(Program.MyClass))
             {
                 var temp = (Program.MyClass)obj;
@@ -61,16 +81,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return;
             }
 
-            throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
+            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
         }
 
         public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -82,11 +97,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
 
             if (configuration["MyInt"] is string value1)
@@ -97,11 +107,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 var value = new Program.MyClass2();
@@ -112,11 +117,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             foreach (IConfigurationSection section in configuration.GetChildren())
             {
                 if (section.Value is string value)
@@ -128,11 +128,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
         public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
         {
-            if (obj is null)
-            {
-                throw new ArgumentNullException(nameof(obj));
-            }
-
             ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
 
             obj.MyString = configuration["MyString"]!;
@@ -167,6 +162,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             }
         }
 
+
         /// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
         public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
         {
@@ -219,7 +215,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
         
             if (binderOptions.BindNonPublicProperties)
             {
-                throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
+                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
             }
         
             return binderOptions;
@@ -236,5 +232,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
             }
         }
+        #endregion Core binding extensions.
     }
 }
index 8807dfb..c9eb9c7 100644 (file)
@@ -8,6 +8,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
 {
     public partial class ConfigurationBindingGeneratorTests
     {
+        #region IServiceCollection extensions.
         private string GetConfigureSource(string paramList) => $$"""
             using System.Collections.Generic;
             using Microsoft.Extensions.Configuration;
@@ -40,7 +41,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
                 }
             }
             """;
+        #endregion IServiceCollection extensions.
 
+        #region OptionsBuilder<T> extensions.
         [Fact]
         public async Task Configure_T() =>
             await VerifyAgainstBaselineUsingFile("Configure_T.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection);
@@ -126,5 +129,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
             await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(), extType: ExtensionClassType.OptionsBuilder);
             await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(@", _ => { }"), extType: ExtensionClassType.OptionsBuilder);
         }
+        #endregion OptionsBuilder<T> extensions.
     }
 }
index aba2a9f..b5c3fb4 100644 (file)
@@ -2,7 +2,6 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
-using System.Globalization;
 using System.Linq;
 using System.Threading.Tasks;
 using Microsoft.CodeAnalysis;
@@ -44,7 +43,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
 
         [Theory]
         [InlineData(LanguageVersion.Preview)]
-        [InlineData(LanguageVersion.CSharp11)]
         public async Task Bind(LanguageVersion langVersion) =>
             await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder);
 
@@ -651,7 +649,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
 
             await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, assessDiagnostics: (d) =>
             {
-                Console.WriteLine((d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count() , d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()));
+                Console.WriteLine((d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count(), d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()));
                 Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count());
                 Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count());
             });
index 5bc5145..a512c5e 100644 (file)
@@ -52,15 +52,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
             ServiceCollection,
         }
 
-        [Fact]
-        public async Task LangVersionMustBeCharp11OrHigher()
+        [Theory]
+        [InlineData(LanguageVersion.CSharp11)]
+        [InlineData(LanguageVersion.CSharp10)]
+        public async Task LangVersionMustBeCharp12OrHigher(LanguageVersion langVersion)
         {
-            var (d, r) = await RunGenerator(BindCallSampleCode, LanguageVersion.CSharp10);
+            var (d, r) = await RunGenerator(BindCallSampleCode, langVersion);
             Assert.Empty(r);
 
             Diagnostic diagnostic = Assert.Single(d);
             Assert.True(diagnostic.Id == "SYSLIB1102");
-            Assert.Contains("C# 11", diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture));
+            Assert.Contains("C# 12", diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture));
             Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);
         }
 
@@ -250,9 +252,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
             Assert.Single(r);
 
             string generatedSource = string.Join('\n', r[0].SourceText.Lines.Select(x => x.ToString()));
-            Assert.Contains($"public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass0 obj) => {{ }};", generatedSource);
-            Assert.Contains($"public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass1 obj, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => {{ }};", generatedSource);
-            Assert.Contains($"public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass2 obj) => {{ }};", generatedSource);
+            Assert.Contains("public static void Bind_ProgramMyClass0(this IConfiguration configuration, object? obj)", generatedSource);
+            Assert.Contains("public static void Bind_ProgramMyClass1(this IConfiguration configuration, object? obj, Action<BinderOptions>? configureOptions)", generatedSource);
+            Assert.Contains("public static void Bind_ProgramMyClass2(this IConfiguration configuration, string key, object? obj)", generatedSource);
 
             Assert.Empty(d);
         }
@@ -395,7 +397,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
 
         private static async Task<(ImmutableArray<Diagnostic>, ImmutableArray<GeneratedSourceResult>)> RunGenerator(
             string testSourceCode,
-            LanguageVersion langVersion = LanguageVersion.CSharp11,
+            LanguageVersion langVersion = LanguageVersion.Preview,
             IEnumerable<Assembly>? references = null) =>
             await RoslynTestUtils.RunGenerator(
                 new ConfigurationBindingGenerator(),
index 2108bc2..cfd45c3 100644 (file)
@@ -4,7 +4,7 @@
     <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
     <!-- Type not supported; property on type not suppported -->
     <NoWarn>SYSLIB1100,SYSLIB1101</NoWarn>
-    <!-- The SDK disables the configuration binding generator by default no matter how it was referenced, so we need to enable it here for testing. -->
+    <Features>$(Features);InterceptorsPreview</Features>
     <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
   </PropertyGroup>
 
index 545e286..c007414 100644 (file)
@@ -3,6 +3,7 @@
   <PropertyGroup>
     <TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
     <EnableDefaultItems>true</EnableDefaultItems>
+    <Features>$(Features);InterceptorsPreview</Features>
     <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
     <IsPackable>true</IsPackable>
     <PackageDescription>Configuration support for Microsoft.Extensions.Logging.</PackageDescription>
index abc5c9d..0dceab4 100644 (file)
@@ -7,7 +7,9 @@
     <DefineConstants>$(DefineConstants);NO_SUPPRESS_GC_TRANSITION</DefineConstants>
     <IncludePlatformAttributes>true</IncludePlatformAttributes>
     <IsPackable>true</IsPackable>
+    <Features>$(Features);InterceptorsPreview</Features>
     <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
+    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
     <PackageDescription>Console logger provider implementation for Microsoft.Extensions.Logging.</PackageDescription>
   </PropertyGroup>
 
index f1843eb..0676fdd 100644 (file)
@@ -2,9 +2,9 @@
   <PropertyGroup>
     <Nullable>enable</Nullable>
     <TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkMinimum)</TargetFrameworks>
-    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
     <DefineConstants>$(DefineConstants);BUILDING_SOURCE_GENERATOR_TESTS;ROSLYN4_0_OR_GREATER;ROSLYN4_4_OR_GREATER</DefineConstants>
-    <!-- The SDK disables the configuration binding generator by default no matter how it was referenced, so we need to enable it here for testing. -->
+    <Features>$(Features);InterceptorsPreview</Features>
+    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
     <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
   </PropertyGroup>