-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Fix: Config binder generator doesn't generate code when named arguments are out of order #91961
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
269786b
Fix Named parameters bug
buyaa-n d4aa485
Test the generator only, don't compare generated file row by row
buyaa-n 70b7489
Add other named parameter combinatios for other overloads in the test…
buyaa-n 9ce6861
Merge branch 'main' of https://github.com/dotnet/runtime into named-p…
buyaa-n 30ba96f
Adjust line numbers with source generator updates
buyaa-n 0c82a9e
Move similar code section into helper method, don't exact exact line …
buyaa-n 0b4c78f
Apply feedbacks
buyaa-n File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
170 changes: 170 additions & 0 deletions
170
...ts/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_NamedParameters.generated.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| // <auto-generated/> | ||
buyaa-n marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #nullable enable | ||
| #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. | ||
|
|
||
| namespace System.Runtime.CompilerServices | ||
| { | ||
| 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 | ||
| { | ||
| using Microsoft.Extensions.Configuration; | ||
| using System; | ||
| using System.CodeDom.Compiler; | ||
| using System.Collections.Generic; | ||
| using System.Globalization; | ||
| using System.Runtime.CompilerServices; | ||
|
|
||
| [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] | ||
| file static class BindingExtensions | ||
| { | ||
| #region IConfiguration extensions. | ||
| /// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary> | ||
| [InterceptsLocation(@"src-0.cs", 12, 33)] | ||
| public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) | ||
| { | ||
| if (configuration is null) | ||
| { | ||
| throw new ArgumentNullException(nameof(configuration)); | ||
| } | ||
|
|
||
| if (instance is null) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| var typedObj = (Program.MyClass)instance; | ||
| 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> instance, BinderOptions? binderOptions) | ||
| { | ||
| foreach (IConfigurationSection section in configuration.GetChildren()) | ||
| { | ||
| if (section.Value is string value) | ||
| { | ||
| instance.Add(ParseInt(value, () => section.Path)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> instance, BinderOptions? binderOptions) | ||
| { | ||
| foreach (IConfigurationSection section in configuration.GetChildren()) | ||
| { | ||
| if (section.Value is string value) | ||
| { | ||
| instance[section.Key] = value; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> instance, BinderOptions? binderOptions) | ||
| { | ||
| foreach (IConfigurationSection section in configuration.GetChildren()) | ||
| { | ||
| if (!(instance.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) | ||
| { | ||
| element = new Program.MyClass2(); | ||
| } | ||
| instance[section.Key] = element; | ||
| } | ||
| } | ||
|
|
||
| public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) | ||
| { | ||
| ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); | ||
|
|
||
| instance.MyString = configuration["MyString"]!; | ||
|
|
||
| if (configuration["MyInt"] is string value1) | ||
| { | ||
| instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); | ||
| } | ||
|
|
||
| if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) | ||
| { | ||
| List<int>? temp4 = instance.MyList; | ||
| temp4 ??= new List<int>(); | ||
| BindCore(section2, ref temp4, binderOptions); | ||
| instance.MyList = temp4; | ||
| } | ||
|
|
||
| if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) | ||
| { | ||
| Dictionary<string, string>? temp7 = instance.MyDictionary; | ||
| temp7 ??= new Dictionary<string, string>(); | ||
| BindCore(section5, ref temp7, binderOptions); | ||
| instance.MyDictionary = temp7; | ||
| } | ||
|
|
||
| if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) | ||
| { | ||
| Dictionary<string, Program.MyClass2>? temp10 = instance.MyComplexDictionary; | ||
| temp10 ??= new Dictionary<string, Program.MyClass2>(); | ||
| BindCore(section8, ref temp10, binderOptions); | ||
| instance.MyComplexDictionary = temp10; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| /// <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) | ||
| { | ||
| if (binderOptions?.ErrorOnUnknownConfiguration is true) | ||
| { | ||
| List<string>? temp = null; | ||
|
|
||
| foreach (IConfigurationSection section in configuration.GetChildren()) | ||
| { | ||
| if (!keys.Value.Contains(section.Key)) | ||
| { | ||
| (temp ??= new List<string>()).Add($"'{section.Key}'"); | ||
| } | ||
| } | ||
|
|
||
| if (temp is not null) | ||
| { | ||
| throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) | ||
| { | ||
| foreach (IConfigurationSection _ in configuration.GetChildren()) | ||
| { | ||
| return configuration; | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| public static int ParseInt(string value, Func<string?> getPath) | ||
| { | ||
| try | ||
| { | ||
| return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); | ||
| } | ||
| catch (Exception exception) | ||
| { | ||
| throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); | ||
| } | ||
| } | ||
| #endregion Core binding extensions. | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.