File: AttributeArgumentSyntaxExtensions.cs
Web Access
Project: ..\..\..\src\Workspaces\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Workspaces.csproj (Microsoft.CodeAnalysis.CSharp.Workspaces)
// 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;
        }
    }
}