// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Remote.Testing;
using Microsoft.CodeAnalysis.Test.Utilities.EmbeddedLanguages;
using Roslyn.Test.Utilities;
using Xunit;
using static Microsoft.CodeAnalysis.Editor.UnitTests.Classification.FormattedClassifications;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Classification
{
    public partial class SemanticClassifierTests
    {
        [Theory, CombinatorialData]
        public async Task TestRegex1(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = new Regex(@"$(\a\t\u0020)|[^\p{Lu}-a\w\sa-z-[m-p]]+?(?#comment)|(\b\G\z)|(?<name>sub){0,5}?^");
                    }
                }
                """,
                testHost,
                Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Class("Regex"),
                Regex.Anchor("$"),
                Regex.Grouping("("),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("t"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("u"),
                Regex.OtherEscape("0020"),
                Regex.Grouping(")"),
                Regex.Alternation("|"),
                Regex.CharacterClass("["),
                Regex.CharacterClass("^"),
                Regex.CharacterClass("\\"),
                Regex.CharacterClass("p"),
                Regex.CharacterClass("{"),
                Regex.CharacterClass("Lu"),
                Regex.CharacterClass("}"),
                Regex.Text("-a"),
                Regex.CharacterClass("\\"),
                Regex.CharacterClass("w"),
                Regex.CharacterClass("\\"),
                Regex.CharacterClass("s"),
                Regex.Text("a"),
                Regex.CharacterClass("-"),
                Regex.Text("z"),
                Regex.CharacterClass("-"),
                Regex.CharacterClass("["),
                Regex.Text("m"),
                Regex.CharacterClass("-"),
                Regex.Text("p"),
                Regex.CharacterClass("]"),
                Regex.CharacterClass("]"),
                Regex.Quantifier("+"),
                Regex.Quantifier("?"),
                Regex.Comment("(?#comment)"),
                Regex.Alternation("|"),
                Regex.Grouping("("),
                Regex.Anchor("\\"),
                Regex.Anchor("b"),
                Regex.Anchor("\\"),
                Regex.Anchor("G"),
                Regex.Anchor("\\"),
                Regex.Anchor("z"),
                Regex.Grouping(")"),
                Regex.Alternation("|"),
                Regex.Grouping("("),
                Regex.Grouping("?"),
                Regex.Grouping("<"),
                Regex.Grouping("name"),
                Regex.Grouping(">"),
                Regex.Text("sub"),
                Regex.Grouping(")"),
                Regex.Quantifier("{"),
                Regex.Quantifier("0"),
                Regex.Quantifier(","),
                Regex.Quantifier("5"),
                Regex.Quantifier("}"),
                Regex.Quantifier("?"),
                Regex.Anchor("^"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex2(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        // language=regex
                        var r = @"$(\a\t\u0020)|[^\p{Lu}-a\w\sa-z-[m-p]]+?(?#comment)|(\b\G\z)|(?<name>sub){0,5}?^";
                    }
                }
                """,
                testHost,
                Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.Grouping("("),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("t"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("u"),
                Regex.OtherEscape("0020"),
                Regex.Grouping(")"),
                Regex.Alternation("|"),
                Regex.CharacterClass("["),
                Regex.CharacterClass("^"),
                Regex.CharacterClass("\\"),
                Regex.CharacterClass("p"),
                Regex.CharacterClass("{"),
                Regex.CharacterClass("Lu"),
                Regex.CharacterClass("}"),
                Regex.Text("-a"),
                Regex.CharacterClass("\\"),
                Regex.CharacterClass("w"),
                Regex.CharacterClass("\\"),
                Regex.CharacterClass("s"),
                Regex.Text("a"),
                Regex.CharacterClass("-"),
                Regex.Text("z"),
                Regex.CharacterClass("-"),
                Regex.CharacterClass("["),
                Regex.Text("m"),
                Regex.CharacterClass("-"),
                Regex.Text("p"),
                Regex.CharacterClass("]"),
                Regex.CharacterClass("]"),
                Regex.Quantifier("+"),
                Regex.Quantifier("?"),
                Regex.Comment("(?#comment)"),
                Regex.Alternation("|"),
                Regex.Grouping("("),
                Regex.Anchor("\\"),
                Regex.Anchor("b"),
                Regex.Anchor("\\"),
                Regex.Anchor("G"),
                Regex.Anchor("\\"),
                Regex.Anchor("z"),
                Regex.Grouping(")"),
                Regex.Alternation("|"),
                Regex.Grouping("("),
                Regex.Grouping("?"),
                Regex.Grouping("<"),
                Regex.Grouping("name"),
                Regex.Grouping(">"),
                Regex.Text("sub"),
                Regex.Grouping(")"),
                Regex.Quantifier("{"),
                Regex.Quantifier("0"),
                Regex.Quantifier(","),
                Regex.Quantifier("5"),
                Regex.Quantifier("}"),
                Regex.Quantifier("?"),
                Regex.Anchor("^"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex3(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* language=regex */@"$(\a\t\u0020\\)|[^\p{Lu}-a\w\sa-z-[m-p]]+?(?#comment)|(\b\G\z)|(?<name>sub){0,5}?^";
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.Grouping("("),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("t"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("u"),
                Regex.OtherEscape("0020"),
                Regex.SelfEscapedCharacter("\\"),
                Regex.SelfEscapedCharacter("\\"),
                Regex.Grouping(")"),
                Regex.Alternation("|"),
                Regex.CharacterClass("["),
                Regex.CharacterClass("^"),
                Regex.CharacterClass("\\"),
                Regex.CharacterClass("p"),
                Regex.CharacterClass("{"),
                Regex.CharacterClass("Lu"),
                Regex.CharacterClass("}"),
                Regex.Text("-a"),
                Regex.CharacterClass("\\"),
                Regex.CharacterClass("w"),
                Regex.CharacterClass("\\"),
                Regex.CharacterClass("s"),
                Regex.Text("a"),
                Regex.CharacterClass("-"),
                Regex.Text("z"),
                Regex.CharacterClass("-"),
                Regex.CharacterClass("["),
                Regex.Text("m"),
                Regex.CharacterClass("-"),
                Regex.Text("p"),
                Regex.CharacterClass("]"),
                Regex.CharacterClass("]"),
                Regex.Quantifier("+"),
                Regex.Quantifier("?"),
                Regex.Comment("(?#comment)"),
                Regex.Alternation("|"),
                Regex.Grouping("("),
                Regex.Anchor("\\"),
                Regex.Anchor("b"),
                Regex.Anchor("\\"),
                Regex.Anchor("G"),
                Regex.Anchor("\\"),
                Regex.Anchor("z"),
                Regex.Grouping(")"),
                Regex.Alternation("|"),
                Regex.Grouping("("),
                Regex.Grouping("?"),
                Regex.Grouping("<"),
                Regex.Grouping("name"),
                Regex.Grouping(">"),
                Regex.Text("sub"),
                Regex.Grouping(")"),
                Regex.Quantifier("{"),
                Regex.Quantifier("0"),
                Regex.Quantifier(","),
                Regex.Quantifier("5"),
                Regex.Quantifier("}"),
                Regex.Quantifier("?"),
                Regex.Anchor("^"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex4(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang=regex */@"$\a(?#comment)";
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex4_utf8_1(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang=regex */"$\\a(?#comment)";
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape(@"\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex4_utf8_2(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang=regex */@"$\a(?#comment)"u8;
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex5(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang=regexp */@"$\a(?#comment)";
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex6(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang=regexp */@"$\a(?#comment) # not end of line comment";
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"),
                Regex.Text(" # not end of line comment"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex7(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang=regexp,ignorepatternwhitespace */@"$\a(?#comment) # is end of line comment";
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"),
                Regex.Comment("# is end of line comment"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex8(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang = regexp , ignorepatternwhitespace */@"$\a(?#comment) # is end of line comment";
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"),
                Regex.Comment("# is end of line comment"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex9(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = new Regex(@"$\a(?#comment) # is end of line comment", RegexOptions.IgnorePatternWhitespace);
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Class("Regex"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"),
                Regex.Comment("# is end of line comment"),
                Enum("RegexOptions"),
                EnumMember("IgnorePatternWhitespace"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex10(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = new Regex(@"$\a(?#comment) # is not end of line comment");
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Class("Regex"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"),
                Regex.Text(" # is not end of line comment"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex10_utf8(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        // lang=regex
                        var r = @"$\a(?#comment) # is not end of line comment"u8;
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"),
                Regex.Text(" # is not end of line comment"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegex11(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    // language=regex
                    private static string myRegex = @"$(\a\t\u0020)";
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Regex.Anchor("$"),
                Regex.Grouping("("),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("t"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("u"),
                Regex.OtherEscape("0020"),
                Regex.Grouping(")"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexSingleLineRawStringLiteral(TestHost testHost)
        {
            await TestAsync(
                """"
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang=regex */ """$\a(?#comment)""";
                    }
                }
                """",
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexSingleLineRawStringLiteral_utf8(TestHost testHost)
        {
            await TestAsync(
                """"
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang=regex */ """$\a(?#comment)"""u8;
                    }
                }
                """",
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexMultiLineRawStringLiteral(TestHost testHost)
        {
            await TestAsync(
                """"
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang=regex */ """
                            $\a(?#comment)
                            """;
                    }
                }
                """",
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexMultiLineRawStringLiteral_utf8(TestHost testHost)
        {
            await TestAsync(
                """"
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = /* lang=regex */ """
                            $\a(?#comment)
                            """u8;
                    }
                }
                """",
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/47079")]
        [CombinatorialData]
        public async Task TestRegexWithSpecialCSharpCharLiterals(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    // the double-quote inside the string should not affect this being classified as a regex.
                    private Regex myRegex = new Regex(@"^ "" $";
                }
                """,
                testHost,
                Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Class("Regex"),
                Class("Regex"),
                Regex.Anchor("^"),
                Regex.Text(@" """" "),
                Regex.Anchor("$"));
        }

        [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/47079")]
        [CombinatorialData]
        public async Task TestRegexWithSpecialCSharpCharLiterals_utf8(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    // lang=regex
                    private string myRegex = @"^ "" $"u8;
                }
                """,
                testHost,
                Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Regex.Anchor("^"),
                Regex.Text(@" """" "),
                Regex.Anchor("$"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_Field(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    [StringSyntax(StringSyntaxAttribute.Regex)]
                    private string field;

                    void Goo()
                    {
                        [|this.field = @"$\a(?#comment)";|]
                    }
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Field("field"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_Field2(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    [StringSyntax(StringSyntaxAttribute.Regex)]
                    [|private string field = @"$\a(?#comment)";|]
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_Property(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    [StringSyntax(StringSyntaxAttribute.Regex)]
                    private string Prop { get; set; }

                    void Goo()
                    {
                        [|this.Prop = @"$\a(?#comment)";|]
                    }
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Property("Prop"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_Property2(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    [StringSyntax(StringSyntaxAttribute.Regex)]
                    [|private string Prop { get; set; } = @"$\a(?#comment)";|]
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_Argument(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    private void M([StringSyntax(StringSyntaxAttribute.Regex)] string p)
                    {
                    }

                    void Goo()
                    {
                        [|M(@"$\a(?#comment)");|]
                    }
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Method("M"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_ParamsArgument(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    private void M([StringSyntax(StringSyntaxAttribute.Regex)] params string[] p)
                    {
                    }

                    void Goo()
                    {
                        [|M(@"$\a(?#comment)");|]
                    }
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Method("M"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/64549")]
        [CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_ParamsArgument2(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    private void M([StringSyntax(StringSyntaxAttribute.Regex)] params string[] p)
                    {
                    }

                    void Goo()
                    {
                        [|M(@"$\a(?#comment)", @"$\a(?#comment)");|]
                    }
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Method("M"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_ArrayArgument(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    private void M([StringSyntax(StringSyntaxAttribute.Regex)] string[] p)
                    {
                    }

                    void Goo()
                    {
                        [|M(new string[] { @"$\a(?#comment)" });|]
                    }
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Method("M"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_ImplicitArrayArgument(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    private void M([StringSyntax(StringSyntaxAttribute.Regex)] string[] p)
                    {
                    }

                    void Goo()
                    {
                        [|M(new[] { @"$\a(?#comment)" });|]
                    }
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Method("M"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_CollectionArgument(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Collections.Generic;
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    private void M([StringSyntax(StringSyntaxAttribute.Regex)] List<string> p)
                    {
                    }

                    void Goo()
                    {
                        [|M(new List<string> { @"$\a(?#comment)" });|]
                    }
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Method("M"),
                Class("List"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_ImplicitCollectionArgument(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Collections.Generic;
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    private void M([StringSyntax(StringSyntaxAttribute.Regex)] List<string> p)
                    {
                    }

                    void Goo()
                    {
                        [|M(new() { @"$\a(?#comment)" });|]
                    }
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Method("M"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_Argument_Options(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                class Program
                {
                    private void M([StringSyntax(StringSyntaxAttribute.Regex)] string p, RegexOptions options)
                    {
                    }

                    void Goo()
                    {
                        [|M(@"$\a(?#comment) # is end of line comment", RegexOptions.IgnorePatternWhitespace);|]
                    }
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Method("M"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"),
                Regex.Comment("# is end of line comment"),
                Enum("RegexOptions"),
                EnumMember("IgnorePatternWhitespace"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_Attribute(TestHost testHost)
        {
            await TestAsync(
                """
                using System;
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                [AttributeUsage(AttributeTargets.Field)]
                class RegexTestAttribute : Attribute
                {
                    public RegexTestAttribute([StringSyntax(StringSyntaxAttribute.Regex)] string value) { }
                }

                class Program
                {
                    [|[RegexTest(@"$\a(?#comment)")]|]
                    private string field;
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Class("RegexTest"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        [WorkItem("https://github.com/dotnet/roslyn/issues/61947")]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_AttributeField(TestHost testHost)
        {
            await TestAsync(
                """
                using System;
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                [AttributeUsage(AttributeTargets.Field)]
                class RegexTestAttribute : Attribute
                {
                    public RegexTestAttribute() { }

                    [StringSyntax(StringSyntaxAttribute.Regex)]
                    public string value;
                }

                class Program
                {
                    [|[RegexTest(value = @"$\a(?#comment)")]|]
                    private string field;
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Class("RegexTest"),
                Field("value"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        [WorkItem("https://github.com/dotnet/roslyn/issues/61947")]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_AttributeProperty(TestHost testHost)
        {
            await TestAsync(
                """
                using System;
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                [AttributeUsage(AttributeTargets.Field)]
                class RegexTestAttribute : Attribute
                {
                    public RegexTestAttribute() { }

                    [StringSyntax(StringSyntaxAttribute.Regex)]
                    public string value { get; set; }
                }

                class Program
                {
                    [|[RegexTest(value = @"$\a(?#comment)")]|]
                    private string field;
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Class("RegexTest"),
                Property("value"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_ParamsAttribute(TestHost testHost)
        {
            await TestAsync(
                """
                using System;
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                [AttributeUsage(AttributeTargets.Field)]
                class RegexTestAttribute : Attribute
                {
                    public RegexTestAttribute([StringSyntax(StringSyntaxAttribute.Regex)] params string[] value) { }
                }

                class Program
                {
                    [|[RegexTest(@"$\a(?#comment)")]|]
                    private string field;
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Class("RegexTest"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_ArrayAttribute(TestHost testHost)
        {
            await TestAsync(
                """
                using System;
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                [AttributeUsage(AttributeTargets.Field)]
                class RegexTestAttribute : Attribute
                {
                    public RegexTestAttribute([StringSyntax(StringSyntaxAttribute.Regex)] string[] value) { }
                }

                class Program
                {
                    [|[RegexTest(new string[] { @"$\a(?#comment)" })]|]
                    private string field;
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Class("RegexTest"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestRegexOnApiWithStringSyntaxAttribute_ImplicitArrayAttribute(TestHost testHost)
        {
            await TestAsync(
                """
                using System;
                using System.Diagnostics.CodeAnalysis;
                using System.Text.RegularExpressions;

                [AttributeUsage(AttributeTargets.Field)]
                class RegexTestAttribute : Attribute
                {
                    public RegexTestAttribute([StringSyntax(StringSyntaxAttribute.Regex)] string[] value) { }
                }

                class Program
                {
                    [|[RegexTest(new[] { @"$\a(?#comment)" })]|]
                    private string field;
                }
                """ + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp,
                testHost,
                Class("RegexTest"),
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        public async Task TestIncompleteRegexLeadingToStringInsideSkippedTokensInsideADirective(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void M()
                    {
                        // not terminating this string caused us to eat up to the quote on the next line.
                        // we then treated #comment as a directive with a lot of skipped tokens on it, including
                        // a skipped token for ";
                        //
                        // Because it's a comment on a directive, special lexing rules apply (i.e. no escape
                        // characters are supposed, and we want our system to bail there and not try to validate
                        // it.
                        var r = new Regex(@"$;
                        var s = /* language=regex */ @"(?#comment)|(\b\G\z)|(?<name>sub){0,5}?^";
                    }
                }
                """,
                testHost, Namespace("System"),
                Namespace("Text"),
                Namespace("RegularExpressions"),
                Keyword("var"),
                Class("Regex"));
        }

        [Theory, CombinatorialData]
        [WorkItem("https://github.com/dotnet/roslyn/issues/61982")]
        public async Task TestRegexAmbiguity1(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = Regex.Match("", [|@"$\a(?#comment)"|]
                """,
                testHost,
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }

        [Theory, CombinatorialData]
        [WorkItem("https://github.com/dotnet/roslyn/issues/61982")]
        public async Task TestRegexAmbiguity2(TestHost testHost)
        {
            await TestAsync(
                """
                using System.Text.RegularExpressions;

                class Program
                {
                    void Goo()
                    {
                        var r = Regex.Match("", [|@"$\a(?#comment)"|],
                """,
                testHost,
                Regex.Anchor("$"),
                Regex.OtherEscape("\\"),
                Regex.OtherEscape("a"),
                Regex.Comment("(?#comment)"));
        }
    }
}
