File: SignatureHelp\ElementAccessExpressionSignatureHelpProviderTests.cs
Web Access
Project: src\src\EditorFeatures\CSharpTest\Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests)
// 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.
 
#nullable disable
 
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.SignatureHelp;
using Microsoft.CodeAnalysis.Editor.UnitTests.SignatureHelp;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SignatureHelp;
 
[Trait(Traits.Feature, Traits.Features.SignatureHelp)]
public class ElementAccessExpressionSignatureHelpProviderTests : AbstractCSharpSignatureHelpProviderTests
{
    internal override Type GetSignatureHelpProviderType()
        => typeof(ElementAccessExpressionSignatureHelpProvider);
 
    #region "Regular tests"
 
    [Fact]
    public async Task TestInvocationWithParametersOn1()
    {
        var markup = """
            class C
            {
                public string this[int a]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    var x = [|c[$$|]];
                }
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string C[int a]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestAsync(markup, expectedOrderedItems);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24311")]
    public async Task TestInvocationWithParametersOn1_WithRefReturn()
    {
        var markup = """
            class C
            {
                public ref int this[int a]
                {
                    get { throw null; }
                }
                void Goo(C c)
                {
                    [|c[$$]|]
                }
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("ref int C[int a]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestAsync(markup, expectedOrderedItems);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24311")]
    public async Task TestInvocationWithParametersOn1_WithRefReadonlyReturn()
    {
        var markup = """
            class C
            {
                public ref readonly int this[int a]
                {
                    get { throw null; }
                }
                void Goo(C c)
                {
                    [|c[$$]|]
                }
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("ref readonly int C[int a]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestAsync(markup, expectedOrderedItems);
    }
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/636117")]
    public async Task TestInvocationOnExpression()
    {
        var markup = """
            class C
            {
                public string this[int a]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    C[] c = new C[1];
                    c[0][$$
                }
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string C[int a]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestAsync(markup, expectedOrderedItems);
    }
 
    [Fact]
    public async Task TestInvocationWithParametersXmlCommentsOn1()
    {
        var markup = """
            class C
            {
                /// <summary>
                /// Summary for this.
                /// </summary>
                /// <param name="a">Param a</param>
                public string this[int a]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    var x = [|c[$$|]];
                }
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string C[int a]", "Summary for this.", "Param a", currentParameterIndex: 0)
        };
 
        await TestAsync(markup, expectedOrderedItems);
    }
 
    [Fact]
    public async Task TestInvocationWithParametersOn2()
    {
        var markup = """
            class C
            {
                public string this[int a, bool b]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    var x = [|c[22, $$|]];
                }
            }
            """;
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string C[int a, bool b]", string.Empty, string.Empty, currentParameterIndex: 1)
        };
 
        await TestAsync(markup, expectedOrderedItems);
    }
 
    [Fact]
    public async Task TestInvocationWithParametersXmlComentsOn2()
    {
        var markup = """
            class C
            {
                /// <summary>
                /// Summary for this.
                /// </summary>
                /// <param name="a">Param a</param>
                /// <param name="b">Param b</param>
                public string this[int a, bool b]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    var x = [|c[22, $$|]];
                }
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string C[int a, bool b]", "Summary for this.", "Param b", currentParameterIndex: 1)
        };
 
        await TestAsync(markup, expectedOrderedItems);
    }
 
    [Fact]
    public async Task TestInvocationWithoutClosingBracketWithParameters()
    {
        var markup =
            """
            class C
            {
                public string this[int a]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    var x = [|c[$$
                |]}
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string C[int a]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestAsync(markup, expectedOrderedItems);
    }
 
    [Fact]
    public async Task TestInvocationWithoutClosingBracketWithParametersOn2()
    {
        var markup = """
            class C
            {
                public string this[int a, bool b]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    var x = [|c[22, $$
                |]}
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string C[int a, bool b]", string.Empty, string.Empty, currentParameterIndex: 1)
        };
 
        await TestAsync(markup, expectedOrderedItems);
    }
 
    #endregion
 
    #region "Current Parameter Name"
 
