File: SignatureHelp\SignatureHelpUtilities.cs
Web Access
Project: src\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.Features)
// 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;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.SignatureHelp;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Shared.Extensions;
 
namespace Microsoft.CodeAnalysis.CSharp.SignatureHelp;
 
internal static class SignatureHelpUtilities
{
    private static readonly Func<BaseArgumentListSyntax, SyntaxToken> s_getBaseArgumentListOpenToken = list => list.GetOpenToken();
    private static readonly Func<TypeArgumentListSyntax, SyntaxToken> s_getTypeArgumentListOpenToken = list => list.LessThanToken;
    private static readonly Func<InitializerExpressionSyntax, SyntaxToken> s_getInitializerExpressionOpenToken = e => e.OpenBraceToken;
    private static readonly Func<AttributeArgumentListSyntax, SyntaxToken> s_getAttributeArgumentListOpenToken = list => list.OpenParenToken;
 
    private static readonly Func<BaseArgumentListSyntax, SyntaxToken> s_getBaseArgumentListCloseToken = list => list.GetCloseToken();
    private static readonly Func<TypeArgumentListSyntax, SyntaxToken> s_getTypeArgumentListCloseToken = list => list.GreaterThanToken;
    private static readonly Func<InitializerExpressionSyntax, SyntaxToken> s_getInitializerExpressionCloseToken = e => e.CloseBraceToken;
    private static readonly Func<AttributeArgumentListSyntax, SyntaxToken> s_getAttributeArgumentListCloseToken = list => list.CloseParenToken;
 
    private static readonly Func<BaseArgumentListSyntax, SyntaxNodeOrTokenList> s_getBaseArgumentListArgumentsWithSeparators =
        list => list.Arguments.GetWithSeparators();
    private static readonly Func<TypeArgumentListSyntax, SyntaxNodeOrTokenList> s_getTypeArgumentListArgumentsWithSeparators =
        list => list.Arguments.GetWithSeparators();
    private static readonly Func<InitializerExpressionSyntax, SyntaxNodeOrTokenList> s_getInitializerExpressionArgumentsWithSeparators =
        e => e.Expressions.GetWithSeparators();
    private static readonly Func<AttributeArgumentListSyntax, SyntaxNodeOrTokenList> s_getAttributeArgumentListArgumentsWithSeparators =
        list => list.Arguments.GetWithSeparators();
 
    private static readonly Func<BaseArgumentListSyntax, IEnumerable<string?>> s_getBaseArgumentListNames =
        list => list.Arguments.Select(argument => argument.NameColon?.Name.Identifier.ValueText);
    private static readonly Func<TypeArgumentListSyntax, IEnumerable<string?>> s_getTypeArgumentListNames =
        list => list.Arguments.Select(a => (string?)null);
    private static readonly Func<InitializerExpressionSyntax, IEnumerable<string?>> s_getInitializerExpressionNames =
        e => e.Expressions.Select(a => (string?)null);
    private static readonly Func<AttributeArgumentListSyntax, IEnumerable<string?>> s_getAttributeArgumentListNames =
        list => list.Arguments.Select(
            argument => argument.NameColon?.Name.Identifier.ValueText ?? argument.NameEquals?.Name.Identifier.ValueText);
 
    public static SignatureHelpState? GetSignatureHelpState(BaseArgumentListSyntax argumentList, int position)
    {
        return CommonSignatureHelpUtilities.GetSignatureHelpState(
            argumentList, position,
            s_getBaseArgumentListOpenToken,
            s_getBaseArgumentListCloseToken,
            s_getBaseArgumentListArgumentsWithSeparators,
            s_getBaseArgumentListNames);
    }
 
    internal static SignatureHelpState? GetSignatureHelpState(TypeArgumentListSyntax argumentList, int position)
    {
        return CommonSignatureHelpUtilities.GetSignatureHelpState(
            argumentList, position,
            s_getTypeArgumentListOpenToken,
            s_getTypeArgumentListCloseToken,
            s_getTypeArgumentListArgumentsWithSeparators,
            s_getTypeArgumentListNames);
    }
 
    internal static SignatureHelpState? GetSignatureHelpState(InitializerExpressionSyntax argumentList, int position)
    {
        return CommonSignatureHelpUtilities.GetSignatureHelpState(
            argumentList, position,
            s_getInitializerExpressionOpenToken,
            s_getInitializerExpressionCloseToken,
            s_getInitializerExpressionArgumentsWithSeparators,
            s_getInitializerExpressionNames);
    }
 
    internal static SignatureHelpState? GetSignatureHelpState(AttributeArgumentListSyntax argumentList, int position)
    {
        return CommonSignatureHelpUtilities.GetSignatureHelpState(
            argumentList, position,
            s_getAttributeArgumentListOpenToken,
            s_getAttributeArgumentListCloseToken,
            s_getAttributeArgumentListArgumentsWithSeparators,
            s_getAttributeArgumentListNames);
    }
 
    internal static TextSpan GetSignatureHelpSpan(BaseArgumentListSyntax argumentList)
        => CommonSignatureHelpUtilities.GetSignatureHelpSpan(argumentList, s_getBaseArgumentListCloseToken);
 
    internal static TextSpan GetSignatureHelpSpan(TypeArgumentListSyntax argumentList)
        => CommonSignatureHelpUtilities.GetSignatureHelpSpan(argumentList, s_getTypeArgumentListCloseToken);
 
    internal static TextSpan GetSignatureHelpSpan(InitializerExpressionSyntax initializer)
        => CommonSignatureHelpUtilities.GetSignatureHelpSpan(initializer, initializer.SpanStart, s_getInitializerExpressionCloseToken);
 
    internal static TextSpan GetSignatureHelpSpan(AttributeArgumentListSyntax argumentList)
        => CommonSignatureHelpUtilities.GetSignatureHelpSpan(argumentList, s_getAttributeArgumentListCloseToken);
 
    internal static bool IsTriggerParenOrComma<TSyntaxNode>(SyntaxToken token, Func<char, bool> isTriggerCharacter) where TSyntaxNode : SyntaxNode
    {
        // Don't dismiss if the user types ( to start a parenthesized expression or tuple
        // Note that the tuple initially parses as a parenthesized expression 
        if (token.IsKind(SyntaxKind.OpenParenToken) &&
            token.Parent is ParenthesizedExpressionSyntax parenExpr)
        {
            var parenthesizedExpr = parenExpr.WalkUpParentheses();
            if (parenthesizedExpr.Parent is ArgumentSyntax)
            {
                var parent = parenthesizedExpr.Parent;
                var grandParent = parent.Parent;
                if (grandParent is ArgumentListSyntax && grandParent.Parent is TSyntaxNode)
                {
                    // Argument to TSyntaxNode's argument list
                    return true;
                }
                else
                {
                    // Argument to a tuple in TSyntaxNode's argument list
                    return grandParent is TupleExpressionSyntax && parenthesizedExpr.GetAncestor<TSyntaxNode>() != null;
                }
            }
            else
            {
                // Not an argument
                return false;
            }
        }
 
        // Don't dismiss if the user types ',' to add a member to a tuple
        if (token.IsKind(SyntaxKind.CommaToken) && token.Parent is TupleExpressionSyntax && token.GetAncestor<TSyntaxNode>() != null)
        {
            return true;
        }
 
        return !token.IsKind(SyntaxKind.None) &&
            token.ValueText.Length == 1 &&
            isTriggerCharacter(token.ValueText[0]) &&
            token.Parent is ArgumentListSyntax &&
            token.Parent.Parent is TSyntaxNode;
    }
}