diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs index f49deca75971c..7b40f198e08f2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs @@ -111,7 +111,9 @@ internal enum MethodsToGen_Extensions_OptionsBuilder // Method group. BindConfiguration_T is its own method group. Bind = Bind_T | Bind_T_BinderOptions, - Any = Bind | BindConfiguration_T_path_BinderOptions, + BindConfiguration = BindConfiguration_T_path_BinderOptions, + + Any = Bind | BindConfiguration, } /// diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs index eac828ada0d4c..3029a8de34f9e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs @@ -1,10 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis; -using System.Threading; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -15,8 +15,9 @@ internal sealed record BinderInvocation public static BinderInvocation? Create(GeneratorSyntaxContext context, CancellationToken cancellationToken) { - if (context.Node is not InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax } invocationSyntax || - context.SemanticModel.GetOperation(invocationSyntax, cancellationToken) is not IInvocationOperation operation) + if (!IsCandidateInvocationExpressionSyntax(context.Node, out InvocationExpressionSyntax? invocationSyntax) || + context.SemanticModel.GetOperation(invocationSyntax, cancellationToken) is not IInvocationOperation operation || + !IsCandidateInvocation(operation)) { return null; } @@ -27,5 +28,72 @@ internal sealed record BinderInvocation Location = invocationSyntax.GetLocation() }; } + + private static bool IsCandidateInvocationExpressionSyntax(SyntaxNode node, out InvocationExpressionSyntax? invocationSyntax) + { + if (node is InvocationExpressionSyntax + { + Expression: MemberAccessExpressionSyntax + { + Name.Identifier.ValueText: string memberName + } + } syntax && IsCandidateBindingMethodName(memberName)) + { + invocationSyntax = syntax; + return true; + } + + invocationSyntax = null; + return false; + + static bool IsCandidateBindingMethodName(string name) => + IsCandidateMethodName_ConfigurationBinder(name) || + IsCandidateMethodName_OptionsBuilderConfigurationExtensions(name) || + IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(name); + } + + private static bool IsCandidateInvocation(IInvocationOperation operation) + { + if (operation.TargetMethod is not IMethodSymbol + { + IsExtensionMethod: true, + Name: string methodName, + ContainingType: ITypeSymbol + { + Name: string containingTypeName, + ContainingNamespace: INamespaceSymbol { } containingNamespace, + } containingType + } method || + containingNamespace.ToDisplayString() is not string containingNamespaceName) + { + return false; + } + + return (containingTypeName) switch + { + "ConfigurationBinder" => + containingNamespaceName is "Microsoft.Extensions.Configuration" && + IsCandidateMethodName_ConfigurationBinder(methodName), + "OptionsBuilderConfigurationExtensions" => + containingNamespaceName is "Microsoft.Extensions.DependencyInjection" && + IsCandidateMethodName_OptionsBuilderConfigurationExtensions(methodName), + "OptionsConfigurationServiceCollectionExtensions" => + containingNamespaceName is "Microsoft.Extensions.DependencyInjection" && + IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(methodName), + _ => false, + }; + } + + private static bool IsCandidateMethodName_ConfigurationBinder(string name) => name is + nameof(MethodsToGen_ConfigurationBinder.Bind) or + nameof(MethodsToGen_ConfigurationBinder.Get) or + nameof(MethodsToGen_ConfigurationBinder.GetValue); + + private static bool IsCandidateMethodName_OptionsBuilderConfigurationExtensions(string name) => name is + nameof(MethodsToGen_Extensions_OptionsBuilder.Bind) or + nameof(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration); + + private static bool IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(string name) => name is + nameof(MethodsToGen_Extensions_ServiceCollection.Configure); } }