    [Fact]
    public async Task TestCurrentParameterName()
    {
        var markup = """
            class C
            {
                public string this[int a, bool b]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    var x = [|c[b: false, a: $$42|]];
                }
            }
            """;
 
        await VerifyCurrentParameterNameAsync(markup, "a");
    }
 
    #endregion
 
    #region "Trigger tests"
 
    [Fact]
    public async Task TestInvocationOnTriggerBracket()
    {
        var markup = """
            class C
            {
                public string this[int a]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    var x = [|c[$$|]];
                }
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string C[int a]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true);
    }
 
    [Fact]
    public async Task TestInvocationOnTriggerComma()
    {
        var markup = """
            class C
            {
                public string this[int a, bool b]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    var x = [|c[42,$$|]];
                }
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string C[int a, bool b]", string.Empty, string.Empty, currentParameterIndex: 1)
        };
 
        await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true);
    }
 
    [Fact]
    public async Task TestNoInvocationOnSpace()
    {
        var markup = """
            class C
            {
                public string this[int a, bool b]
                {
                    get { return null; }
                    set { }
                }
            }
 
            class D
            {
                void Goo()
                {
                    var c = new C();
                    var x = [|c[42, $$|]];
                }
            }
            """;
 
        var expectedOrderedItems = new List<SignatureHelpTestItem>();
        await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true);
    }
 
    [Fact]
    public void TestTriggerCharacters()
    {
        char[] expectedCharacters = [',', '['];
        char[] unexpectedCharacters = [' ', '(', '<'];
 
        VerifyTriggerCharacters(expectedCharacters, unexpectedCharacters);
    }
 
    #endregion
 
    #region "EditorBrowsable tests"
 
    [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")]
    public async Task EditorBrowsable_Indexer_PropertyAlways()
    {
        var markup = """
            class Program
            {
                void M()
                {
                    new Goo()[$$
                }
            }
            """;
 
        var referencedCode = """
            public class Goo
            {
                [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)]
                public int this[int x]
                {
                    get { return 5; }
                    set { }
                }
            }
            """;
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("int Goo[int x]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup,
                                            referencedCode: referencedCode,
                                            expectedOrderedItemsMetadataReference: expectedOrderedItems,
                                            expectedOrderedItemsSameSolution: expectedOrderedItems,
                                            sourceLanguage: LanguageNames.CSharp,
                                            referencedLanguage: LanguageNames.CSharp);
    }
 
    [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")]
    public async Task EditorBrowsable_Indexer_PropertyNever()
    {
        var markup = """
            class Program
            {
                void M()
                {
                    new Goo()[$$
                }
            }
            """;
 
        var referencedCode = """
            public class Goo
            {
                [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
                public int this[int x]
                {
                    get { return 5; }
                    set { }
                }
            }
            """;
        var expectedOrderedItemsMetadataReference = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("int Goo[int x]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup,
                                            referencedCode: referencedCode,
                                            expectedOrderedItemsMetadataReference: new List<SignatureHelpTestItem>(),
                                            expectedOrderedItemsSameSolution: expectedOrderedItemsMetadataReference,
                                            sourceLanguage: LanguageNames.CSharp,
                                            referencedLanguage: LanguageNames.CSharp);
    }
 
    [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")]
    public async Task EditorBrowsable_Indexer_PropertyAdvanced()
    {
        var markup = """
            class Program
            {
                void M()
                {
                    new Goo()[$$
                }
            }
            """;
 
        var referencedCode = """
            public class Goo
            {
                [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
                public int this[int x]
                {
                    get { return 5; }
                    set { }
                }
            }
            """;
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("int Goo[int x]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup,
            referencedCode: referencedCode,
            expectedOrderedItemsMetadataReference: new List<SignatureHelpTestItem>(),
            expectedOrderedItemsSameSolution: expectedOrderedItems,
            sourceLanguage: LanguageNames.CSharp,
            referencedLanguage: LanguageNames.CSharp,
            hideAdvancedMembers: true);
 
        await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup,
            referencedCode: referencedCode,
            expectedOrderedItemsMetadataReference: expectedOrderedItems,
            expectedOrderedItemsSameSolution: expectedOrderedItems,
            sourceLanguage: LanguageNames.CSharp,
            referencedLanguage: LanguageNames.CSharp,
            hideAdvancedMembers: false);
    }
 
    [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")]
    public async Task EditorBrowsable_Indexer_PropertyNeverOnOneOfTwoOverloads()
    {
        var markup = """
            class Program
            {
                void M()
                {
                    new Goo()[$$
                }
            }
            """;
 
        var referencedCode = """
            public class Goo
            {
                [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
                public int this[int x]
                {
                    get { return 5; }
                    set { }
                }
 
                public int this[double d]
                {
                    get { return 5; }
                    set { }
                }
            }
            """;
 
        var expectedOrderedItemsMetadataReference = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("int Goo[double d]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        var expectedOrderedItemsSameSolution = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("int Goo[double d]", string.Empty, string.Empty, currentParameterIndex: 0),
            new SignatureHelpTestItem("int Goo[int x]", string.Empty, string.Empty, currentParameterIndex: 0),
        };
 
        await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup,
                                            referencedCode: referencedCode,
                                            expectedOrderedItemsMetadataReference: expectedOrderedItemsMetadataReference,
                                            expectedOrderedItemsSameSolution: expectedOrderedItemsSameSolution,
                                            sourceLanguage: LanguageNames.CSharp,
                                            referencedLanguage: LanguageNames.CSharp);
    }
 
    [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")]
    public async Task EditorBrowsable_Indexer_GetBrowsableNeverIgnored()
    {
        var markup = """
            class Program
            {
                void M()
                {
                    new Goo()[$$
                }
            }
            """;
 
        var referencedCode = """
            public class Goo
            {
                public int this[int x]
                {
                    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
                    get { return 5; }
                    set { }
                }
            }
            """;
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("int Goo[int x]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup,
                                            referencedCode: referencedCode,
                                            expectedOrderedItemsMetadataReference: expectedOrderedItems,
                                            expectedOrderedItemsSameSolution: expectedOrderedItems,
                                            sourceLanguage: LanguageNames.CSharp,
                                            referencedLanguage: LanguageNames.CSharp);
    }
 
    [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")]
    public async Task EditorBrowsable_Indexer_SetBrowsableNeverIgnored()
    {
        var markup = """
            class Program
            {
                void M()
                {
                    new Goo()[$$
                }
            }
            """;
 
        var referencedCode = """
            public class Goo
            {
                public int this[int x]
                {
                    get { return 5; }
                    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
                    set { }
                }
            }
            """;
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("int Goo[int x]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup,
                                            referencedCode: referencedCode,
                                            expectedOrderedItemsMetadataReference: expectedOrderedItems,
                                            expectedOrderedItemsSameSolution: expectedOrderedItems,
                                            sourceLanguage: LanguageNames.CSharp,
                                            referencedLanguage: LanguageNames.CSharp);
    }
 
    [Fact, WorkItem(7336, "DevDiv_Projects/Roslyn")]
    public async Task EditorBrowsable_Indexer_GetSetBrowsableNeverIgnored()
    {
        var markup = """
            class Program
            {
                void M()
                {
                    new Goo()[$$
                }
            }
            """;
 
        var referencedCode = """
            public class Goo
            {
                public int this[int x]
                {
                    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
                    get { return 5; }
                    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
                    set { }
                }
            }
            """;
        var expectedOrderedItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("int Goo[int x]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup,
                                            referencedCode: referencedCode,
                                            expectedOrderedItemsMetadataReference: expectedOrderedItems,
                                            expectedOrderedItemsSameSolution: expectedOrderedItems,
                                            sourceLanguage: LanguageNames.CSharp,
                                            referencedLanguage: LanguageNames.CSharp);
    }
 
    #endregion
 
    #region Indexed Property tests
 
    [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530811")]
    public async Task IndexedProperty()
    {
        var markup = """
            class Program
            {
                void M()
                {
                        CCC c = new CCC();
                        c.IndexProp[$$
                }
            }
            """;
 
        // Note that <COMImport> is required by compiler.  Bug 17013 tracks enabling indexed property for non-COM types.
        var referencedCode = """
            Imports System.Runtime.InteropServices
 
            <ComImport()>
            <GuidAttribute(CCC.ClassId)>
            Public Class CCC
 
            #Region "COM GUIDs"
                Public Const ClassId As String = "9d965fd2-1514-44f6-accd-257ce77c46b0"
                Public Const InterfaceId As String = "a9415060-fdf0-47e3-bc80-9c18f7f39cf6"
                Public Const EventsId As String = "c6a866a5-5f97-4b53-a5df-3739dc8ff1bb"
            # End Region
 
                        ''' <summary>
                ''' An index property from VB
                ''' </summary>
                ''' <param name="p1">p1 is an integer index</param>
                ''' <returns>A string</returns>
                Public Property IndexProp(ByVal p1 As Integer) As String
                    Get
                        Return Nothing
                    End Get
                    Set(ByVal value As String)
 
                    End Set
                End Property
            End Class
            """;
 
        var metadataItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string CCC.IndexProp[int p1]", string.Empty, string.Empty, currentParameterIndex: 0)
        };
 
        var projectReferenceItems = new List<SignatureHelpTestItem>
        {
            new SignatureHelpTestItem("string CCC.IndexProp[int p1]", "An index property from VB", "p1 is an integer index", currentParameterIndex: 0)
        };
 
        await TestSignatureHelpInEditorBrowsableContextsAsync(markup: markup,
                                           referencedCode: referencedCode,
                                           expectedOrderedItemsMetadataReference: metadataItems,
                                           expectedOrderedItemsSameSolution: projectReferenceItems,
                                           sourceLanguage: LanguageNames.CSharp,
                                           referencedLanguage: LanguageNames.VisualBasic);
    }
 
    #endregion
 
    [Fact]
    public async Task FieldUnavailableInOneLinkedFile()
    {
        var markup = """
            <Workspace>
                <Project Language="C#" CommonReferences="true" AssemblyName="Proj1" PreprocessorSymbols="GOO">
                    <Document FilePath="SourceDocument"><![CDATA[
            class C
            {
            #if GOO
                public int this[int z]
                {
                    get
                    {
                        return 0;
                    }
                }
            #endif
                void goo()
                {
                    var x = this[$$
                }
            }
            ]]>
                    </Document>
                </Project>
                <Project Language="C#" CommonReferences="true" AssemblyName="Proj2">
                    <Document IsLinkFile="true" LinkAssemblyName="Proj1" LinkFilePath="SourceDocument"/>
                </Project>
            </Workspace>
            """;
        var expectedDescription = new SignatureHelpTestItem($"int C[int z]\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0);
        await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false);
    }
 
    [Fact]
    public async Task ExcludeFilesWithInactiveRegions()
    {
        var markup = """
            <Workspace>
                <Project Language="C#" CommonReferences="true" AssemblyName="Proj1" PreprocessorSymbols="GOO,BAR">
                    <Document FilePath="SourceDocument"><![CDATA[
            class C
            {
            #if GOO
                public int this[int z]
                {
                    get
                    {
                        return 0;
                    }
                }
            #endif
 
            #if BAR
                void goo()
                {
                    var x = this[$$
                }
            #endif
            }
            ]]>
                    </Document>
                </Project>
                <Project Language="C#" CommonReferences="true" AssemblyName="Proj2">
                    <Document IsLinkFile="true" LinkAssemblyName="Proj1" LinkFilePath="SourceDocument" />
                </Project>
                <Project Language="C#" CommonReferences="true" AssemblyName="Proj3" PreprocessorSymbols="BAR">
                    <Document IsLinkFile="true" LinkAssemblyName="Proj1" LinkFilePath="SourceDocument"/>
                </Project>
            </Workspace>
            """;
 
        var expectedDescription = new SignatureHelpTestItem($"int C[int z]\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0);
        await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false);
    }
 
    [Trait(Traits.Feature, Traits.Features.SignatureHelp)]
    public class IncompleteElementAccessExpressionSignatureHelpProviderTests : AbstractCSharpSignatureHelpProviderTests
    {
        internal override Type GetSignatureHelpProviderType()
            => typeof(ElementAccessExpressionSignatureHelpProvider);
 
        [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/636117")]
        public async Task TestInvocation()
        {
            var markup = """
                class C
                {
                    public string this[int a]
                    {
                        get { return null; }
                        set { }
                    }
                }
 
                class D
                {
                    void Goo()
                    {
                        var c = new C();
                        c[$$]
                    }
                }
                """;
 
            var expectedOrderedItems = new List<SignatureHelpTestItem>
            {
                new SignatureHelpTestItem("string C[int a]", string.Empty, string.Empty, currentParameterIndex: 0)
            };
 
            await TestAsync(markup, expectedOrderedItems);
        }
 
        [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/939417")]
        public async Task ConditionalIndexer()
        {
            var markup = """
                public class P
                {
                    public int this[int z]
                    {
                        get
                        {
                            return 0;
                        }
                    }
 
                    public void goo()
                    {
                        P p = null;
                        p?[$$]
                    }
                }
                """;
 
            var expectedOrderedItems = new List<SignatureHelpTestItem>
            {
                new SignatureHelpTestItem("int P[int z]", string.Empty, string.Empty, currentParameterIndex: 0)
            };
 
            await TestAsync(markup, expectedOrderedItems);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/32")]
        public async Task NonIdentifierConditionalIndexer()
        {
            var expected = new[] { new SignatureHelpTestItem("char string[int index]") };
            await TestAsync(
                """
                class C
                {
                    void M()
                    {
                        ""?[$$ }
                }
                """, expected); // inline with a string literal
            await TestAsync(
                """
                class C
                {
                    void M()
                    {
                        ""?[/**/$$ }
                }
                """, expected); // inline with a string literal and multiline comment
            await TestAsync(
                """
                class C
                {
                    void M()
                    {
                        ("")?[$$ }
                }
                """, expected); // parenthesized expression
            await TestAsync(
                """
                class C
                {
                    void M()
                    {
                        new System.String(' ', 1)?[$$ }
                }
                """, expected); // new object expression
 
            // more complicated parenthesized expression
            await TestAsync(
                """
                class C
                {
                    void M()
                    {
                        (null as System.Collections.Generic.List<int>)?[$$ }
                }
                """, [new SignatureHelpTestItem("int System.Collections.Generic.List<int>[int index]")]);
        }
 
        [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1067933")]
        public async Task InvokedWithNoToken()
        {
            var markup = """
                // goo[$$
                """;
 
            await TestAsync(markup);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/2482")]
        public async Task WhereExpressionLooksLikeArrayTypeSyntaxOfQualifiedName()
        {
            var markup = """
                class WithIndexer
                {
                    public int this[int index] { get { return 0; } }
                }
 
                class TestClass
                {
                    public WithIndexer Item { get; set; }
 
                    public void Method(TestClass tc)
                    {
                        // `tc.Item[]` parses as ArrayTypeSyntax with an ElementType of QualifiedNameSyntax
                        tc.Item[$$]
                    }
                }
                """;
            await TestAsync(markup, [new SignatureHelpTestItem("int WithIndexer[int index]")], usePreviousCharAsTrigger: true);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20507")]
        public async Task InConditionalIndexingFollowedByMemberAccess()
        {
            var markup = """
                class Indexable
                {
                    public Indexable this[int x] { get => null; }
 
                    Indexable Count;
 
                    static void Main(string[] args)
                    {
                        Indexable x;
                        x?[$$].Count;
                    }
                }
                """;
            await TestAsync(markup, [new SignatureHelpTestItem("Indexable Indexable[int x]")], usePreviousCharAsTrigger: false);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20507")]
        public async Task InConditionalIndexingFollowedByConditionalAccess()
        {
            var markup = """
                class Indexable
                {
                    public Indexable this[int x] { get => null; }
 
                    Indexable Count;
 
                    static void Main(string[] args)
                    {
                        Indexable x;
                        x?[$$].Count?.Count;
                    }
                }
                """;
            await TestAsync(markup, [new SignatureHelpTestItem("Indexable Indexable[int x]")], usePreviousCharAsTrigger: false);
        }
    }
}