File: Classification\TotalClassifierTests.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.
 
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Editor.Tagging;
using Microsoft.CodeAnalysis.Editor.UnitTests.Classification;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Remote.Testing;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Tagging;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
using static Microsoft.CodeAnalysis.Editor.UnitTests.Classification.FormattedClassifications;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Classification;
 
[Trait(Traits.Feature, Traits.Features.Classification)]
public sealed partial class TotalClassifierTests : AbstractCSharpClassifierTests
{
    protected override async Task<ImmutableArray<ClassifiedSpan>> GetClassificationSpansAsync(string code, ImmutableArray<TextSpan> spans, ParseOptions? options, TestHost testHost)
    {
        using var workspace = CreateWorkspace(code, options, testHost);
        var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id);
 
        return await GetAllClassificationsAsync(document, spans);
    }
 
    [Theory, CombinatorialData]
    public Task VarAsUsingAliasForNamespace(TestHost testHost)
        => TestAsync(
            @"using var = System;",
            testHost,
            Keyword("using"),
            Namespace("var"),
            Operators.Equals,
            Namespace("System"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/547068")]
    public Task Bug17819(TestHost testHost)
        => TestAsync(
            """
            _ _()
            {
            }
            ///<param name='_
            }
            """,
            testHost,
            ParseOptions(Options.Regular),
            Method("_"),
            Method("_"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            XmlDoc.Delimiter("///"),
            XmlDoc.Delimiter("<"),
            XmlDoc.Name("param"),
            XmlDoc.AttributeName("name"),
            XmlDoc.Delimiter("="),
            XmlDoc.AttributeQuotes("'"),
            Identifier("_"),
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task VarAsUsingAliasForClass(TestHost testHost)
        => TestAsync(
@"using var = System.Math;",
            testHost,
            Keyword("using"),
            Class("var"),
            Operators.Equals,
            Namespace("System"),
            Operators.Dot,
            Class("Math"),
            Static("Math"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task VarAsUsingAliasForDelegate(TestHost testHost)
        => TestAsync(
@"using var = System.Action;",
            testHost,
            Keyword("using"),
            Delegate("var"),
            Operators.Equals,
            Namespace("System"),
            Operators.Dot,
            Delegate("Action"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task VarAsUsingAliasForStruct(TestHost testHost)
        => TestAsync(
@"using var = System.DateTime;",
            testHost,
            Keyword("using"),
            Struct("var"),
            Operators.Equals,
            Namespace("System"),
            Operators.Dot,
            Struct("DateTime"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task VarAsUsingAliasForEnum(TestHost testHost)
        => TestAsync(
@"using var = System.DayOfWeek;",
            testHost,
            Keyword("using"),
            Enum("var"),
            Operators.Equals,
            Namespace("System"),
            Operators.Dot,
            Enum("DayOfWeek"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task VarAsUsingAliasForInterface(TestHost testHost)
        => TestAsync(
@"using var = System.IDisposable;",
            testHost,
            Keyword("using"),
            Interface("var"),
            Operators.Equals,
            Namespace("System"),
            Operators.Dot,
            Interface("IDisposable"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task VarAsConstructorName(TestHost testHost)
        => TestAsync(
            """
            class var
            {
                var()
                {
                }
            }
            """,
            testHost,
            Keyword("class"),
            Class("var"),
            Punctuation.OpenCurly,
            Class("var"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestRecordClass(TestHost testHost)
        => TestAsync(
            """
            record class R
            {
                R()
                {
                }
            }
            """,
            testHost,
            Keyword("record"),
            Keyword("class"),
            RecordClass("R"),
            Punctuation.OpenCurly,
            RecordClass("R"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestRecordStruct(TestHost testHost)
        => TestAsync(
            """
            record struct R
            {
                R(int i)
                {
                }
            }
            """,
            testHost,
            Keyword("record"),
            Keyword("struct"),
            RecordStruct("R"),
            Punctuation.OpenCurly,
            RecordStruct("R"),
            Punctuation.OpenParen,
            Keyword("int"),
            Parameter("i"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task UsingAliasGlobalNamespace(TestHost testHost)
        => TestAsync(
@"using IO = global::System.IO;",
            testHost,
            Keyword("using"),
            Namespace("IO"),
            Operators.Equals,
            Keyword("global"),
            Operators.ColonColon,
            Namespace("System"),
            Operators.Dot,
            Namespace("IO"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task PartialDynamicWhere(TestHost testHost)
        => TestAsync("""
            partial class partial<where> where where : partial<where>
            {
                static dynamic dynamic<partial>()
                {
                    return dynamic<dynamic>();
                }
            }
            """,
            testHost,
            Keyword("partial"),
            Keyword("class"),
            Class("partial"),
            Punctuation.OpenAngle,
            TypeParameter("where"),
            Punctuation.CloseAngle,
            Keyword("where"),
            TypeParameter("where"),
            Punctuation.Colon,
            Class("partial"),
            Punctuation.OpenAngle,
            TypeParameter("where"),
            Punctuation.CloseAngle,
            Punctuation.OpenCurly,
            Keyword("static"),
            Keyword("dynamic"),
            Method("dynamic"),
            Static("dynamic"),
            Punctuation.OpenAngle,
            TypeParameter("partial"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            ControlKeyword("return"),
            Method("dynamic"),
            Static("dynamic"),
            Punctuation.OpenAngle,
            Keyword("dynamic"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543123")]
    public Task VarInForeach(TestHost testHost)
        => TestInMethodAsync(@"foreach (var v in args) { }",
            testHost,
            ControlKeyword("foreach"),
            Punctuation.OpenParen,
            Keyword("var"),
            Local("v"),
            ControlKeyword("in"),
            Identifier("args"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task ValueInSetterAndAnonymousTypePropertyName(TestHost testHost)
        => TestAsync(
            """
            class C
            {
                int P
                {
                    set
                    {
                        var t = new { value = value };
                    }
                }
            }
            """,
            testHost,
            Keyword("class"),
            Class("C"),
            Punctuation.OpenCurly,
            Keyword("int"),
            Property("P"),
            Punctuation.OpenCurly,
            Keyword("set"),
            Punctuation.OpenCurly,
            Keyword("var"),
            Local("t"),
            Operators.Equals,
            Keyword("new"),
            Punctuation.OpenCurly,
            Property("value"),
            Operators.Equals,
            Keyword("value"),
            Punctuation.CloseCurly,
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestValueInEvent(TestHost testHost)
        => TestInClassAsync(
            """
            event int Bar
            {
                add
                {
                    this.value = value;
                }
 
                remove
                {
                    this.value = value;
                }
            }
            """,
            testHost,
            Keyword("event"),
            Keyword("int"),
            Event("Bar"),
            Punctuation.OpenCurly,
            Keyword("add"),
            Punctuation.OpenCurly,
            Keyword("this"),
            Operators.Dot,
            Identifier("value"),
            Operators.Equals,
            Keyword("value"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
 
            Keyword("remove"),
            Punctuation.OpenCurly,
            Keyword("this"),
            Operators.Dot,
            Identifier("value"),
            Operators.Equals,
            Keyword("value"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestValueInProperty(TestHost testHost)
        => TestInClassAsync(
            """
            int Goo
            {
                get
                {
                    this.value = value;
                }
 
                set
                {
                    this.value = value;
                }
            }
            """,
            testHost,
            Keyword("int"),
            Property("Goo"),
            Punctuation.OpenCurly,
            Keyword("get"),
            Punctuation.OpenCurly,
            Keyword("this"),
            Operators.Dot,
            Identifier("value"),
            Operators.Equals,
            Identifier("value"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
 
            Keyword("set"),
            Punctuation.OpenCurly,
            Keyword("this"),
            Operators.Dot,
            Identifier("value"),
            Operators.Equals,
            Keyword("value"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task ValueFieldInSetterAccessedThroughThis(TestHost testHost)
        => TestInClassAsync(
            """
            int P
            {
                set
                {
                    this.value = value;
                }
            }
            """,
            testHost,
            Keyword("int"),
            Property("P"),
            Punctuation.OpenCurly,
            Keyword("set"),
            Punctuation.OpenCurly,
            Keyword("this"),
            Operators.Dot,
            Identifier("value"),
            Operators.Equals,
            Keyword("value"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task NewOfInterface(TestHost testHost)
        => TestInMethodAsync(
@"object o = new System.IDisposable();",
            testHost,
            Keyword("object"),
            Local("o"),
            Operators.Equals,
            Keyword("new"),
            Namespace("System"),
            Operators.Dot,
            Interface("IDisposable"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.Semicolon);
 
    [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545611")]
    [CombinatorialData]
    public Task TestVarConstructor(TestHost testHost)
        => TestAsync(
            """
            class var
            {
                void Main()
                {
                    new var();
                }
            }
            """,
            testHost,
            Keyword("class"),
            Class("var"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("Main"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("new"),
            Class("var"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545609")]
    [CombinatorialData]
    public Task TestVarTypeParameter(TestHost testHost)
        => TestAsync(
            """
            class X
            {
                void Goo<var>()
                {
                    var x;
                }
            }
            """,
            testHost,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("Goo"),
            Punctuation.OpenAngle,
            TypeParameter("var"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("var"),
            Local("x"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545610")]
    [CombinatorialData]
    public Task TestVarAttribute1(TestHost testHost)
        => TestAsync(
            """
            using System;
 
            [var]
            class var : Attribute
            {
            }
            """,
            testHost,
            Keyword("using"),
            Namespace("System"),
            Punctuation.Semicolon,
            Punctuation.OpenBracket,
            Class("var"),
            Punctuation.CloseBracket,
            Keyword("class"),
            Class("var"),
            Punctuation.Colon,
            Class("Attribute"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545610")]
    [CombinatorialData]
    public Task TestVarAttribute2(TestHost testHost)
        => TestAsync(
            """
            using System;
 
            [var]
            class varAttribute : Attribute
            {
            }
            """,
            testHost,
            Keyword("using"),
            Namespace("System"),
            Punctuation.Semicolon,
            Punctuation.OpenBracket,
            Class("var"),
            Punctuation.CloseBracket,
            Keyword("class"),
            Class("varAttribute"),
            Punctuation.Colon,
            Class("Attribute"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546170")]
    [CombinatorialData]
    public Task TestStandaloneTypeName(TestHost testHost)
        => TestAsync(
            """
            using System;
 
            class C
            {
                static void Main()
                {
                    var tree = Console
                }
            }
            """,
            testHost,
            Keyword("using"),
            Namespace("System"),
            Punctuation.Semicolon,
            Keyword("class"),
            Class("C"),
            Punctuation.OpenCurly,
            Keyword("static"),
            Keyword("void"),
            Method("Main"),
            Static("Main"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("var"),
            Local("tree"),
            Operators.Equals,
            Class("Console"),
            Static("Console"),
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546403")]
    [CombinatorialData]
    public Task TestNamespaceClassAmbiguities(TestHost testHost)
        => TestAsync(
            """
            class C
            {
            }
 
            namespace C
            {
            }
            """,
            testHost,
            Keyword("class"),
            Class("C"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Keyword("namespace"),
            Namespace("C"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task NameAttributeValue(TestHost testHost)
        => TestAsync(
            """
            class Program<T>
            {
                /// <param name="x"/>
                void Goo(int x)
                {
                }
            }
            """,
            testHost,
            Keyword("class"),
            Class("Program"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenCurly,
            XmlDoc.Delimiter("///"),
            XmlDoc.Text(" "),
            XmlDoc.Delimiter("<"),
            XmlDoc.Name("param"),
            XmlDoc.AttributeName("name"),
            XmlDoc.Delimiter("="),
            XmlDoc.AttributeQuotes("""
                "
                """),
            Parameter("x"),
            XmlDoc.AttributeQuotes("""
                "
                """),
            XmlDoc.Delimiter("/>"),
            Keyword("void"),
            Method("Goo"),
            Punctuation.OpenParen,
            Keyword("int"),
            Parameter("x"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task Cref1(TestHost testHost)
        => TestAsync(
            """
            /// <see cref="Program{T}"/>
            class Program<T>
            {
                void Goo()
                {
                }
            }
            """,
            testHost,
            XmlDoc.Delimiter("///"),
            XmlDoc.Text(" "),
            XmlDoc.Delimiter("<"),
            XmlDoc.Name("see"),
            XmlDoc.AttributeName("cref"),
            XmlDoc.Delimiter("="),
            XmlDoc.AttributeQuotes("""
                "
                """),
            Class("Program"),
            Punctuation.OpenCurly,
            TypeParameter("T"),
            Punctuation.CloseCurly,
            XmlDoc.AttributeQuotes("""
                "
                """),
            XmlDoc.Delimiter("/>"),
            Keyword("class"),
            Class("Program"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("Goo"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task CrefNamespaceIsNotClass(TestHost testHost)
        => TestAsync(
            """
            ///  <see cref="N"/>
            namespace N
            {
                class Program
                {
                }
            }
            """,
            testHost,
            XmlDoc.Delimiter("///"),
            XmlDoc.Text("  "),
            XmlDoc.Delimiter("<"),
            XmlDoc.Name("see"),
            XmlDoc.AttributeName("cref"),
            XmlDoc.Delimiter("="),
            XmlDoc.AttributeQuotes("""
                "
                """),
            Namespace("N"),
            XmlDoc.AttributeQuotes("""
                "
                """),
            XmlDoc.Delimiter("/>"),
            Keyword("namespace"),
            Namespace("N"),
            Punctuation.OpenCurly,
            Keyword("class"),
            Class("Program"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task InterfacePropertyWithSameNameShouldBePreferredToType(TestHost testHost)
        => TestAsync(
            """
            interface IGoo
            {
                int IGoo { get; set; }
 
                void Bar(int x = IGoo);
            }
            """,
            testHost,
            Keyword("interface"),
            Interface("IGoo"),
            Punctuation.OpenCurly,
            Keyword("int"),
            Property("IGoo"),
            Punctuation.OpenCurly,
            Keyword("get"),
            Punctuation.Semicolon,
            Keyword("set"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Keyword("void"),
            Method("Bar"),
            Punctuation.OpenParen,
            Keyword("int"),
            Parameter("x"),
            Operators.Equals,
            Property("IGoo"),
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem("https://github.com/dotnet/roslyn/issues/633")]
    public Task XmlDocCref(TestHost testHost)
        => TestAsync(
            """
            /// <summary>
            /// <see cref="MyClass.MyClass(int)"/>
            /// </summary>
            class MyClass
            {
                public MyClass(int x)
                {
                }
            }
            """,
            testHost,
            XmlDoc.Delimiter("///"),
            XmlDoc.Text(" "),
            XmlDoc.Delimiter("<"),
            XmlDoc.Name("summary"),
            XmlDoc.Delimiter(">"),
            XmlDoc.Delimiter("///"),
            XmlDoc.Text(" "),
            XmlDoc.Delimiter("<"),
            XmlDoc.Name("see"),
            XmlDoc.AttributeName("cref"),
            XmlDoc.Delimiter("="),
            XmlDoc.AttributeQuotes("""
                "
                """),
            Class("MyClass"),
            Operators.Dot,
            Class("MyClass"),
            Punctuation.OpenParen,
            Keyword("int"),
            Punctuation.CloseParen,
            XmlDoc.AttributeQuotes("""
                "
                """),
            XmlDoc.Delimiter("/>"),
            XmlDoc.Delimiter("///"),
            XmlDoc.Text(" "),
            XmlDoc.Delimiter("</"),
            XmlDoc.Name("summary"),
            XmlDoc.Delimiter(">"),
            Keyword("class"),
            Class("MyClass"),
            Punctuation.OpenCurly,
            Keyword("public"),
            Class("MyClass"),
            Punctuation.OpenParen,
            Keyword("int"),
            Parameter("x"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestGenericTypeWithNoArity(TestHost testHost)
        => TestAsync(
            """
            using System.Collections.Generic;
 
            class Program : IReadOnlyCollection
            {
            }
            """,
            testHost,
            Keyword("using"),
            Namespace("System"),
            Operators.Dot,
            Namespace("Collections"),
            Operators.Dot,
            Namespace("Generic"),
            Punctuation.Semicolon,
            Keyword("class"),
            Class("Program"),
            Punctuation.Colon,
            Interface("IReadOnlyCollection"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestGenericTypeWithWrongArity(TestHost testHost)
        => TestAsync(
            """
            using System.Collections.Generic;
 
            class Program : IReadOnlyCollection<int,string>
            {
            }
            """,
            testHost,
            Keyword("using"),
            Namespace("System"),
            Operators.Dot,
            Namespace("Collections"),
            Operators.Dot,
            Namespace("Generic"),
            Punctuation.Semicolon,
            Keyword("class"),
            Class("Program"),
            Punctuation.Colon,
            Interface("IReadOnlyCollection"),
            Punctuation.OpenAngle,
            Keyword("int"),
            Punctuation.Comma,
            Keyword("string"),
            Punctuation.CloseAngle,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestExtensionMethodDeclaration(TestHost testHost)
        => TestAsync(
            """
            static class ExtMethod
            {
                public static void TestMethod(this C c)
                {
                }
            }
            """,
            testHost,
            Keyword("static"),
            Keyword("class"),
            Class("ExtMethod"),
            Static("ExtMethod"),
            Punctuation.OpenCurly,
            Keyword("public"),
            Keyword("static"),
            Keyword("void"),
            ExtensionMethod("TestMethod"),
            Static("TestMethod"),
            Punctuation.OpenParen,
            Keyword("this"),
            Identifier("C"),
            Parameter("c"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestExtensionMethodUsage(TestHost testHost)
        => TestAsync(
            """
            static class ExtMethod
            {
                public static void TestMethod(this C c)
                {
                }
            }
 
            class C
            {
                void Test()
                {
                    ExtMethod.TestMethod(new C());
                    new C().TestMethod();
                }
            }
            """,
            testHost,
            ParseOptions(Options.Regular),
            Keyword("static"),
            Keyword("class"),
            Class("ExtMethod"),
            Static("ExtMethod"),
            Punctuation.OpenCurly,
            Keyword("public"),
            Keyword("static"),
            Keyword("void"),
            ExtensionMethod("TestMethod"),
            Static("TestMethod"),
            Punctuation.OpenParen,
            Keyword("this"),
            Class("C"),
            Parameter("c"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("C"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("Test"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Class("ExtMethod"),
            Static("ExtMethod"),
            Operators.Dot,
            Method("TestMethod"),
            Static("TestMethod"),
            Punctuation.OpenParen,
            Keyword("new"),
            Class("C"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Keyword("new"),
            Class("C"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Operators.Dot,
            ExtensionMethod("TestMethod"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestConstLocals(TestHost testHost)
        => TestInMethodAsync(
            """
            const int Number = 42;
            var x = Number;
            """,
            testHost,
            Keyword("const"),
            Keyword("int"),
            Constant("Number"),
            Static("Number"),
            Operators.Equals,
            Number("42"),
            Punctuation.Semicolon,
            Keyword("var"),
            Local("x"),
            Operators.Equals,
            Constant("Number"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_InsideMethod(TestHost testHost)
        => TestInMethodAsync("""
            var unmanaged = 0;
            unmanaged++;
            """,
            testHost,
            Keyword("var"),
            Local("unmanaged"),
            Operators.Equals,
            Number("0"),
            Punctuation.Semicolon,
            Local("unmanaged"),
            Operators.PlusPlus,
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_Type_Keyword(TestHost testHost)
        => TestAsync(
            "class X<T> where T : unmanaged { }",
            testHost,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_Type_ExistingInterface(TestHost testHost)
        => TestAsync("""
            interface unmanaged {}
            class X<T> where T : unmanaged { }
            """,
            testHost,
            Keyword("interface"),
            Interface("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_Type_ExistingInterfaceButOutOfScope(TestHost testHost)
        => TestAsync("""
            namespace OtherScope
            {
                interface unmanaged {}
            }
            class X<T> where T : unmanaged { }
            """,
            testHost,
            Keyword("namespace"),
            Namespace("OtherScope"),
            Punctuation.OpenCurly,
            Keyword("interface"),
            Interface("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_Method_Keyword(TestHost testHost)
        => TestAsync("""
            class X
            {
                void M<T>() where T : unmanaged { }
            }
            """,
            testHost,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_Method_ExistingInterface(TestHost testHost)
        => TestAsync("""
            interface unmanaged {}
            class X
            {
                void M<T>() where T : unmanaged { }
            }
            """,
            testHost,
            Keyword("interface"),
            Interface("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_Method_ExistingInterfaceButOutOfScope(TestHost testHost)
        => TestAsync("""
            namespace OtherScope
            {
                interface unmanaged {}
            }
            class X
            {
                void M<T>() where T : unmanaged { }
            }
            """,
            testHost,
            Keyword("namespace"),
            Namespace("OtherScope"),
            Punctuation.OpenCurly,
            Keyword("interface"),
            Interface("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_Delegate_Keyword(TestHost testHost)
        => TestAsync(
            "delegate void D<T>() where T : unmanaged;",
            testHost,
            Keyword("delegate"),
            Keyword("void"),
            Delegate("D"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_Delegate_ExistingInterface(TestHost testHost)
        => TestAsync("""
            interface unmanaged {}
            delegate void D<T>() where T : unmanaged;
            """,
            testHost,
            Keyword("interface"),
            Interface("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Keyword("delegate"),
            Keyword("void"),
            Delegate("D"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_Delegate_ExistingInterfaceButOutOfScope(TestHost testHost)
        => TestAsync("""
            namespace OtherScope
            {
                interface unmanaged {}
            }
            delegate void D<T>() where T : unmanaged;
            """,
            testHost,
            Keyword("namespace"),
            Namespace("OtherScope"),
            Punctuation.OpenCurly,
            Keyword("interface"),
            Interface("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Keyword("delegate"),
            Keyword("void"),
            Delegate("D"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_LocalFunction_Keyword(TestHost testHost)
        => TestAsync("""
            class X
            {
                void N()
                {
                    void M<T>() where T : unmanaged { }
                }
            }
            """,
            testHost,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("N"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_LocalFunction_ExistingInterface(TestHost testHost)
        => TestAsync("""
            interface unmanaged {}
            class X
            {
                void N()
                {
                    void M<T>() where T : unmanaged { }
                }
            }
            """,
            testHost,
            Keyword("interface"),
            Interface("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("N"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestUnmanagedConstraint_LocalFunction_ExistingInterfaceButOutOfScope(TestHost testHost)
        => TestAsync("""
            namespace OtherScope
            {
                interface unmanaged {}
            }
            class X
            {
                void N()
                {
                    void M<T>() where T : unmanaged { }
                }
            }
            """,
            testHost,
            Keyword("namespace"),
            Namespace("OtherScope"),
            Punctuation.OpenCurly,
            Keyword("interface"),
            Interface("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("N"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("unmanaged"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/29492")]
    [CombinatorialData]
    public Task TestOperatorOverloading(TestHost testHost)
        => TestAsync("""
            class C
            {
                void M()
                {
                    var a = 1 + 1;
                    var b = new True() + new True();
                }
            }
            class True
            {
                public static True operator +(True a, True b)
                {
                     return new True();
                }
            }
            """,
testHost,
Keyword("class"),
Class("C"),
Punctuation.OpenCurly,
Keyword("void"),
Method("M"),
Punctuation.OpenParen,
Punctuation.CloseParen,
Punctuation.OpenCurly,
Keyword("var"),
Local("a"),
Operators.Equals,
Number("1"),
Operators.Plus,
Number("1"),
Punctuation.Semicolon,
Keyword("var"),
Local("b"),
Operators.Equals,
Keyword("new"),
Class("True"),
Punctuation.OpenParen,
Punctuation.CloseParen,
OverloadedOperators.Plus,
Keyword("new"),
Class("True"),
Punctuation.OpenParen,
Punctuation.CloseParen,
Punctuation.Semicolon,
Punctuation.CloseCurly,
Punctuation.CloseCurly,
Keyword("class"),
Class("True"),
Punctuation.OpenCurly,
Keyword("public"),
Keyword("static"),
Class("True"),
Keyword("operator"),
Operators.Plus,
Punctuation.OpenParen,
Class("True"),
Parameter("a"),
Punctuation.Comma,
Class("True"),
Parameter("b"),
Punctuation.CloseParen,
Punctuation.OpenCurly,
ControlKeyword("return"),
Keyword("new"),
Class("True"),
Punctuation.OpenParen,
Punctuation.CloseParen,
Punctuation.Semicolon,
Punctuation.CloseCurly,
Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_InsideMethod(TestHost testHost)
        => TestInMethodAsync("""
            var notnull = 0;
            notnull++;
            """,
            testHost,
            Keyword("var"),
            Local("notnull"),
            Operators.Equals,
            Number("0"),
            Punctuation.Semicolon,
            Local("notnull"),
            Operators.PlusPlus,
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_Type_Keyword(TestHost testHost)
        => TestAsync(
            "class X<T> where T : notnull { }",
            testHost,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_Type_ExistingInterface(TestHost testHost)
        => TestAsync("""
            interface notnull {}
            class X<T> where T : notnull { }
            """,
            testHost,
            Keyword("interface"),
            Interface("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_Type_ExistingInterfaceButOutOfScope(TestHost testHost)
        => TestAsync("""
            namespace OtherScope
            {
                interface notnull {}
            }
            class X<T> where T : notnull { }
            """,
            testHost,
            Keyword("namespace"),
            Namespace("OtherScope"),
            Punctuation.OpenCurly,
            Keyword("interface"),
            Interface("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_Method_Keyword(TestHost testHost)
        => TestAsync("""
            class X
            {
                void M<T>() where T : notnull { }
            }
            """,
            testHost,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_Method_ExistingInterface(TestHost testHost)
        => TestAsync("""
            interface notnull {}
            class X
            {
                void M<T>() where T : notnull { }
            }
            """,
            testHost,
            Keyword("interface"),
            Interface("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_Method_ExistingInterfaceButOutOfScope(TestHost testHost)
        => TestAsync("""
            namespace OtherScope
            {
                interface notnull {}
            }
            class X
            {
                void M<T>() where T : notnull { }
            }
            """,
            testHost,
            Keyword("namespace"),
            Namespace("OtherScope"),
            Punctuation.OpenCurly,
            Keyword("interface"),
            Interface("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_Delegate_Keyword(TestHost testHost)
        => TestAsync(
            "delegate void D<T>() where T : notnull;",
            testHost,
            Keyword("delegate"),
            Keyword("void"),
            Delegate("D"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_Delegate_ExistingInterface(TestHost testHost)
        => TestAsync("""
            interface notnull {}
            delegate void D<T>() where T : notnull;
            """,
            testHost,
            Keyword("interface"),
            Interface("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Keyword("delegate"),
            Keyword("void"),
            Delegate("D"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_Delegate_ExistingInterfaceButOutOfScope(TestHost testHost)
        => TestAsync("""
            namespace OtherScope
            {
                interface notnull {}
            }
            delegate void D<T>() where T : notnull;
            """,
            testHost,
            Keyword("namespace"),
            Namespace("OtherScope"),
            Punctuation.OpenCurly,
            Keyword("interface"),
            Interface("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Keyword("delegate"),
            Keyword("void"),
            Delegate("D"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_LocalFunction_Keyword(TestHost testHost)
        => TestAsync("""
            class X
            {
                void N()
                {
                    void M<T>() where T : notnull { }
                }
            }
            """,
            testHost,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("N"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_LocalFunction_ExistingInterface(TestHost testHost)
        => TestAsync("""
            interface notnull {}
            class X
            {
                void N()
                {
                    void M<T>() where T : notnull { }
                }
            }
            """,
            testHost,
            Keyword("interface"),
            Interface("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("N"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestNotNullConstraint_LocalFunction_ExistingInterfaceButOutOfScope(TestHost testHost)
        => TestAsync("""
            namespace OtherScope
            {
                interface notnull {}
            }
            class X
            {
                void N()
                {
                    void M<T>() where T : notnull { }
                }
            }
            """,
            testHost,
            Keyword("namespace"),
            Namespace("OtherScope"),
            Punctuation.OpenCurly,
            Keyword("interface"),
            Interface("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("X"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("N"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenAngle,
            TypeParameter("T"),
            Punctuation.CloseAngle,
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Keyword("where"),
            TypeParameter("T"),
            Punctuation.Colon,
            Keyword("notnull"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/10174")]
    [CombinatorialData]
    public Task VarInPropertyPattern(TestHost testHost)
        => TestAsync(
            """
            using System;
 
            class Person { public string Name; }
 
            class Program
            {
                void Goo(object o)
                {
                    if (o is Person { Name: var n })
                    {
                        Console.WriteLine(n);
                    }
                }
            }
            """,
            testHost,
            Keyword("using"),
            Namespace("System"),
            Punctuation.Semicolon,
            Keyword("class"),
            Class("Person"),
            Punctuation.OpenCurly,
            Keyword("public"),
            Keyword("string"),
            Field("Name"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Keyword("class"),
            Class("Program"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("Goo"),
            Punctuation.OpenParen,
            Keyword("object"),
            Parameter("o"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            ControlKeyword("if"),
            Punctuation.OpenParen,
            Parameter("o"),
            Keyword("is"),
            Class("Person"),
            Punctuation.OpenCurly,
            Field("Name"),
            Punctuation.Colon,
            Keyword("var"),
            Local("n"),
            Punctuation.CloseCurly,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Class("Console"),
            Static("Console"),
            Operators.Dot,
            Method("WriteLine"),
            Static("WriteLine"),
            Punctuation.OpenParen,
            Local("n"),
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
    [CombinatorialData]
    public Task NotPattern(TestHost testHost)
        => TestAsync(
            """
            class Person
            {
                void Goo(object o)
                {
                    if (o is not Person p)
                    {
                    }
                }
            }
            """,
            testHost,
            Keyword("class"),
            Class("Person"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("Goo"),
            Punctuation.OpenParen,
            Keyword("object"),
            Parameter("o"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            ControlKeyword("if"),
            Punctuation.OpenParen,
            Parameter("o"),
            Keyword("is"),
            Keyword("not"),
            Class("Person"),
            Local("p"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
    [CombinatorialData]
    public Task OrPattern(TestHost testHost)
        => TestAsync(
            """
            class Person
            {
                void Goo(object o)
                {
                    if (o is Person or int)
                    {
                    }
                }
            }
            """,
            testHost,
            Keyword("class"),
            Class("Person"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("Goo"),
            Punctuation.OpenParen,
            Keyword("object"),
            Parameter("o"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            ControlKeyword("if"),
            Punctuation.OpenParen,
            Parameter("o"),
            Keyword("is"),
            Class("Person"),
            Keyword("or"),
            Keyword("int"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/59484")]
    [CombinatorialData]
    public Task TestPatternVariables(TestHost testHost)
        => TestAsync(
            """
            void M(object o) {
                _ = o is [var (x, y), {} z] list;
            }
            """,
            testHost,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenParen,
            Keyword("object"),
            Parameter("o"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("_"),
            Operators.Equals,
            Parameter("o"),
            Keyword("is"),
            Punctuation.OpenBracket,
            Keyword("var"),
            Punctuation.OpenParen,
            Local("x"),
            Punctuation.Comma,
            Local("y"),
            Punctuation.CloseParen,
            Punctuation.Comma,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Local("z"),
            Punctuation.CloseBracket,
            Local("list"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly);
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
    [CombinatorialData]
    public Task RelationalPattern(TestHost testHost)
        => TestAsync(
            """
            class Person
            {
                void Goo(object o)
                {
                    if (o is >= 0)
                    {
                    }
                }
            }
            """,
            testHost,
            Keyword("class"),
            Class("Person"),
            Punctuation.OpenCurly,
            Keyword("void"),
            Method("Goo"),
            Punctuation.OpenParen,
            Keyword("object"),
            Parameter("o"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            ControlKeyword("if"),
            Punctuation.OpenParen,
            Parameter("o"),
            Keyword("is"),
            Operators.GreaterThanEquals,
            NumericLiteral("0"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task BasicFileScopedNamespaceClassification(TestHost testHost)
        => TestAsync(
            """
            namespace NS;
 
            class C { }
            """,
            testHost,
            Keyword("namespace"),
            Namespace("NS"),
            Punctuation.Semicolon,
            Keyword("class"),
            Class("C"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestStringEscape(TestHost testHost)
        => TestInMethodAsync(@"var goo = $@""{{{12:X}}}"";",
            testHost,
            Keyword("var"),
            Local("goo"),
            Operators.Equals,
            Verbatim("""
                $@"
                """),
            Escape("{{"),
            Punctuation.OpenCurly,
            Number("12"),
            Punctuation.Colon,
            String("X"),
            Punctuation.CloseCurly,
            Escape("}}"),
            Verbatim("""
                "
                """),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    [WorkItem("https://github.com/dotnet/roslyn/issues/55313")]
    public Task TestStaticConstructorClass(TestHost testHost)
        => TestAsync(
            """
            class C
            {
                static C() { }
            }
            """,
            testHost,
            Keyword("class"),
            Class("C"),
            Punctuation.OpenCurly,
            Keyword("static"),
            Class("C"),
            Static("C"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem("https://github.com/dotnet/roslyn/issues/55313")]
    public Task TestStaticConstructorInterface(TestHost testHost)
        => TestAsync(
            """
            interface C
            {
                static C() { }
            }
            """,
            testHost,
            Keyword("interface"),
            Interface("C"),
            Punctuation.OpenCurly,
            Keyword("static"),
            Interface("C"),
            Static("C"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem("https://github.com/dotnet/roslyn/issues/59569")]
    public Task TestArgsInTopLevel(TestHost testHost)
        => TestAsync(
            """
            [|foreach (var arg in args)
            {
            }|]
            """,
            testHost,
            parseOptions: null,
            ControlKeyword("foreach"),
            Punctuation.OpenParen,
            Keyword("var"),
            Local("arg"),
            ControlKeyword("in"),
            Keyword("args"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem("https://github.com/dotnet/roslyn/issues/59569")]
    public Task TestArgsInNormalProgram(TestHost testHost)
        => TestAsync(
            """
            class Program
            {
                static void Main(string[] args)
                {
                    [|foreach (var arg in args)
                    {
                    }|]
                }
            }
            """,
            testHost,
            parseOptions: null,
            ControlKeyword("foreach"),
            Punctuation.OpenParen,
            Keyword("var"),
            Local("arg"),
            ControlKeyword("in"),
            Parameter("args"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncInIncompleteMember(TestHost testHost)
        => TestAsync(
            """
            class Test
            {
                public async
            }
            """,
            testHost,
            parseOptions: null,
            Keyword("class"),
            Class("Test"),
            Punctuation.OpenCurly,
            Keyword("public"),
            Keyword("async"),
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncInIncompleteMemberWhenAsyncTypeIsDefined(TestHost testHost)
        => TestAsync(
            """
            [|class Test
            {
                public async
            }|]
 
            class async
            {
            }
            """,
            testHost,
            parseOptions: null,
            Keyword("class"),
            Class("Test"),
            Punctuation.OpenCurly,
            Keyword("public"),
            Class("async"),
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncInPotentialLocalFunctionDeclaration(TestHost testHost)
        => TestAsync(
            """
            void M()
            {
                async
            }
            """,
            testHost,
            parseOptions: null,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("async"),
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncInPotentialLocalFunctionDeclarationWhenAsyncTypeIsDefined(TestHost testHost)
        => TestAsync(
            """
            [|void M()
            {
                async
            }|]
 
            class async
            {
            }
            """,
            testHost,
            parseOptions: null,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Class("async"),
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncAsLocalMemberType_NoAsyncInScope(TestHost testHost)
        => TestAsync(
            """
            class Test
            {
                void M()
                {
                    [|async a;|]
                }
            }
            """,
            testHost,
            parseOptions: null,
            Keyword("async"),
            Local("a"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncAsLocalMemberType_AsyncInScope(TestHost testHost)
        => TestAsync(
            """
            class async { }
 
            class Test
            {
                void M()
                {
                    [|async a;|]
                }
            }
            """,
            testHost,
            parseOptions: null,
            Class("async"),
            Local("a"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncAsPropertyType_NoAsyncInScope(TestHost testHost)
        => TestAsync(
            """
            class Test
            {
                [|public async Prop { get; set; }|]
            }
            """,
            testHost,
            parseOptions: null,
            Keyword("public"),
            Keyword("async"),
            Property("Prop"),
            Punctuation.OpenCurly,
            Keyword("get"),
            Punctuation.Semicolon,
            Keyword("set"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncAsPropertyType_AsyncInScope(TestHost testHost)
        => TestAsync(
            """
            class async { }
 
            class Test
            {
                [|public async Prop { get; set; }|]
            }
            """,
            testHost,
            parseOptions: null,
            Keyword("public"),
            Class("async"),
            Property("Prop"),
            Punctuation.OpenCurly,
            Keyword("get"),
            Punctuation.Semicolon,
            Keyword("set"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncAsMethodReturnType_NoAsyncInScope(TestHost testHost)
        => TestAsync(
            """
            class Test
            {
                [|public async M()|] {}
            }
            """,
            testHost,
            parseOptions: null,
            Keyword("public"),
            Keyword("async"),
            Method("M"),
            Punctuation.OpenParen,
            Punctuation.CloseParen);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncAsMethodReturnType_AsyncInScope(TestHost testHost)
        => TestAsync(
            """
            class async { }
 
            class Test
            {
                [|public async M()|] {}
            }
            """,
            testHost,
            parseOptions: null,
            Keyword("public"),
            Class("async"),
            Method("M"),
            Punctuation.OpenParen,
            Punctuation.CloseParen);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncAsAccessingName(TestHost testHost)
        => TestAsync(
            """
            class Test
            {
                void M()
                {
                    var a = [|C.async;|]
                }
            }
 
            class C
            {
                public static int async;
            }
            """,
            testHost,
            parseOptions: null,
            Class("C"),
            Operators.Dot,
            Field("async"),
            Static("async"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    [WorkItem(60399, "https://github.com/dotnet/roslyn/issues/60339")]
    public Task TestAsyncInIncompleteDelegateOrLambda(TestHost testHost)
        => TestAsync(
            """
            using System;
            class Test
            {
                void M()
                {
                    [|Action a = async |]
                }
            }
            """,
            testHost,
            parseOptions: null,
            Delegate("Action"),
            Local("a"),
            Operators.Equals,
            Keyword("async"));
 
    [Theory, CombinatorialData]
    public Task TestPartialInIncompleteMember1(TestHost testHost)
        => TestAsync("""
            class C
            {
                [|partial|]
            }
            """,
            testHost,
            Keyword("partial"));
 
    [Theory, CombinatorialData]
    public Task TestPartialInIncompleteMember2(TestHost testHost)
        => TestAsync("""
            class C
            {
                [|public partial|]
            }
            """,
            testHost,
            Keyword("public"),
            Keyword("partial"));
 
    [Theory, CombinatorialData]
    public Task TestPartialInIncompleteMember1_PartialTypeIsDefined(TestHost testHost)
        => TestAsync("""
            class partial
            {
            }
 
            class C
            {
                [|partial|]
            }
            """,
            testHost,
            Class("partial"));
 
    [Theory, CombinatorialData]
    public Task TestPartialInIncompleteMember2_PartialTypeIsDefined(TestHost testHost)
        => TestAsync("""
            class partial
            {
            }
 
            class C
            {
                [|public partial|]
            }
            """,
            testHost,
            Keyword("public"),
            Class("partial"));
 
    [Theory, CombinatorialData]
    public Task TestTopLevelPartial1(TestHost testHost)
        => TestAsync("""
            partial
            """,
            testHost,
            Keyword("partial"));
 
    [Theory, CombinatorialData]
    public Task TestTopLevelPartial2(TestHost testHost)
        => TestAsync("""
            public partial
            """,
            testHost,
            Keyword("public"),
            Keyword("partial"));
 
    [Theory, CombinatorialData]
    public Task TestTopLevelPartial1_PartialTypeIsDefined(TestHost testHost)
        => TestAsync("""
            class partial
            {
            }
 
            [|partial|]
            """,
            testHost,
            Class("partial"));
 
    [Theory, CombinatorialData]
    public Task TestTopLevelPartial2_PartialTypeIsDefined(TestHost testHost)
        => TestAsync("""
            class partial
            {
            }
 
            [|public partial|]
            """,
            testHost,
            Keyword("public"),
            Class("partial"));
 
    /// <seealso cref="SemanticClassifierTests.LocalFunctionUse"/>
    /// <seealso cref="SyntacticClassifierTests.LocalFunctionDeclaration"/>
    [Theory, CombinatorialData]
    public Task LocalFunctionDeclarationAndUse(TestHost testHost)
        => TestAsync(
            """
            using System;
 
            class C
            {
                void M(Action action)
                {
                    [|localFunction();
                    staticLocalFunction();
 
                    M(localFunction);
                    M(staticLocalFunction);
 
                    void localFunction() { }
                    static void staticLocalFunction() { }|]
                }
            }
 
            """,
            testHost,
            Method("localFunction"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Method("staticLocalFunction"),
            Static("staticLocalFunction"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Method("M"),
            Punctuation.OpenParen,
            Method("localFunction"),
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Method("M"),
            Punctuation.OpenParen,
            Method("staticLocalFunction"),
            Static("staticLocalFunction"),
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Keyword("void"),
            Method("localFunction"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly,
            Keyword("static"),
            Keyword("void"),
            Method("staticLocalFunction"),
            Static("staticLocalFunction"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task TestScopedVar(TestHost testHost)
        => TestAsync("""
            static void method(scoped in S s)
            {
                scoped var rs1 = s;
            }
 
            file readonly ref struct S { }
            """, testHost,
            Keyword("static"),
            Keyword("void"),
            Method("method"),
            Static("method"),
            Punctuation.OpenParen,
            Keyword("scoped"),
            Keyword("in"),
            Struct("S"),
            Parameter("s"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("scoped"),
            Keyword("var"),
            Local("rs1"),
            Operators.Equals,
            Parameter("s"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Keyword("file"),
            Keyword("readonly"),
            Keyword("ref"),
            Keyword("struct"),
            Struct("S"),
            Punctuation.OpenCurly,
            Punctuation.CloseCurly);
 
    [Theory, CombinatorialData]
    public Task Lambda_DefaultParameterValue(TestHost testHost)
        => TestAsync(
            """
            class C
            {
                const int N = 10;
 
                void M()
                {
                    var lam = [|(int x = N) => x|];
                }
            }
 
            """,
            testHost,
            Punctuation.OpenParen,
            Keyword("int"),
            Parameter("x"),
            Operators.Equals,
            Constant("N"),
            Static("N"),
            Punctuation.CloseParen,
            Operators.EqualsGreaterThan,
            Parameter("x"));
 
    [Theory, CombinatorialData]
    public Task UsingAliasToType1(TestHost testHost)
        => TestAsync(
            """
            using X = int;
            """,
            testHost,
            Keyword("using"),
            Struct("X"),
            Operators.Equals,
            Keyword("int"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task UsingAliasToType2(TestHost testHost)
        => TestAsync(
            """
            using X = int[];
            """,
            testHost,
            Keyword("using"),
            Identifier("X"),
            Operators.Equals,
            Keyword("int"),
            Punctuation.OpenBracket,
            Punctuation.CloseBracket,
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task UsingAliasToType3(TestHost testHost)
        => TestAsync(
            """
            using unsafe X = int*;
            """,
            testHost,
            Keyword("using"),
            Keyword("unsafe"),
            Identifier("X"),
            Operators.Equals,
            Keyword("int"),
            Operators.Asterisk,
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task UsingAliasToType4(TestHost testHost)
        => TestAsync(
            """
            using unsafe X = delegate*<int,int>;
            """,
            testHost,
            Keyword("using"),
            Keyword("unsafe"),
            Identifier("X"),
            Operators.Equals,
            Keyword("delegate"),
            Operators.Asterisk,
            Punctuation.OpenAngle,
            Keyword("int"),
            Punctuation.Comma,
            Keyword("int"),
            Punctuation.CloseAngle,
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    public Task UsingAliasToType5(TestHost testHost)
        => TestAsync(
            """
            using X = (int x, string b);
            """,
            testHost,
            Keyword("using"),
            Struct("X"),
            Operators.Equals,
            Punctuation.OpenParen,
            Keyword("int"),
            Identifier("x"),
            Punctuation.Comma,
            Keyword("string"),
            Identifier("b"),
            Punctuation.CloseParen,
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    [WorkItem("https://github.com/dotnet/roslyn/issues/70107")]
    public Task TestFunctionPointer1(TestHost testHost)
        => TestAsync(
            """
            delegate* unmanaged[Fastcall, Stdcall, Thiscall]<int> fp;
            """,
            testHost,
            parseOptions: null,
            Keyword("delegate"),
            Operators.Asterisk,
            Keyword("unmanaged"),
            Punctuation.OpenBracket,
            Class("Fastcall"),
            Punctuation.Comma,
            Class("Stdcall"),
            Punctuation.Comma,
            Class("Thiscall"),
            Punctuation.CloseBracket,
            Punctuation.OpenAngle,
            Keyword("int"),
            Punctuation.CloseAngle,
            Local("fp"),
            Punctuation.Semicolon);
 
    [Theory, CombinatorialData]
    [WorkItem("https://github.com/dotnet/roslyn/issues/70107")]
    public Task TestFunctionPointer2(TestHost testHost)
        => TestAsync(
            """
            delegate* unmanaged[Member]<int> fp;
            """,
            testHost,
            parseOptions: null,
            Keyword("delegate"),
            Operators.Asterisk,
            Keyword("unmanaged"),
            Punctuation.OpenBracket,
            Identifier("Member"),
            Punctuation.CloseBracket,
            Punctuation.OpenAngle,
            Keyword("int"),
            Punctuation.CloseAngle,
            Local("fp"),
            Punctuation.Semicolon);
 
    [WpfFact]
    public async Task TestTotalClassifier()
    {
        using var workspace = EditorTestWorkspace.CreateCSharp(""""
            using System.Text.RegularExpressions;
 
            class C
            {
                // class D { }
                void M()
                {
                    new Regex("(a)");
                    var s1 = "s1";
                    var s2 = $"s2";
                    var s3 = @"s3";
                    var s4 = """
                    s4
                    """;
                }
            }
            """");
        var document = workspace.Documents.First();
 
        var listenerProvider = workspace.ExportProvider.GetExportedValue<IAsynchronousOperationListenerProvider>();
        var globalOptions = workspace.ExportProvider.GetExportedValue<IGlobalOptionService>();
 
        var provider = new TotalClassificationTaggerProvider(
            workspace.GetService<TaggerHost>(),
            workspace.GetService<ClassificationTypeMap>());
 
        var buffer = document.GetTextBuffer();
        using var tagger = provider.CreateTagger(document.GetTextView(), buffer);
 
        var waiter = listenerProvider.GetWaiter(FeatureAttribute.Classification);
        await waiter.ExpeditedWaitAsync();
 
        var allCode = buffer.CurrentSnapshot.GetText();
        var tags = tagger!.GetTags(new NormalizedSnapshotSpanCollection(buffer.CurrentSnapshot.GetFullSpan()));
 
        var actualOrdered = tags.OrderBy((t1, t2) => t1.Span.Span.Start - t2.Span.Span.Start);
 
        var actualFormatted = actualOrdered.Select(a => new FormattedClassification(allCode.Substring(a.Span.Span.Start, a.Span.Span.Length), a.Tag.ClassificationType.Classification));
 
        AssertEx.Equal(
        [
            Keyword("using"),
            Namespace("System"),
            Operators.Dot,
            Namespace("Text"),
            Operators.Dot,
            Namespace("RegularExpressions"),
            Punctuation.Semicolon,
            Keyword("class"),
            Class("C"),
            Punctuation.OpenCurly,
            Comment("// class D { }"),
            Keyword("void"),
            Method("M"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("new"),
            Class("Regex"),
            Punctuation.OpenParen,
            String("""
                "
                """),
            Regex.Grouping("("),
            Regex.Text("a"),
            Regex.Grouping(")"),
            String("""
                "
                """),
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Keyword("var"),
            Local("s1"),
            Operators.Equals,
            String("""
                "s1"
                """),
            Punctuation.Semicolon,
            Keyword("var"),
            Local("s2"),
            Operators.Equals,
            String("""
                $"
                """),
            String("s2"),
            String("""
                "
                """),
            Punctuation.Semicolon,
            Keyword("var"),
            Local("s3"),
            Operators.Equals,
            Verbatim("""
                @"s3"
                """),
            Punctuation.Semicolon,
            Keyword("var"),
            Local("s4"),
            Operators.Equals,
            String(""""
                """
                        s4
                        """
                """"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
        ], actualFormatted);
    }
 
    [WpfFact]
    public void TestCopyPasteClassifier()
    {
        using var workspace = EditorTestWorkspace.CreateCSharp(""""
            using System.Text.RegularExpressions;
 
            class C
            {
                // class D { }
                void M()
                {
                    new Regex("(a)");
                    var s1 = "s1";
                    var s2 = $"s2";
                    var s3 = @"s3";
                    var s4 = """
                    s4
                    """;
                }
            }
            """");
        var document = workspace.Documents.First();
 
        var listenerProvider = workspace.ExportProvider.GetExportedValue<IAsynchronousOperationListenerProvider>();
        var globalOptions = workspace.ExportProvider.GetExportedValue<IGlobalOptionService>();
 
        var provider = new CopyPasteAndPrintingClassificationBufferTaggerProvider(
            workspace.GetService<IThreadingContext>(),
            workspace.GetService<ClassificationTypeMap>(),
            listenerProvider,
            globalOptions);
 
        var buffer = document.GetTextBuffer();
        using var tagger = provider.CreateTagger<IClassificationTag>(buffer);
 
        var allCode = buffer.CurrentSnapshot.GetText();
        var tags = tagger!.GetAllTags(new NormalizedSnapshotSpanCollection(buffer.CurrentSnapshot.GetFullSpan()), CancellationToken.None);
 
        var actualOrdered = tags.OrderBy((t1, t2) => t1.Span.Span.Start - t2.Span.Span.Start);
 
        var actualFormatted = actualOrdered.Select(a => new FormattedClassification(allCode.Substring(a.Span.Span.Start, a.Span.Span.Length), a.Tag.ClassificationType.Classification));
 
        AssertEx.Equal(
        [
            Keyword("using"),
            Namespace("System"),
            Operators.Dot,
            Namespace("Text"),
            Operators.Dot,
            Namespace("RegularExpressions"),
            Punctuation.Semicolon,
            Keyword("class"),
            Class("C"),
            Punctuation.OpenCurly,
            Comment("// class D { }"),
            Keyword("void"),
            Method("M"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("new"),
            Class("Regex"),
            Punctuation.OpenParen,
            String("""
                "
                """),
            Regex.Grouping("("),
            Regex.Text("a"),
            Regex.Grouping(")"),
            String("""
                "
                """),
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Keyword("var"),
            Local("s1"),
            Operators.Equals,
            String("""
                "s1"
                """),
            Punctuation.Semicolon,
            Keyword("var"),
            Local("s2"),
            Operators.Equals,
            String("""
                $"
                """),
            String("s2"),
            String("""
                "
                """),
            Punctuation.Semicolon,
            Keyword("var"),
            Local("s3"),
            Operators.Equals,
            Verbatim("""
                @"s3"
                """),
            Punctuation.Semicolon,
            Keyword("var"),
            Local("s4"),
            Operators.Equals,
            String(""""
                """
                        s4
                        """
                """"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly,
        ], actualFormatted);
    }
 
    [Theory, CombinatorialData]
    public Task TestModernExtension1(TestHost testHost)
        => TestAsync(
            """
            static class C
            {
                extension(string s)
                {
                    public bool IsNullOrEmpty() => false;
                }
 
                void M(string s)
                {
                    var v = s.IsNullOrEmpty();
                }
            }
            """,
            testHost,
            CSharpParseOptions.Default.WithLanguageVersion(LanguageVersionExtensions.CSharpNext),
            Keyword("static"),
            Keyword("class"),
            Class("C"),
            Static("C"),
            Punctuation.OpenCurly,
            Keyword("extension"),
            Punctuation.OpenParen,
            Keyword("string"),
            Parameter("s"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("public"),
            Keyword("bool"),
            ExtensionMethod("IsNullOrEmpty"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Operators.EqualsGreaterThan,
            Keyword("false"),
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Keyword("void"),
            Method("M"),
            Punctuation.OpenParen,
            Keyword("string"),
            Parameter("s"),
            Punctuation.CloseParen,
            Punctuation.OpenCurly,
            Keyword("var"),
            Local("v"),
            Operators.Equals,
            Parameter("s"),
            Operators.Dot,
            ExtensionMethod("IsNullOrEmpty"),
            Punctuation.OpenParen,
            Punctuation.CloseParen,
            Punctuation.Semicolon,
            Punctuation.CloseCurly,
            Punctuation.CloseCurly);
}