File: src\Workspaces\SharedUtilitiesAndExtensions\Compiler\CSharp\Extensions\AttributeArgumentSyntaxExtensions.cs
Web Access
Project: src\src\CodeStyle\CSharp\Analyzers\Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj (Microsoft.CodeAnalysis.CSharp.CodeStyle)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;
 
namespace Microsoft.CodeAnalysis.CSharp.Extensions;
 
internal static class AttributeArgumentSyntaxExtensions
{
    /// <summary>
    /// Returns the parameter to which this argument is passed. If <paramref name="allowParams"/>
    /// is true, the last parameter will be returned if it is params parameter and the index of
    /// the specified argument is greater than the number of parameters.
    /// </summary>
    /// <remarks>
    /// Returns null if the <paramref name="argument"/> is a named argument.
    /// </remarks>
    public static IParameterSymbol? DetermineParameter(
        this AttributeArgumentSyntax argument,
        SemanticModel semanticModel,
        bool allowUncertainCandidates = false,
        bool allowParams = false,
        CancellationToken cancellationToken = default)
    {
        // if argument is a named argument it can't map to a parameter.
        if (argument.NameEquals != null)
            return null;
 
        if (argument.Parent is not AttributeArgumentListSyntax argumentList)
            return null;
 
        if (argumentList.Parent is not AttributeSyntax invocableExpression)
            return null;
 
        var symbols = semanticModel.GetSymbolInfo(invocableExpression, cancellationToken).GetBestOrAllSymbols();
        if (symbols.Length >= 2 && !allowUncertainCandidates)
            return null;
 
        foreach (var symbol in symbols)
        {
            var parameters = symbol.GetParameters();
 
            // Handle named argument
            if (argument.NameColon != null && !argument.NameColon.IsMissing)
            {
                var name = argument.NameColon.Name.Identifier.ValueText;
                var parameter = parameters.FirstOrDefault(p => p.Name == name);
                if (parameter != null)
                    return parameter;
 
                continue;
            }
 
            // Handle positional argument
            var index = argumentList.Arguments.IndexOf(argument);
            if (index < 0)
                continue;
 
            if (index < parameters.Length)
                return parameters[index];
 
            if (allowParams)
            {
                var lastParameter = parameters.LastOrDefault();
                if (lastParameter == null)
                    continue;
 
                if (lastParameter.IsParams)
                    return lastParameter;
            }
        }
 
        return null;
    }
}