|
// 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;
}
}
|