| File: RuntimeSource\Configuration.Binder\Parser\BinderInvocation.cs | Web Access |
| Project: src\src\Tools\ConfigurationSchemaGenerator\ConfigurationSchemaGenerator.csproj (ConfigurationSchemaGenerator) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { internal sealed class BinderInvocation { private BinderInvocation(IInvocationOperation operation, Location location) { Operation = operation; Location = location; } public IInvocationOperation Operation { get; } public Location Location { get; } public static BinderInvocation? Create(GeneratorSyntaxContext context, CancellationToken cancellationToken) { Debug.Assert(IsCandidateSyntaxNode(context.Node)); InvocationExpressionSyntax invocationSyntax = (InvocationExpressionSyntax)context.Node; return context.SemanticModel.GetOperation(invocationSyntax, cancellationToken) is IInvocationOperation operation && IsBindingOperation(operation) ? new BinderInvocation(operation, invocationSyntax.GetLocation()) : null; } public static bool IsCandidateSyntaxNode(SyntaxNode node) { return node is InvocationExpressionSyntax { // TODO: drill further into this evaluation for a declaring-type name check. // https://github.com/dotnet/runtime/issues/90687. Expression: MemberAccessExpressionSyntax { Name.Identifier.ValueText: string memberName, } } && IsCandidateBindingMethodName(memberName); static bool IsCandidateBindingMethodName(string name) => IsValidMethodName_ConfigurationBinder(name) || IsValidMethodName_OptionsBuilderConfigurationExtensions(name) || IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(name); } public static bool IsBindingOperation(IInvocationOperation operation) { if (operation.TargetMethod is not IMethodSymbol { IsExtensionMethod: true, Name: string methodName, ContainingType: INamedTypeSymbol { Name: string containingTypeName, ContainingNamespace: INamespaceSymbol containingNamespace, } }) { return false; } string containingNamespaceName = containingNamespace.ToDisplayString(); return (containingTypeName) switch { "ConfigurationBinder" => containingNamespaceName is "Microsoft.Extensions.Configuration" && IsValidMethodName_ConfigurationBinder(methodName), "OptionsBuilderConfigurationExtensions" => containingNamespaceName is "Microsoft.Extensions.DependencyInjection" && IsValidMethodName_OptionsBuilderConfigurationExtensions(methodName), "OptionsConfigurationServiceCollectionExtensions" => containingNamespaceName is "Microsoft.Extensions.DependencyInjection" && IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(methodName), _ => false, }; } private static bool IsValidMethodName_ConfigurationBinder(string name) => name is "Bind" or "Get" or "GetValue"; private static bool IsValidMethodName_OptionsBuilderConfigurationExtensions(string name) => name is "Bind" or "BindConfiguration"; private static bool IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(string name) => name is "Configure"; } }