File: Syntax\SyntaxTreeTests.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 System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
using Xunit.Abstractions;
using static Roslyn.Test.Utilities.TestHelpers;
using KeyValuePair = Roslyn.Utilities.KeyValuePairUtil;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    public class SyntaxTreeTests : ParsingTests
    {
        public SyntaxTreeTests(ITestOutputHelper output) : base(output) { }
 
        public enum SyntaxTreeFactoryKind
        {
            Create,
            Subclass,
            ParseText,
            SynthesizedSyntaxTree,
            ParsedTreeWithPath,
            ParsedTreeWithRootAndOptions,
        }
 
        [Theory]
        [CombinatorialData]
        public void SyntaxTreeCreationAndDirectiveParsing(SyntaxTreeFactoryKind factoryKind)
        {
            var source = """
                #define U
 
                #if !Q
                #undef U
                #endif
 
                #if U
                #define X
                #else
                #define Y
                #endif
 
                using System.Diagnostics;
 
                #if Y
                class C
                {
                    [Conditional("Y")]
                    public static void F1()
                    {
                    }
 
                    [Conditional("U")]
                    public static void F2()
                    {
                    }
 
                    public static void Main()
                    {
                        F1();
                        F2();
                    }
                }
                #endif
                """;
 
            var parseOptions = CSharpParseOptions.Default;
            var root = SyntaxFactory.ParseCompilationUnit(source, options: parseOptions);
 
            var tree = factoryKind switch
            {
                SyntaxTreeFactoryKind.Create => CSharpSyntaxTree.Create(root, options: parseOptions, path: "", encoding: null),
                SyntaxTreeFactoryKind.ParseText => CSharpSyntaxTree.ParseText(SourceText.From(source, Encoding.UTF8, SourceHashAlgorithm.Sha256), parseOptions),
                SyntaxTreeFactoryKind.Subclass => new MockCSharpSyntaxTree(root, SourceText.From(source, Encoding.UTF8, SourceHashAlgorithm.Sha256), parseOptions),
                SyntaxTreeFactoryKind.SynthesizedSyntaxTree => SyntaxNode.CloneNodeAsRoot(root, syntaxTree: null).SyntaxTree,
                SyntaxTreeFactoryKind.ParsedTreeWithPath => WithInitializedDirectives(CSharpSyntaxTree.Create(root, options: parseOptions, path: "old path", Encoding.UTF8)).WithFilePath("new path"),
                SyntaxTreeFactoryKind.ParsedTreeWithRootAndOptions => WithInitializedDirectives(SyntaxFactory.ParseSyntaxTree("", options: parseOptions)).WithRootAndOptions(root, parseOptions),
                _ => throw ExceptionUtilities.UnexpectedValue(factoryKind)
            };
 
            Assert.Equal("#define U | #undef U | #define Y", ((CSharpSyntaxTree)tree).GetDirectives().GetDebuggerDisplay());
 
            var compilation = CSharpCompilation.Create("test", new[] { tree }, TargetFrameworkUtil.GetReferences(TargetFramework.Standard), TestOptions.DebugDll);
 
            CompileAndVerify(compilation).VerifyIL("C.Main", @"
{
  // Code size        8 (0x8)
  .maxstack  0
  IL_0000:  nop
  IL_0001:  call       ""void C.F1()""
  IL_0006:  nop
  IL_0007:  ret
}
");
 
            static SyntaxTree WithInitializedDirectives(SyntaxTree tree)
            {
                _ = ((CSharpSyntaxTree)tree).GetDirectives();
                return tree;
            }
        }
 
        [Fact]
        public void Create()
        {
            var root = SyntaxFactory.ParseCompilationUnit("");
 
            var tree = CSharpSyntaxTree.Create(root);
            Assert.Equal(SourceHashAlgorithm.Sha1, tree.GetText().ChecksumAlgorithm);
        }
 
        // Diagnostic options on syntax trees are now obsolete
#pragma warning disable CS0618
        [Fact]
        public void Create_WithDiagnosticOptions()
        {
            var options = CreateImmutableDictionary(("CS0078", ReportDiagnostic.Suppress));
            var tree = CSharpSyntaxTree.Create(SyntaxFactory.ParseCompilationUnit(""), options: null, path: null, encoding: null, diagnosticOptions: options);
 
            Assert.Same(options, tree.DiagnosticOptions);
            Assert.Equal(SourceHashAlgorithm.Sha1, tree.GetText().ChecksumAlgorithm);
        }
 
        [Fact]
        public void ParseTreeWithChangesPreservesDiagnosticOptions()
        {
            var options = CreateImmutableDictionary(("CS0078", ReportDiagnostic.Suppress));
            var tree = CSharpSyntaxTree.ParseText(
                SourceText.From(""),
                options: null,
                path: "",
                diagnosticOptions: options,
                isGeneratedCode: null,
                cancellationToken: default);
            Assert.Same(options, tree.DiagnosticOptions);
            var newTree = tree.WithChangedText(SourceText.From("class C { }"));
            Assert.Same(options, newTree.DiagnosticOptions);
        }
 
        [Fact]
        public void ParseTreeNullDiagnosticOptions()
        {
            var tree = CSharpSyntaxTree.ParseText(
                SourceText.From(""),
                options: null,
                path: "",
                diagnosticOptions: null,
                isGeneratedCode: null,
                cancellationToken: default);
            Assert.NotNull(tree.DiagnosticOptions);
            Assert.True(tree.DiagnosticOptions.IsEmpty);
            // The default options are case insensitive but the default empty ImmutableDictionary is not
            Assert.NotSame(ImmutableDictionary<string, ReportDiagnostic>.Empty, tree.DiagnosticOptions);
        }
 
        [Fact]
        public void ParseTreeEmptyDiagnosticOptions()
        {
            var tree = CSharpSyntaxTree.ParseText(
                SourceText.From(""),
                options: null,
                path: "",
                diagnosticOptions: ImmutableDictionary<string, ReportDiagnostic>.Empty,
                isGeneratedCode: null,
                cancellationToken: default);
            Assert.NotNull(tree.DiagnosticOptions);
            Assert.True(tree.DiagnosticOptions.IsEmpty);
            Assert.Same(ImmutableDictionary<string, ReportDiagnostic>.Empty, tree.DiagnosticOptions);
        }
 
        [Fact]
        public void ParseTreeCustomDiagnosticOptions()
        {
            var options = CreateImmutableDictionary(("CS0078", ReportDiagnostic.Suppress));
            var tree = CSharpSyntaxTree.ParseText(
                SourceText.From(""),
                options: null,
                path: "",
                diagnosticOptions: options,
                isGeneratedCode: null,
                cancellationToken: default);
            Assert.Same(options, tree.DiagnosticOptions);
        }
 
        [Fact]
        public void DefaultTreeDiagnosticOptions()
        {
            var tree = SyntaxFactory.SyntaxTree(SyntaxFactory.CompilationUnit());
            Assert.NotNull(tree.DiagnosticOptions);
            Assert.True(tree.DiagnosticOptions.IsEmpty);
        }
 
        [Fact]
        public void WithDiagnosticOptionsNull()
        {
            var tree = SyntaxFactory.SyntaxTree(SyntaxFactory.CompilationUnit());
            var newTree = tree.WithDiagnosticOptions(null);
            Assert.NotNull(newTree.DiagnosticOptions);
            Assert.True(newTree.DiagnosticOptions.IsEmpty);
            Assert.Same(tree, newTree);
        }
 
        [Fact]
        public void WithDiagnosticOptionsEmpty()
        {
            var tree = SyntaxFactory.SyntaxTree(SyntaxFactory.CompilationUnit());
            var newTree = tree.WithDiagnosticOptions(ImmutableDictionary<string, ReportDiagnostic>.Empty);
            Assert.NotNull(tree.DiagnosticOptions);
            Assert.True(newTree.DiagnosticOptions.IsEmpty);
            // Default empty immutable dictionary is case sensitive
            Assert.NotSame(tree.DiagnosticOptions, newTree.DiagnosticOptions);
        }
 
        [Fact]
        public void PerTreeDiagnosticOptionsNewDict()
        {
            var tree = SyntaxFactory.SyntaxTree(SyntaxFactory.CompilationUnit());
            var map = ImmutableDictionary.CreateRange(
                new[] { KeyValuePair.Create("CS00778", ReportDiagnostic.Suppress) });
            var newTree = tree.WithDiagnosticOptions(map);
            Assert.NotNull(newTree.DiagnosticOptions);
            Assert.Same(map, newTree.DiagnosticOptions);
            Assert.NotEqual(tree, newTree);
        }
#pragma warning restore CS0618
 
        [Fact]
        public void WithRootAndOptions_ParsedTree()
        {
            var oldTree = SyntaxFactory.ParseSyntaxTree("class B {}");
            var newRoot = SyntaxFactory.ParseCompilationUnit("class C {}");
            var newOptions = new CSharpParseOptions();
            var newTree = oldTree.WithRootAndOptions(newRoot, newOptions);
            var newText = newTree.GetText();
 
            Assert.Equal(newRoot.ToString(), newTree.GetRoot().ToString());
            Assert.Same(newOptions, newTree.Options);
 
            Assert.Null(newText.Encoding);
            Assert.Equal(SourceHashAlgorithm.Sha1, newText.ChecksumAlgorithm);
        }
 
        [Fact]
        public void WithRootAndOptions_ParsedTreeWithText()
        {
            var oldText = SourceText.From("class B {}", Encoding.Unicode, SourceHashAlgorithms.Default);
            var oldTree = SyntaxFactory.ParseSyntaxTree(oldText);
 
            var newRoot = SyntaxFactory.ParseCompilationUnit("class C {}");
            var newOptions = new CSharpParseOptions();
            var newTree = oldTree.WithRootAndOptions(newRoot, newOptions);
            var newText = newTree.GetText();
 
            Assert.Equal(newRoot.ToString(), newTree.GetRoot().ToString());
            Assert.Same(newOptions, newTree.Options);
            Assert.Same(Encoding.Unicode, newText.Encoding);
            Assert.Equal(SourceHashAlgorithms.Default, newText.ChecksumAlgorithm);
        }
 
        [Fact]
        public void WithRootAndOptions_DummyTree()
        {
            var dummy = new CSharpSyntaxTree.DummySyntaxTree();
            var newRoot = SyntaxFactory.ParseCompilationUnit("class C {}");
            var newOptions = new CSharpParseOptions();
            var newTree = dummy.WithRootAndOptions(newRoot, newOptions);
            Assert.Equal(newRoot.ToString(), newTree.GetRoot().ToString());
            Assert.Same(newOptions, newTree.Options);
        }
 
        [Fact]
        public void WithFilePath_ParsedTree()
        {
            var oldTree = SyntaxFactory.ParseSyntaxTree("class B {}", path: "old.cs");
            var newTree = oldTree.WithFilePath("new.cs");
            var newText = newTree.GetText();
 
            Assert.Equal("new.cs", newTree.FilePath);
            Assert.Equal(oldTree.ToString(), newTree.ToString());
 
            Assert.Null(newText.Encoding);
            Assert.Equal(SourceHashAlgorithm.Sha1, newText.ChecksumAlgorithm);
        }
 
        [Fact]
        public void WithFilePath_ParsedTreeWithText()
        {
            var oldText = SourceText.From("class B {}", Encoding.Unicode, SourceHashAlgorithms.Default);
            var oldTree = SyntaxFactory.ParseSyntaxTree(oldText, path: "old.cs");
 
            var newTree = oldTree.WithFilePath("new.cs");
            var newText = newTree.GetText();
 
            Assert.Equal("new.cs", newTree.FilePath);
            Assert.Equal(oldTree.ToString(), newTree.ToString());
 
            Assert.Same(Encoding.Unicode, newText.Encoding);
            Assert.Equal(SourceHashAlgorithms.Default, newText.ChecksumAlgorithm);
        }
 
        [Fact]
        public void WithFilePath_DummyTree()
        {
            var oldTree = new CSharpSyntaxTree.DummySyntaxTree();
            var newTree = oldTree.WithFilePath("new.cs");
 
            Assert.Equal("new.cs", newTree.FilePath);
            Assert.Equal(oldTree.ToString(), newTree.ToString());
        }
 
        [Fact, WorkItem(12638, "https://github.com/dotnet/roslyn/issues/12638")]
        public void WithFilePath_Null()
        {
            SyntaxTree oldTree = new CSharpSyntaxTree.DummySyntaxTree();
            Assert.Equal(string.Empty, oldTree.WithFilePath(null).FilePath);
            oldTree = SyntaxFactory.ParseSyntaxTree("", path: "old.cs");
            Assert.Equal(string.Empty, oldTree.WithFilePath(null).FilePath);
            Assert.Equal(string.Empty, SyntaxFactory.ParseSyntaxTree("", path: null).FilePath);
            Assert.Equal(string.Empty, CSharpSyntaxTree.Create((CSharpSyntaxNode)oldTree.GetRoot()).FilePath);
        }
 
        [Fact]
        public void GlobalUsingDirective_01()
        {
            var test = "global using ns1;";
 
            UsingTree(test, TestOptions.Regular10);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_02()
        {
            var test = "global using ns1;";
 
            CreateCompilation(test, parseOptions: TestOptions.Regular9).VerifyDiagnostics(
                // (1,1): error CS8773: Feature 'global using directive' is not available in C# 9.0. Please use language version 10.0 or greater.
                // global using ns1;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "global").WithArguments("global using directive", "10.0").WithLocation(1, 1),
                // (1,1): hidden CS8019: Unnecessary using directive.
                // global using ns1;
                Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using ns1;").WithLocation(1, 1),
                // (1,14): error CS0246: The type or namespace name 'ns1' could not be found (are you missing a using directive or an assembly reference?)
                // global using ns1;
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ns1").WithArguments("ns1").WithLocation(1, 14));
 
            UsingTree(test, TestOptions.Regular9);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_03()
        {
            var test = "namespace ns { global using ns1; }";
 
            UsingTree(test, TestOptions.Regular10);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.NamespaceDeclaration);
                {
                    N(SyntaxKind.NamespaceKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns");
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.UsingDirective);
                    {
                        N(SyntaxKind.GlobalKeyword);
                        N(SyntaxKind.UsingKeyword);
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "ns1");
                        }
                        N(SyntaxKind.SemicolonToken);
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_04()
        {
            var test = "namespace ns { global using ns1; }";
 
            CreateCompilation(test, parseOptions: TestOptions.Regular9).VerifyDiagnostics(
                // (1,16): error CS8914: A global using directive cannot be used in a namespace declaration.
                // namespace ns { global using ns1; }
                Diagnostic(ErrorCode.ERR_GlobalUsingInNamespace, "global").WithLocation(1, 16),
                // (1,16): error CS8773: Feature 'global using directive' is not available in C# 9.0. Please use language version 10.0 or greater.
                // namespace ns { global using ns1; }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "global").WithArguments("global using directive", "10.0").WithLocation(1, 16),
                // (1,16): hidden CS8019: Unnecessary using directive.
                // namespace ns { global using ns1; }
                Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using ns1;").WithLocation(1, 16),
                // (1,29): error CS0246: The type or namespace name 'ns1' could not be found (are you missing a using directive or an assembly reference?)
                // namespace ns { global using ns1; }
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ns1").WithArguments("ns1").WithLocation(1, 29));
 
            UsingTree(test, TestOptions.Regular9);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.NamespaceDeclaration);
                {
                    N(SyntaxKind.NamespaceKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns");
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.UsingDirective);
                    {
                        N(SyntaxKind.GlobalKeyword);
                        N(SyntaxKind.UsingKeyword);
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "ns1");
                        }
                        N(SyntaxKind.SemicolonToken);
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_05()
        {
            var test = "global using static ns1;";
 
            UsingTree(test, TestOptions.Regular10);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.StaticKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_06()
        {
            var test = "global using static ns1;";
 
            CreateCompilation(test, parseOptions: TestOptions.Regular9).VerifyDiagnostics(
                // (1,1): error CS8773: Feature 'global using directive' is not available in C# 9.0. Please use language version 10.0 or greater.
                // global using static ns1;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "global").WithArguments("global using directive", "10.0").WithLocation(1, 1),
                // (1,1): hidden CS8019: Unnecessary using directive.
                // global using static ns1;
                Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using static ns1;").WithLocation(1, 1),
                // (1,21): error CS0246: The type or namespace name 'ns1' could not be found (are you missing a using directive or an assembly reference?)
                // global using static ns1;
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ns1").WithArguments("ns1").WithLocation(1, 21));
 
            UsingTree(test, TestOptions.Regular9);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.StaticKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_07()
        {
            var test = "namespace ns { global using static ns1; }";
 
            UsingTree(test, TestOptions.Regular10);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.NamespaceDeclaration);
                {
                    N(SyntaxKind.NamespaceKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns");
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.UsingDirective);
                    {
                        N(SyntaxKind.GlobalKeyword);
                        N(SyntaxKind.UsingKeyword);
                        N(SyntaxKind.StaticKeyword);
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "ns1");
                        }
                        N(SyntaxKind.SemicolonToken);
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_08()
        {
            var test = "namespace ns { global using static ns1; }";
 
            CreateCompilation(test, parseOptions: TestOptions.Regular9).VerifyDiagnostics(
                // (1,16): error CS8914: A global using directive cannot be used in a namespace declaration.
                // namespace ns { global using static ns1; }
                Diagnostic(ErrorCode.ERR_GlobalUsingInNamespace, "global").WithLocation(1, 16),
                // (1,16): error CS8773: Feature 'global using directive' is not available in C# 9.0. Please use language version 10.0 or greater.
                // namespace ns { global using static ns1; }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "global").WithArguments("global using directive", "10.0").WithLocation(1, 16),
                // (1,16): hidden CS8019: Unnecessary using directive.
                // namespace ns { global using static ns1; }
                Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using static ns1;").WithLocation(1, 16),
                // (1,36): error CS0246: The type or namespace name 'ns1' could not be found (are you missing a using directive or an assembly reference?)
                // namespace ns { global using static ns1; }
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ns1").WithArguments("ns1").WithLocation(1, 36));
 
            UsingTree(test, TestOptions.Regular9);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.NamespaceDeclaration);
                {
                    N(SyntaxKind.NamespaceKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns");
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.UsingDirective);
                    {
                        N(SyntaxKind.GlobalKeyword);
                        N(SyntaxKind.UsingKeyword);
                        N(SyntaxKind.StaticKeyword);
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "ns1");
                        }
                        N(SyntaxKind.SemicolonToken);
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_09()
        {
            var test = "global using alias = ns1;";
 
            UsingTree(test, TestOptions.RegularPreview);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.NameEquals);
                    {
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "alias");
                        }
                        N(SyntaxKind.EqualsToken);
                    }
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_10()
        {
            var test = "global using alias = ns1;";
 
            CreateCompilation(test, parseOptions: TestOptions.Regular9).VerifyDiagnostics(
                // (1,1): error CS8773: Feature 'global using directive' is not available in C# 9.0. Please use language version 10.0 or greater.
                // global using alias = ns1;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "global").WithArguments("global using directive", "10.0").WithLocation(1, 1),
                // (1,1): hidden CS8019: Unnecessary using directive.
                // global using alias = ns1;
                Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using alias = ns1;").WithLocation(1, 1),
                // (1,14): warning CS8981: The type name 'alias' only contains lower-cased ascii characters. Such names may become reserved for the language.
                // global using alias = ns1;
                Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "alias").WithArguments("alias").WithLocation(1, 14),
                // (1,22): error CS0246: The type or namespace name 'ns1' could not be found (are you missing a using directive or an assembly reference?)
                // global using alias = ns1;
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ns1").WithArguments("ns1").WithLocation(1, 22));
 
            UsingTree(test, TestOptions.Regular9);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.NameEquals);
                    {
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "alias");
                        }
                        N(SyntaxKind.EqualsToken);
                    }
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_11()
        {
            var test = "namespace ns { global using alias = ns1; }";
 
            UsingTree(test, TestOptions.RegularPreview);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.NamespaceDeclaration);
                {
                    N(SyntaxKind.NamespaceKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns");
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.UsingDirective);
                    {
                        N(SyntaxKind.GlobalKeyword);
                        N(SyntaxKind.UsingKeyword);
                        N(SyntaxKind.NameEquals);
                        {
                            N(SyntaxKind.IdentifierName);
                            {
                                N(SyntaxKind.IdentifierToken, "alias");
                            }
                            N(SyntaxKind.EqualsToken);
                        }
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "ns1");
                        }
                        N(SyntaxKind.SemicolonToken);
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_12()
        {
            var test = "namespace ns { global using alias = ns1; }";
 
            CreateCompilation(test, parseOptions: TestOptions.Regular9).VerifyDiagnostics(
                // (1,16): error CS8914: A global using directive cannot be used in a namespace declaration.
                // namespace ns { global using alias = ns1; }
                Diagnostic(ErrorCode.ERR_GlobalUsingInNamespace, "global").WithLocation(1, 16),
                // (1,16): error CS8773: Feature 'global using directive' is not available in C# 9.0. Please use language version 10.0 or greater.
                // namespace ns { global using alias = ns1; }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "global").WithArguments("global using directive", "10.0").WithLocation(1, 16),
                // (1,16): hidden CS8019: Unnecessary using directive.
                // namespace ns { global using alias = ns1; }
                Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using alias = ns1;").WithLocation(1, 16),
                // (1,29): warning CS8981: The type name 'alias' only contains lower-cased ascii characters. Such names may become reserved for the language.
                // namespace ns { global using alias = ns1; }
                Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "alias").WithArguments("alias").WithLocation(1, 29),
                // (1,37): error CS0246: The type or namespace name 'ns1' could not be found (are you missing a using directive or an assembly reference?)
                // namespace ns { global using alias = ns1; }
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ns1").WithArguments("ns1").WithLocation(1, 37));
 
            UsingTree(test, TestOptions.Regular9);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.NamespaceDeclaration);
                {
                    N(SyntaxKind.NamespaceKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns");
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.UsingDirective);
                    {
                        N(SyntaxKind.GlobalKeyword);
                        N(SyntaxKind.UsingKeyword);
                        N(SyntaxKind.NameEquals);
                        {
                            N(SyntaxKind.IdentifierName);
                            {
                                N(SyntaxKind.IdentifierToken, "alias");
                            }
                            N(SyntaxKind.EqualsToken);
                        }
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "ns1");
                        }
                        N(SyntaxKind.SemicolonToken);
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_13()
        {
            var test = @"
namespace ns {}
global using ns1;
";
 
            UsingTree(test, TestOptions.RegularPreview,
                // (3,1): error CS1529: A using clause must precede all other elements defined in the namespace except extern alias declarations
                // global using ns1;
                Diagnostic(ErrorCode.ERR_UsingAfterElements, "global using ns1;").WithLocation(3, 1)
                );
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.NamespaceDeclaration);
                {
                    N(SyntaxKind.NamespaceKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns");
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_14()
        {
            var test = @"
global using ns1;
extern alias a;
";
 
            UsingTree(test, TestOptions.RegularPreview,
                // (3,1): error CS0439: An extern alias declaration must precede all other elements defined in the namespace
                // extern alias a;
                Diagnostic(ErrorCode.ERR_ExternAfterElements, "extern").WithLocation(3, 1)
                );
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_15()
        {
            var test = @"
namespace ns2
{
    namespace ns {}
    global using ns1;
}
";
 
            UsingTree(test, TestOptions.RegularPreview,
                // (5,5): error CS1529: A using clause must precede all other elements defined in the namespace except extern alias declarations
                //     global using ns1;
                Diagnostic(ErrorCode.ERR_UsingAfterElements, "global using ns1;").WithLocation(5, 5)
                );
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.NamespaceDeclaration);
                {
                    N(SyntaxKind.NamespaceKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns2");
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.NamespaceDeclaration);
                    {
                        N(SyntaxKind.NamespaceKeyword);
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "ns");
                        }
                        N(SyntaxKind.OpenBraceToken);
                        N(SyntaxKind.CloseBraceToken);
                    }
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_16()
        {
            var test = @"
global using ns1;
namespace ns {}
";
 
            UsingTree(test, TestOptions.RegularPreview);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.NamespaceDeclaration);
                {
                    N(SyntaxKind.NamespaceKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns");
                    }
                    N(SyntaxKind.OpenBraceToken);
                    N(SyntaxKind.CloseBraceToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void UsingDirective_01()
        {
            var test = "d using ns1;";
 
            UsingTree(test, TestOptions.Regular,
                // (1,1): error CS0116: A namespace cannot directly contain members such as fields or methods
                // d using ns1;
                Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "d").WithLocation(1, 1)
                );
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_17()
        {
            var test = "d global using ns1;";
 
            UsingTree(test, TestOptions.RegularPreview,
                // (1,1): error CS0116: A namespace cannot directly contain members such as fields or methods
                // d global using ns1;
                Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "d").WithLocation(1, 1)
                );
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void UsingDirective_02()
        {
            var test = "using ns1; p using ns2;";
 
            UsingTree(test, TestOptions.Regular,
                // (1,12): error CS0116: A namespace cannot directly contain members such as fields or methods
                // using ns1; p using ns2;
                Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "p").WithLocation(1, 12)
                );
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns2");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_18()
        {
            var test = "global using ns1; p global using ns2;";
 
            UsingTree(test, TestOptions.RegularPreview,
                // (1,19): error CS0116: A namespace cannot directly contain members such as fields or methods
                // global using ns1; p global using ns2;
                Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "p").WithLocation(1, 19)
                );
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns2");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_19()
        {
            var test = @"
M();
global using ns1;
";
 
            UsingTree(test, TestOptions.RegularPreview,
                // (3,1): error CS1529: A using clause must precede all other elements defined in the namespace except extern alias declarations
                // global using ns1;
                Diagnostic(ErrorCode.ERR_UsingAfterElements, "global using ns1;").WithLocation(3, 1)
                );
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.GlobalStatement);
                {
                    N(SyntaxKind.ExpressionStatement);
                    {
                        N(SyntaxKind.InvocationExpression);
                        {
                            N(SyntaxKind.IdentifierName);
                            {
                                N(SyntaxKind.IdentifierToken, "M");
                            }
                            N(SyntaxKind.ArgumentList);
                            {
                                N(SyntaxKind.OpenParenToken);
                                N(SyntaxKind.CloseParenToken);
                            }
                        }
                        N(SyntaxKind.SemicolonToken);
                    }
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_20()
        {
            var test = @"
global using ns1;
using ns2;
M();
";
 
            UsingTree(test, TestOptions.RegularPreview);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns2");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.GlobalStatement);
                {
                    N(SyntaxKind.ExpressionStatement);
                    {
                        N(SyntaxKind.InvocationExpression);
                        {
                            N(SyntaxKind.IdentifierName);
                            {
                                N(SyntaxKind.IdentifierToken, "M");
                            }
                            N(SyntaxKind.ArgumentList);
                            {
                                N(SyntaxKind.OpenParenToken);
                                N(SyntaxKind.CloseParenToken);
                            }
                        }
                        N(SyntaxKind.SemicolonToken);
                    }
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_21()
        {
            var test = @"
global using alias1 = ns1;
using alias2 = ns2;
M();
";
 
            UsingTree(test, TestOptions.RegularPreview);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.NameEquals);
                    {
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "alias1");
                        }
                        N(SyntaxKind.EqualsToken);
                    }
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.NameEquals);
                    {
                        N(SyntaxKind.IdentifierName);
                        {
                            N(SyntaxKind.IdentifierToken, "alias2");
                        }
                        N(SyntaxKind.EqualsToken);
                    }
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns2");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.GlobalStatement);
                {
                    N(SyntaxKind.ExpressionStatement);
                    {
                        N(SyntaxKind.InvocationExpression);
                        {
                            N(SyntaxKind.IdentifierName);
                            {
                                N(SyntaxKind.IdentifierToken, "M");
                            }
                            N(SyntaxKind.ArgumentList);
                            {
                                N(SyntaxKind.OpenParenToken);
                                N(SyntaxKind.CloseParenToken);
                            }
                        }
                        N(SyntaxKind.SemicolonToken);
                    }
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
 
        [Fact]
        public void GlobalUsingDirective_22()
        {
            var test = @"
global using static ns1;
using static ns2;
M();
";
 
            UsingTree(test, TestOptions.RegularPreview);
 
            N(SyntaxKind.CompilationUnit);
            {
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.GlobalKeyword);
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.StaticKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns1");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.UsingDirective);
                {
                    N(SyntaxKind.UsingKeyword);
                    N(SyntaxKind.StaticKeyword);
                    N(SyntaxKind.IdentifierName);
                    {
                        N(SyntaxKind.IdentifierToken, "ns2");
                    }
                    N(SyntaxKind.SemicolonToken);
                }
                N(SyntaxKind.GlobalStatement);
                {
                    N(SyntaxKind.ExpressionStatement);
                    {
                        N(SyntaxKind.InvocationExpression);
                        {
                            N(SyntaxKind.IdentifierName);
                            {
                                N(SyntaxKind.IdentifierToken, "M");
                            }
                            N(SyntaxKind.ArgumentList);
                            {
                                N(SyntaxKind.OpenParenToken);
                                N(SyntaxKind.CloseParenToken);
                            }
                        }
                        N(SyntaxKind.SemicolonToken);
                    }
                }
                N(SyntaxKind.EndOfFileToken);
            }
            EOF();
        }
    }
}