File: Parsing\NameParsingTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Syntax\Microsoft.CodeAnalysis.CSharp.Syntax.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Syntax.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    public class NameParsingTests : ParsingTests
    {
        public NameParsingTests(ITestOutputHelper output) : base(output) { }
 
        private NameSyntax ParseName(string text)
        {
            return SyntaxFactory.ParseName(text);
        }
 
        private TypeSyntax ParseTypeName(string text)
        {
            return SyntaxFactory.ParseTypeName(text);
        }
 
        [Fact]
        public void TestBasicName()
        {
            var text = "goo";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.False(((IdentifierNameSyntax)name).Identifier.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestBasicNameWithTrash()
        {
            var text = "/*comment*/goo/*comment2*/ bar";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.False(((IdentifierNameSyntax)name).Identifier.IsMissing);
            Assert.Equal(1, name.Errors().Length);
            Assert.Equal(text, name.ToFullString());
        }
 
        [Fact]
        public void TestMissingName()
        {
            var text = string.Empty;
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.True(((IdentifierNameSyntax)name).Identifier.IsMissing);
            Assert.Equal(1, name.Errors().Length);
            Assert.Equal((int)ErrorCode.ERR_IdentifierExpected, name.Errors()[0].Code);
            Assert.Equal(string.Empty, name.ToString());
        }
 
        [Fact]
        public void TestMissingNameDueToKeyword()
        {
            var text = "class";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.True(name.IsMissing);
            Assert.Equal(2, name.Errors().Length);
            Assert.Equal((int)ErrorCode.ERR_UnexpectedToken, name.Errors()[0].Code);
            Assert.Equal((int)ErrorCode.ERR_IdentifierExpected, name.Errors()[1].Code);
            Assert.Equal(string.Empty, name.ToString());
        }
 
        [Fact]
        public void TestMissingNameDueToPartialClassStart()
        {
            var text = "partial class";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.True(name.IsMissing);
            Assert.Equal(2, name.Errors().Length);
            Assert.Equal((int)ErrorCode.ERR_UnexpectedToken, name.Errors()[0].Code);
            Assert.Equal((int)ErrorCode.ERR_InvalidExprTerm, name.Errors()[1].Code);
            Assert.Equal(string.Empty, name.ToString());
        }
 
        [Fact]
        public void TestMissingNameDueToPartialMethodStart()
        {
            var text = "partial void Method()";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.True(name.IsMissing);
            Assert.Equal(2, name.Errors().Length);
            Assert.Equal((int)ErrorCode.ERR_UnexpectedToken, name.Errors()[0].Code);
            Assert.Equal((int)ErrorCode.ERR_InvalidExprTerm, name.Errors()[1].Code);
            Assert.Equal(string.Empty, name.ToString());
        }
 
        [Fact]
        public void TestAliasedName()
        {
            var text = "goo::bar";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.AliasQualifiedName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestGlobalAliasedName()
        {
            var text = "global::bar";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.False(name.IsMissing);
            Assert.Equal(SyntaxKind.AliasQualifiedName, name.Kind());
            var an = (AliasQualifiedNameSyntax)name;
            Assert.Equal(SyntaxKind.GlobalKeyword, an.Alias.Identifier.Kind());
            Assert.Equal(0, name.Errors().Length);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestDottedName()
        {
            var text = "goo.bar";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.QualifiedName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestAliasedDottedName()
        {
            var text = "goo::bar.Zed";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.QualifiedName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            Assert.Equal(text, name.ToString());
 
            name = ((QualifiedNameSyntax)name).Left;
            Assert.Equal(SyntaxKind.AliasQualifiedName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
        }
 
        [Fact]
        public void TestDoubleAliasName()
        {
            // In the original implementation of the parser this error case was parsed as 
            //
            // (goo :: bar ) :: baz
            //
            // However, we have decided that the left hand side of a :: should always be
            // an identifier, not a name, even in error cases. Therefore instead we 
            // parse this as though the error was that the user intended to make the 
            // second :: a dot; we parse this as
            //
            // (goo :: bar ) . baz
 
            var text = "goo::bar::baz";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.QualifiedName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(1, name.Errors().Length);
            Assert.Equal(text, name.ToString());
 
            name = ((QualifiedNameSyntax)name).Left;
            Assert.Equal(SyntaxKind.AliasQualifiedName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
        }
 
        [Fact]
        public void TestGenericName()
        {
            var text = "goo<bar>";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.GenericName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            var gname = (GenericNameSyntax)name;
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.False(gname.IsUnboundGenericName);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestGenericNameWithTwoArguments()
        {
            var text = "goo<bar,zed>";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.GenericName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            var gname = (GenericNameSyntax)name;
            Assert.Equal(2, gname.TypeArgumentList.Arguments.Count);
            Assert.False(gname.IsUnboundGenericName);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestNestedGenericName_01()
        {
            var text = "goo<bar<zed>>";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.GenericName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            var gname = (GenericNameSyntax)name;
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.False(gname.IsUnboundGenericName);
            Assert.NotNull(gname.TypeArgumentList.Arguments[0]);
            Assert.Equal(SyntaxKind.GenericName, gname.TypeArgumentList.Arguments[0].Kind());
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestNestedGenericName_02()
        {
            var text = "goo<bar<zed<U>>>";
            var name = ParseName(text);
 
            UsingNode(text, name);
 
            N(SyntaxKind.GenericName);
            {
                N(SyntaxKind.IdentifierToken, "goo");
                N(SyntaxKind.TypeArgumentList);
                {
                    N(SyntaxKind.LessThanToken);
                    N(SyntaxKind.GenericName);
                    {
                        N(SyntaxKind.IdentifierToken, "bar");
                        N(SyntaxKind.TypeArgumentList);
                        {
                            N(SyntaxKind.LessThanToken);
                            N(SyntaxKind.GenericName);
                            {
                                N(SyntaxKind.IdentifierToken, "zed");
                                N(SyntaxKind.TypeArgumentList);
                                {
                                    N(SyntaxKind.LessThanToken);
                                    N(SyntaxKind.IdentifierName);
                                    {
                                        N(SyntaxKind.IdentifierToken, "U");
                                    }
                                    N(SyntaxKind.GreaterThanToken);
                                }
                            }
                            N(SyntaxKind.GreaterThanToken);
                        }
                    }
                    N(SyntaxKind.GreaterThanToken);
                }
            }
            EOF();
        }
 
        [Fact]
        public void TestOpenNameWithNoCommas()
        {
            var text = "goo<>";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.GenericName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            var gname = (GenericNameSyntax)name;
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.Equal(0, gname.TypeArgumentList.Arguments.SeparatorCount);
            Assert.True(gname.IsUnboundGenericName);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestOpenNameWithAComma()
        {
            var text = "goo<,>";
            var name = ParseName(text);
 
            Assert.NotNull(name);
            Assert.Equal(SyntaxKind.GenericName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            var gname = (GenericNameSyntax)name;
            Assert.Equal(2, gname.TypeArgumentList.Arguments.Count);
            Assert.Equal(1, gname.TypeArgumentList.Arguments.SeparatorCount);
            Assert.True(gname.IsUnboundGenericName);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestBasicTypeName()
        {
            var text = "goo";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(SyntaxKind.IdentifierName, tname.Kind());
            var name = (NameSyntax)tname;
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestDottedTypeName()
        {
            var text = "goo.bar";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(SyntaxKind.QualifiedName, tname.Kind());
            var name = (NameSyntax)tname;
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestGenericTypeName()
        {
            var text = "goo<bar>";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(SyntaxKind.GenericName, tname.Kind());
            var name = (NameSyntax)tname;
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            var gname = (GenericNameSyntax)name;
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.False(gname.IsUnboundGenericName);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestNestedGenericTypeName_01()
        {
            var text = "goo<bar<zed>>";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(SyntaxKind.GenericName, tname.Kind());
            var name = (NameSyntax)tname;
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            var gname = (GenericNameSyntax)name;
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.False(gname.IsUnboundGenericName);
            Assert.NotNull(gname.TypeArgumentList.Arguments[0]);
            Assert.Equal(SyntaxKind.GenericName, gname.TypeArgumentList.Arguments[0].Kind());
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestNestedGenericTypeName_02()
        {
            var text = "goo<bar<zed<U>>>";
            var tname = ParseTypeName(text);
 
            UsingNode(text, tname);
 
            N(SyntaxKind.GenericName);
            {
                N(SyntaxKind.IdentifierToken, "goo");
                N(SyntaxKind.TypeArgumentList);
                {
                    N(SyntaxKind.LessThanToken);
                    N(SyntaxKind.GenericName);
                    {
                        N(SyntaxKind.IdentifierToken, "bar");
                        N(SyntaxKind.TypeArgumentList);
                        {
                            N(SyntaxKind.LessThanToken);
                            N(SyntaxKind.GenericName);
                            {
                                N(SyntaxKind.IdentifierToken, "zed");
                                N(SyntaxKind.TypeArgumentList);
                                {
                                    N(SyntaxKind.LessThanToken);
                                    N(SyntaxKind.IdentifierName);
                                    {
                                        N(SyntaxKind.IdentifierToken, "U");
                                    }
                                    N(SyntaxKind.GreaterThanToken);
                                }
                            }
                            N(SyntaxKind.GreaterThanToken);
                        }
                    }
                    N(SyntaxKind.GreaterThanToken);
                }
            }
            EOF();
        }
 
        [Fact]
        public void TestOpenTypeNameWithNoCommas()
        {
            var text = "goo<>";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(SyntaxKind.GenericName, tname.Kind());
            var name = (NameSyntax)tname;
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
            var gname = (GenericNameSyntax)name;
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.Equal(0, gname.TypeArgumentList.Arguments.SeparatorCount);
            Assert.True(gname.IsUnboundGenericName);
            Assert.Equal(text, name.ToString());
        }
 
        [Fact]
        public void TestKnownTypeNames()
        {
            ParseKnownTypeName(SyntaxKind.BoolKeyword);
            ParseKnownTypeName(SyntaxKind.ByteKeyword);
            ParseKnownTypeName(SyntaxKind.SByteKeyword);
            ParseKnownTypeName(SyntaxKind.ShortKeyword);
            ParseKnownTypeName(SyntaxKind.UShortKeyword);
            ParseKnownTypeName(SyntaxKind.IntKeyword);
            ParseKnownTypeName(SyntaxKind.UIntKeyword);
            ParseKnownTypeName(SyntaxKind.LongKeyword);
            ParseKnownTypeName(SyntaxKind.ULongKeyword);
            ParseKnownTypeName(SyntaxKind.FloatKeyword);
            ParseKnownTypeName(SyntaxKind.DoubleKeyword);
            ParseKnownTypeName(SyntaxKind.DecimalKeyword);
            ParseKnownTypeName(SyntaxKind.StringKeyword);
            ParseKnownTypeName(SyntaxKind.ObjectKeyword);
        }
 
        private void ParseKnownTypeName(SyntaxKind kind)
        {
            var text = SyntaxFacts.GetText(kind);
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(SyntaxKind.PredefinedType, tname.Kind());
            Assert.Equal(text, tname.ToString());
            var tok = ((PredefinedTypeSyntax)tname).Keyword;
            Assert.Equal(kind, tok.Kind());
        }
 
        [Fact]
        public void TestNullableTypeName()
        {
            var text = "goo?";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(SyntaxKind.NullableType, tname.Kind());
            Assert.Equal(text, tname.ToString());
            var name = (NameSyntax)((NullableTypeSyntax)tname).ElementType;
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
        }
 
        [Fact]
        public void TestPointerTypeName()
        {
            var text = "goo*";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(SyntaxKind.PointerType, tname.Kind());
            Assert.Equal(text, tname.ToString());
            var name = (NameSyntax)((PointerTypeSyntax)tname).ElementType;
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
        }
 
        [Fact]
        public void TestPointerTypeNameWithMultipleAsterisks()
        {
            var text = "goo***";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(text, tname.ToString());
            Assert.Equal(SyntaxKind.PointerType, tname.Kind());
 
            // check depth of pointer defers
            int depth = 0;
            while (tname.Kind() == SyntaxKind.PointerType)
            {
                tname = ((PointerTypeSyntax)tname).ElementType;
                depth++;
            }
 
            Assert.Equal(3, depth);
 
            var name = (NameSyntax)tname;
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
        }
 
        [Fact]
        public void TestArrayTypeName()
        {
            var text = "goo[]";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(text, tname.ToString());
            Assert.Equal(SyntaxKind.ArrayType, tname.Kind());
 
            var array = (ArrayTypeSyntax)tname;
            Assert.Equal(1, array.RankSpecifiers.Count);
            Assert.Equal(1, array.RankSpecifiers[0].Sizes.Count);
            Assert.Equal(0, array.RankSpecifiers[0].Sizes.SeparatorCount);
            Assert.Equal(1, array.RankSpecifiers[0].Rank);
 
            var name = (NameSyntax)array.ElementType;
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
        }
 
        [Fact]
        public void TestMultiDimensionalArrayTypeName()
        {
            var text = "goo[,,]";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(text, tname.ToString());
            Assert.Equal(SyntaxKind.ArrayType, tname.Kind());
 
            var array = (ArrayTypeSyntax)tname;
            Assert.Equal(1, array.RankSpecifiers.Count);
            Assert.Equal(3, array.RankSpecifiers[0].Sizes.Count);
            Assert.Equal(2, array.RankSpecifiers[0].Sizes.SeparatorCount);
            Assert.Equal(3, array.RankSpecifiers[0].Rank);
 
            var name = (NameSyntax)array.ElementType;
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
        }
 
        [Fact]
        public void TestMultiRankedArrayTypeName()
        {
            var text = "goo[][,][,,]";
            var tname = ParseTypeName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(text, tname.ToString());
            Assert.Equal(SyntaxKind.ArrayType, tname.Kind());
 
            var array = (ArrayTypeSyntax)tname;
            Assert.Equal(3, array.RankSpecifiers.Count);
 
            Assert.Equal(1, array.RankSpecifiers[0].Sizes.Count);
            Assert.Equal(0, array.RankSpecifiers[0].Sizes.SeparatorCount);
            Assert.Equal(1, array.RankSpecifiers[0].Rank);
 
            Assert.Equal(2, array.RankSpecifiers[1].Sizes.Count);
            Assert.Equal(1, array.RankSpecifiers[1].Sizes.SeparatorCount);
            Assert.Equal(2, array.RankSpecifiers[1].Rank);
 
            Assert.Equal(3, array.RankSpecifiers[2].Sizes.Count);
            Assert.Equal(2, array.RankSpecifiers[2].Sizes.SeparatorCount);
            Assert.Equal(3, array.RankSpecifiers[2].Rank);
 
            var name = (NameSyntax)array.ElementType;
            Assert.Equal(SyntaxKind.IdentifierName, name.Kind());
            Assert.False(name.IsMissing);
            Assert.Equal(0, name.Errors().Length);
        }
 
        [Fact]
        public void TestVarianceInNameBad()
        {
            var text = "goo<in bar>";
            var tname = ParseName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(text, tname.ToString());
            Assert.Equal(SyntaxKind.GenericName, tname.Kind());
 
            var gname = (GenericNameSyntax)tname;
            Assert.Equal("goo", gname.Identifier.ToString());
            Assert.False(gname.IsUnboundGenericName);
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.NotNull(gname.TypeArgumentList.Arguments[0]);
 
            var arg = gname.TypeArgumentList.Arguments[0];
            Assert.Equal(SyntaxKind.IdentifierName, arg.Kind());
            Assert.True(arg.ContainsDiagnostics);
            Assert.Equal(1, arg.Errors().Length);
            Assert.Equal((int)ErrorCode.ERR_IllegalVarianceSyntax, arg.Errors()[0].Code);
 
            Assert.Equal(text, tname.ToString());
        }
 
        [Fact]
        public void TestAttributeInNameBad()
        {
            var text = "goo<[My]bar>";
            var tname = ParseName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(text, tname.ToString());
            Assert.Equal(SyntaxKind.GenericName, tname.Kind());
 
            var gname = (GenericNameSyntax)tname;
            Assert.Equal("goo", gname.Identifier.ToString());
            Assert.False(gname.IsUnboundGenericName);
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.NotNull(gname.TypeArgumentList.Arguments[0]);
 
            var arg = gname.TypeArgumentList.Arguments[0];
            Assert.Equal(SyntaxKind.IdentifierName, arg.Kind());
            Assert.True(arg.ContainsDiagnostics);
            Assert.Equal(1, arg.Errors().Length);
            Assert.Equal((int)ErrorCode.ERR_TypeExpected, arg.Errors()[0].Code);
 
            Assert.Equal(text, tname.ToString());
        }
 
        [WorkItem(7177, "https://github.com/dotnet/roslyn/issues/7177")]
        [Fact]
        public void TestConstantInGenericNameBad()
        {
            var text = "goo<0>";
            var tname = ParseName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(text, tname.ToString());
            Assert.Equal(SyntaxKind.GenericName, tname.Kind());
 
            var gname = (GenericNameSyntax)tname;
            Assert.Equal("goo", gname.Identifier.ToString());
            Assert.False(gname.IsUnboundGenericName);
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.NotNull(gname.TypeArgumentList.Arguments[0]);
 
            var arg = gname.TypeArgumentList.Arguments[0];
            Assert.Equal(SyntaxKind.IdentifierName, arg.Kind());
            Assert.True(arg.ContainsDiagnostics);
            Assert.Equal(1, arg.Errors().Length);
            Assert.Equal((int)ErrorCode.ERR_TypeExpected, arg.Errors()[0].Code);
 
            Assert.Equal(text, tname.ToString());
        }
 
        [WorkItem(7177, "https://github.com/dotnet/roslyn/issues/7177")]
        [Fact]
        public void TestConstantInGenericNamePartiallyBad()
        {
            var text = "goo<0,bool>";
            var tname = ParseName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(text, tname.ToString());
            Assert.Equal(SyntaxKind.GenericName, tname.Kind());
 
            var gname = (GenericNameSyntax)tname;
            Assert.Equal("goo", gname.Identifier.ToString());
            Assert.False(gname.IsUnboundGenericName);
            Assert.Equal(2, gname.TypeArgumentList.Arguments.Count);
            Assert.NotNull(gname.TypeArgumentList.Arguments[0]);
            Assert.NotNull(gname.TypeArgumentList.Arguments[1]);
 
            var arg = gname.TypeArgumentList.Arguments[0];
            Assert.Equal(SyntaxKind.IdentifierName, arg.Kind());
            Assert.True(arg.ContainsDiagnostics);
            Assert.Equal(1, arg.Errors().Length);
            Assert.Equal((int)ErrorCode.ERR_TypeExpected, arg.Errors()[0].Code);
 
            var arg2 = gname.TypeArgumentList.Arguments[1];
            Assert.Equal(SyntaxKind.PredefinedType, arg2.Kind());
            Assert.False(arg2.ContainsDiagnostics);
            Assert.Equal(0, arg2.Errors().Length);
 
            Assert.Equal(text, tname.ToString());
        }
 
        [WorkItem(7177, "https://github.com/dotnet/roslyn/issues/7177")]
        [Fact]
        public void TestKeywordInGenericNameBad()
        {
            var text = "goo<static>";
            var tname = ParseName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(text, tname.ToString());
            Assert.Equal(SyntaxKind.GenericName, tname.Kind());
 
            var gname = (GenericNameSyntax)tname;
            Assert.Equal("goo", gname.Identifier.ToString());
            Assert.False(gname.IsUnboundGenericName);
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.NotNull(gname.TypeArgumentList.Arguments[0]);
 
            var arg = gname.TypeArgumentList.Arguments[0];
            Assert.Equal(SyntaxKind.IdentifierName, arg.Kind());
            Assert.True(arg.ContainsDiagnostics);
            Assert.Equal(1, arg.Errors().Length);
            Assert.Equal((int)ErrorCode.ERR_TypeExpected, arg.Errors()[0].Code);
 
            Assert.Equal(text, tname.ToString());
        }
 
        [Fact]
        public void TestAttributeAndVarianceInNameBad()
        {
            var text = "goo<[My]in bar>";
            var tname = ParseName(text);
 
            Assert.NotNull(tname);
            Assert.Equal(text, tname.ToString());
            Assert.Equal(SyntaxKind.GenericName, tname.Kind());
 
            var gname = (GenericNameSyntax)tname;
            Assert.Equal("goo", gname.Identifier.ToString());
            Assert.False(gname.IsUnboundGenericName);
            Assert.Equal(1, gname.TypeArgumentList.Arguments.Count);
            Assert.NotNull(gname.TypeArgumentList.Arguments[0]);
 
            var arg = gname.TypeArgumentList.Arguments[0];
            Assert.Equal(SyntaxKind.IdentifierName, arg.Kind());
            Assert.True(arg.ContainsDiagnostics);
            Assert.Equal(2, arg.Errors().Length);
            Assert.Equal((int)ErrorCode.ERR_TypeExpected, arg.Errors()[0].Code);
            Assert.Equal((int)ErrorCode.ERR_IllegalVarianceSyntax, arg.Errors()[1].Code);
 
            Assert.Equal(text, tname.ToString());
        }
 
        [WorkItem(545778, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545778")]
        [Fact]
        public void TestFormattingCharacter()
        {
            var text = "\u0915\u094d\u200d\u0937";
            var tok = SyntaxFactory.ParseToken(text);
 
            Assert.NotEqual(default, tok);
            Assert.Equal(text, tok.ToString());
            Assert.NotEqual(text, tok.ValueText);
            Assert.Equal("\u0915\u094d\u0937", tok.ValueText); //formatting character \u200d removed
 
            Assert.True(SyntaxFacts.ContainsDroppedIdentifierCharacters(text));
            Assert.False(SyntaxFacts.ContainsDroppedIdentifierCharacters(tok.ValueText));
        }
 
        [WorkItem(959148, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/959148")]
        [Fact]
        public void TestSoftHyphen()
        {
            var text = "x\u00ady";
            var tok = SyntaxFactory.ParseToken(text);
 
            Assert.NotEqual(default, tok);
            Assert.Equal(text, tok.ToString());
            Assert.NotEqual(text, tok.ValueText);
            Assert.Equal("xy", tok.ValueText); // formatting character SOFT HYPHEN (U+00AD) removed
 
            Assert.True(SyntaxFacts.ContainsDroppedIdentifierCharacters(text));
            Assert.False(SyntaxFacts.ContainsDroppedIdentifierCharacters(tok.ValueText));
        }
 
        [WorkItem(545778, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545778")]
        [Fact]
        public void ContainsDroppedIdentifierCharacters()
        {
            Assert.False(SyntaxFacts.ContainsDroppedIdentifierCharacters(null));
            Assert.False(SyntaxFacts.ContainsDroppedIdentifierCharacters(""));
            Assert.False(SyntaxFacts.ContainsDroppedIdentifierCharacters("a"));
            Assert.False(SyntaxFacts.ContainsDroppedIdentifierCharacters("a@"));
 
            Assert.True(SyntaxFacts.ContainsDroppedIdentifierCharacters("@"));
            Assert.True(SyntaxFacts.ContainsDroppedIdentifierCharacters("@a"));
            Assert.True(SyntaxFacts.ContainsDroppedIdentifierCharacters("\u200d"));
            Assert.True(SyntaxFacts.ContainsDroppedIdentifierCharacters("a\u200d"));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67277")]
        public void ParseGenericNameInvocationWithOmittedTypeArguments()
        {
            var source = """
                class C
                {
                    void M<T1, T2>()
                    {
                        M<,>();
                    }
                }
                """;
 
            UsingTree(source);
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.ClassDeclaration);
                {
                    N(SyntaxKind.ClassKeyword);
                    N(SyntaxKind.IdentifierToken, "C");
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.MethodDeclaration);
                    {
                        N(SyntaxKind.PredefinedType);
                        {
                            N(SyntaxKind.VoidKeyword);
                        }
                        N(SyntaxKind.IdentifierToken, "M");
                        N(SyntaxKind.TypeParameterList);
                        {
                            N(SyntaxKind.LessThanToken);
                            N(SyntaxKind.TypeParameter);
                            {
                                N(SyntaxKind.IdentifierToken, "T1");
                            }
                            N(SyntaxKind.CommaToken);
                            N(SyntaxKind.TypeParameter);
                            {
                                N(SyntaxKind.IdentifierToken, "T2");
                            }
                            N(SyntaxKind.GreaterThanToken);
                        }
                        N(SyntaxKind.ParameterList);
                        {
                            N(SyntaxKind.OpenParenToken);
                            N(SyntaxKind.CloseParenToken);
                        }
                        N(SyntaxKind.Block);
                        {
                            N(SyntaxKind.OpenBraceToken);
                            N(SyntaxKind.ExpressionStatement);
                            {
                                N(SyntaxKind.InvocationExpression);
                                {
                                    N(SyntaxKind.GenericName);
                                    {
                                        N(SyntaxKind.IdentifierToken, "M");
                                        N(SyntaxKind.TypeArgumentList);
                                        {
                                            N(SyntaxKind.LessThanToken);
                                            N(SyntaxKind.OmittedTypeArgument);
                                            {
                                                N(SyntaxKind.OmittedTypeArgumentToken);
                                            }
                                            N(SyntaxKind.CommaToken);
                                            N(SyntaxKind.OmittedTypeArgument);
                                            {
                                                N(SyntaxKind.OmittedTypeArgumentToken);
                                            }
                                            N(SyntaxKind.GreaterThanToken);
                                        }
                                    }
                                    N(SyntaxKind.ArgumentList);
                                    {
                                        N(SyntaxKind.OpenParenToken);
                                        N(SyntaxKind.CloseParenToken);
                                    }
                                }
                                N(SyntaxKind.SemicolonToken);
                            }
                            N(SyntaxKind.CloseBraceToken);
                        }
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
 
            CreateCompilation(source).VerifyDiagnostics(
                // (5,9): error CS0305: Using the generic method group 'M' requires 2 type arguments
                //         M<,>();
                Diagnostic(ErrorCode.ERR_BadArity, "M<,>").WithArguments("M", "method group", "2").WithLocation(5, 9));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67277")]
        public void ParseGenericNameInvocationWithOmittedTypeArguments_CSharp1()
        {
            var source = """
                class C
                {
                    void M<T1, T2>()
                    {
                        M<,>();
                    }
                }
                """;
 
            UsingTree(source, TestOptions.Regular1,
                // (5,10): error CS8022: Feature 'generics' is not available in C# 1. Please use language version 2 or greater.
                //         M<,>();
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion1, "<").WithArguments("generics", "2").WithLocation(5, 10));
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.ClassDeclaration);
                {
                    N(SyntaxKind.ClassKeyword);
                    N(SyntaxKind.IdentifierToken, "C");
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.MethodDeclaration);
                    {
                        N(SyntaxKind.PredefinedType);
                        {
                            N(SyntaxKind.VoidKeyword);
                        }
                        N(SyntaxKind.IdentifierToken, "M");
                        N(SyntaxKind.TypeParameterList);
                        {
                            N(SyntaxKind.LessThanToken);
                            N(SyntaxKind.TypeParameter);
                            {
                                N(SyntaxKind.IdentifierToken, "T1");
                            }
                            N(SyntaxKind.CommaToken);
                            N(SyntaxKind.TypeParameter);
                            {
                                N(SyntaxKind.IdentifierToken, "T2");
                            }
                            N(SyntaxKind.GreaterThanToken);
                        }
                        N(SyntaxKind.ParameterList);
                        {
                            N(SyntaxKind.OpenParenToken);
                            N(SyntaxKind.CloseParenToken);
                        }
                        N(SyntaxKind.Block);
                        {
                            N(SyntaxKind.OpenBraceToken);
                            N(SyntaxKind.ExpressionStatement);
                            {
                                N(SyntaxKind.InvocationExpression);
                                {
                                    N(SyntaxKind.GenericName);
                                    {
                                        N(SyntaxKind.IdentifierToken, "M");
                                        N(SyntaxKind.TypeArgumentList);
                                        {
                                            N(SyntaxKind.LessThanToken);
                                            N(SyntaxKind.OmittedTypeArgument);
                                            {
                                                N(SyntaxKind.OmittedTypeArgumentToken);
                                            }
                                            N(SyntaxKind.CommaToken);
                                            N(SyntaxKind.OmittedTypeArgument);
                                            {
                                                N(SyntaxKind.OmittedTypeArgumentToken);
                                            }
                                            N(SyntaxKind.GreaterThanToken);
                                        }
                                    }
                                    N(SyntaxKind.ArgumentList);
                                    {
                                        N(SyntaxKind.OpenParenToken);
                                        N(SyntaxKind.CloseParenToken);
                                    }
                                }
                                N(SyntaxKind.SemicolonToken);
                            }
                            N(SyntaxKind.CloseBraceToken);
                        }
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
 
            CreateCompilation(source, parseOptions: TestOptions.Regular1).VerifyDiagnostics(
                // (3,11): error CS8022: Feature 'generics' is not available in C# 1. Please use language version 2 or greater.
                //     void M<T1, T2>()
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion1, "<").WithArguments("generics", "2").WithLocation(3, 11),
                // (5,9): error CS0305: Using the generic method group 'M' requires 2 type arguments
                //         M<,>();
                Diagnostic(ErrorCode.ERR_BadArity, "M<,>").WithArguments("M", "method group", "2").WithLocation(5, 9),
                // (5,10): error CS8022: Feature 'generics' is not available in C# 1. Please use language version 2 or greater.
                //         M<,>();
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion1, "<").WithArguments("generics", "2").WithLocation(5, 10));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67277")]
        public void ParseGenericNameInvocationWithOmittedTypeArguments2()
        {
            var source = """
                class X<T>
                {
                }
 
                class C
                {
                    void M<T1, T2>()
                    {
                        M<int,X<>>();
                    }
                }
                """;
 
            UsingTree(source);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.ClassDeclaration);
                {
                    N(SyntaxKind.ClassKeyword);
                    N(SyntaxKind.IdentifierToken, "X");
                    N(SyntaxKind.TypeParameterList);
                    {
                        N(SyntaxKind.LessThanToken);
                        N(SyntaxKind.TypeParameter);
                        {
                            N(SyntaxKind.IdentifierToken, "T");
                        }
                        N(SyntaxKind.GreaterThanToken);
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.ClassDeclaration);
                {
                    N(SyntaxKind.ClassKeyword);
                    N(SyntaxKind.IdentifierToken, "C");
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.MethodDeclaration);
                    {
                        N(SyntaxKind.PredefinedType);
                        {
                            N(SyntaxKind.VoidKeyword);
                        }
                        N(SyntaxKind.IdentifierToken, "M");
                        N(SyntaxKind.TypeParameterList);
                        {
                            N(SyntaxKind.LessThanToken);
                            N(SyntaxKind.TypeParameter);
                            {
                                N(SyntaxKind.IdentifierToken, "T1");
                            }
                            N(SyntaxKind.CommaToken);
                            N(SyntaxKind.TypeParameter);
                            {
                                N(SyntaxKind.IdentifierToken, "T2");
                            }
                            N(SyntaxKind.GreaterThanToken);
                        }
                        N(SyntaxKind.ParameterList);
                        {
                            N(SyntaxKind.OpenParenToken);
                            N(SyntaxKind.CloseParenToken);
                        }
                        N(SyntaxKind.Block);
                        {
                            N(SyntaxKind.OpenBraceToken);
                            N(SyntaxKind.ExpressionStatement);
                            {
                                N(SyntaxKind.InvocationExpression);
                                {
                                    N(SyntaxKind.GenericName);
                                    {
                                        N(SyntaxKind.IdentifierToken, "M");
                                        N(SyntaxKind.TypeArgumentList);
                                        {
                                            N(SyntaxKind.LessThanToken);
                                            N(SyntaxKind.PredefinedType);
                                            {
                                                N(SyntaxKind.IntKeyword);
                                            }
                                            N(SyntaxKind.CommaToken);
                                            N(SyntaxKind.GenericName);
                                            {
                                                N(SyntaxKind.IdentifierToken, "X");
                                                N(SyntaxKind.TypeArgumentList);
                                                {
                                                    N(SyntaxKind.LessThanToken);
                                                    N(SyntaxKind.OmittedTypeArgument);
                                                    {
                                                        N(SyntaxKind.OmittedTypeArgumentToken);
                                                    }
                                                    N(SyntaxKind.GreaterThanToken);
                                                }
                                            }
                                            N(SyntaxKind.GreaterThanToken);
                                        }
                                    }
                                    N(SyntaxKind.ArgumentList);
                                    {
                                        N(SyntaxKind.OpenParenToken);
                                        N(SyntaxKind.CloseParenToken);
                                    }
                                }
                                N(SyntaxKind.SemicolonToken);
                            }
                            N(SyntaxKind.CloseBraceToken);
                        }
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
 
            CreateCompilation(source).VerifyDiagnostics(
                // (9,15): error CS7003: Unexpected use of an unbound generic name
                //         M<int,X<>>();
                Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "X<>").WithLocation(9, 15));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67277")]
        public void ParseGenericNameInvocationWithOmittedTypeArguments3()
        {
            var source = """
                class X<T>
                {
                }
 
                class C
                {
                    void M<T1, T2>()
                    {
                        M<X<>, int>();
                    }
                }
                """;
 
            UsingTree(source);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.ClassDeclaration);
                {
                    N(SyntaxKind.ClassKeyword);
                    N(SyntaxKind.IdentifierToken, "X");
                    N(SyntaxKind.TypeParameterList);
                    {
                        N(SyntaxKind.LessThanToken);
                        N(SyntaxKind.TypeParameter);
                        {
                            N(SyntaxKind.IdentifierToken, "T");
                        }
                        N(SyntaxKind.GreaterThanToken);
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.ClassDeclaration);
                {
                    N(SyntaxKind.ClassKeyword);
                    N(SyntaxKind.IdentifierToken, "C");
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.MethodDeclaration);
                    {
                        N(SyntaxKind.PredefinedType);
                        {
                            N(SyntaxKind.VoidKeyword);
                        }
                        N(SyntaxKind.IdentifierToken, "M");
                        N(SyntaxKind.TypeParameterList);
                        {
                            N(SyntaxKind.LessThanToken);
                            N(SyntaxKind.TypeParameter);
                            {
                                N(SyntaxKind.IdentifierToken, "T1");
                            }
                            N(SyntaxKind.CommaToken);
                            N(SyntaxKind.TypeParameter);
                            {
                                N(SyntaxKind.IdentifierToken, "T2");
                            }
                            N(SyntaxKind.GreaterThanToken);
                        }
                        N(SyntaxKind.ParameterList);
                        {
                            N(SyntaxKind.OpenParenToken);
                            N(SyntaxKind.CloseParenToken);
                        }
                        N(SyntaxKind.Block);
                        {
                            N(SyntaxKind.OpenBraceToken);
                            N(SyntaxKind.ExpressionStatement);
                            {
                                N(SyntaxKind.InvocationExpression);
                                {
                                    N(SyntaxKind.GenericName);
                                    {
                                        N(SyntaxKind.IdentifierToken, "M");
                                        N(SyntaxKind.TypeArgumentList);
                                        {
                                            N(SyntaxKind.LessThanToken);
                                            N(SyntaxKind.GenericName);
                                            {
                                                N(SyntaxKind.IdentifierToken, "X");
                                                N(SyntaxKind.TypeArgumentList);
                                                {
                                                    N(SyntaxKind.LessThanToken);
                                                    N(SyntaxKind.OmittedTypeArgument);
                                                    {
                                                        N(SyntaxKind.OmittedTypeArgumentToken);
                                                    }
                                                    N(SyntaxKind.GreaterThanToken);
                                                }
                                            }
                                            N(SyntaxKind.CommaToken);
                                            N(SyntaxKind.PredefinedType);
                                            {
                                                N(SyntaxKind.IntKeyword);
                                            }
                                            N(SyntaxKind.GreaterThanToken);
                                        }
                                    }
                                    N(SyntaxKind.ArgumentList);
                                    {
                                        N(SyntaxKind.OpenParenToken);
                                        N(SyntaxKind.CloseParenToken);
                                    }
                                }
                                N(SyntaxKind.SemicolonToken);
                            }
                            N(SyntaxKind.CloseBraceToken);
                        }
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
 
            CreateCompilation(source).VerifyDiagnostics(
                // (9,11): error CS7003: Unexpected use of an unbound generic name
                //         M<X<>, int>();
                Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "X<>").WithLocation(9, 11));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67277")]
        public void ParseGenericNameInvocationWithOmittedTypeArguments4()
        {
            var source = """
                class X<T>
                {
                }
 
                class Y<A, B>
                {
                }
 
                class C
                {
                    void M<T1, T2>()
                    {
                        M<X<>, Y<,>>();
                    }
                }
                """;
 
            UsingTree(source);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.ClassDeclaration);
                {
                    N(SyntaxKind.ClassKeyword);
                    N(SyntaxKind.IdentifierToken, "X");
                    N(SyntaxKind.TypeParameterList);
                    {
                        N(SyntaxKind.LessThanToken);
                        N(SyntaxKind.TypeParameter);
                        {
                            N(SyntaxKind.IdentifierToken, "T");
                        }
                        N(SyntaxKind.GreaterThanToken);
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.ClassDeclaration);
                {
                    N(SyntaxKind.ClassKeyword);
                    N(SyntaxKind.IdentifierToken, "Y");
                    N(SyntaxKind.TypeParameterList);
                    {
                        N(SyntaxKind.LessThanToken);
                        N(SyntaxKind.TypeParameter);
                        {
                            N(SyntaxKind.IdentifierToken, "A");
                        }
                        N(SyntaxKind.CommaToken);
                        N(SyntaxKind.TypeParameter);
                        {
                            N(SyntaxKind.IdentifierToken, "B");
                        }
                        N(SyntaxKind.GreaterThanToken);
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.ClassDeclaration);
                {
                    N(SyntaxKind.ClassKeyword);
                    N(SyntaxKind.IdentifierToken, "C");
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.MethodDeclaration);
                    {
                        N(SyntaxKind.PredefinedType);
                        {
                            N(SyntaxKind.VoidKeyword);
                        }
                        N(SyntaxKind.IdentifierToken, "M");
                        N(SyntaxKind.TypeParameterList);
                        {
                            N(SyntaxKind.LessThanToken);
                            N(SyntaxKind.TypeParameter);
                            {
                                N(SyntaxKind.IdentifierToken, "T1");
                            }
                            N(SyntaxKind.CommaToken);
                            N(SyntaxKind.TypeParameter);
                            {
                                N(SyntaxKind.IdentifierToken, "T2");
                            }
                            N(SyntaxKind.GreaterThanToken);
                        }
                        N(SyntaxKind.ParameterList);
                        {
                            N(SyntaxKind.OpenParenToken);
                            N(SyntaxKind.CloseParenToken);
                        }
                        N(SyntaxKind.Block);
                        {
                            N(SyntaxKind.OpenBraceToken);
                            N(SyntaxKind.ExpressionStatement);
                            {
                                N(SyntaxKind.InvocationExpression);
                                {
                                    N(SyntaxKind.GenericName);
                                    {
                                        N(SyntaxKind.IdentifierToken, "M");
                                        N(SyntaxKind.TypeArgumentList);
                                        {
                                            N(SyntaxKind.LessThanToken);
                                            N(SyntaxKind.GenericName);
                                            {
                                                N(SyntaxKind.IdentifierToken, "X");
                                                N(SyntaxKind.TypeArgumentList);
                                                {
                                                    N(SyntaxKind.LessThanToken);
                                                    N(SyntaxKind.OmittedTypeArgument);
                                                    {
                                                        N(SyntaxKind.OmittedTypeArgumentToken);
                                                    }
                                                    N(SyntaxKind.GreaterThanToken);
                                                }
                                            }
                                            N(SyntaxKind.CommaToken);
                                            N(SyntaxKind.GenericName);
                                            {
                                                N(SyntaxKind.IdentifierToken, "Y");
                                                N(SyntaxKind.TypeArgumentList);
                                                {
                                                    N(SyntaxKind.LessThanToken);
                                                    N(SyntaxKind.OmittedTypeArgument);
                                                    {
                                                        N(SyntaxKind.OmittedTypeArgumentToken);
                                                    }
                                                    N(SyntaxKind.CommaToken);
                                                    N(SyntaxKind.OmittedTypeArgument);
                                                    {
                                                        N(SyntaxKind.OmittedTypeArgumentToken);
                                                    }
                                                    N(SyntaxKind.GreaterThanToken);
                                                }
                                            }
                                            N(SyntaxKind.GreaterThanToken);
                                        }
                                    }
                                    N(SyntaxKind.ArgumentList);
                                    {
                                        N(SyntaxKind.OpenParenToken);
                                        N(SyntaxKind.CloseParenToken);
                                    }
                                }
                                N(SyntaxKind.SemicolonToken);
                            }
                            N(SyntaxKind.CloseBraceToken);
                        }
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
 
            CreateCompilation(source).VerifyDiagnostics(
                // (13,11): error CS7003: Unexpected use of an unbound generic name
                //         M<X<>, Y<,>>();
                Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "X<>").WithLocation(13, 11),
                // (13,16): error CS7003: Unexpected use of an unbound generic name
                //         M<X<>, Y<,>>();
                Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "Y<,>").WithLocation(13, 16));
        }
    }
}