File: Classification\SemanticClassifierTests_Regex.cs
Web Access
Project: src\src\EditorFeatures\CSharpTest\Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.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)"));
    }
 
    [Theory, CombinatorialData]
    public async Task TestRegexNotOnBinaryExpression(TestHost testHost)
    {
        await TestAsync(
            """
            using System.Text.RegularExpressions;
 
            class Program
            {
                void Goo()
                {
                    // language=regex
                    var r = @"[a-" + @"z]";
                }
            }
            """,
            testHost,
            Namespace("System"),
            Namespace("Text"),
            Namespace("RegularExpressions"),
            Keyword("var"));
    }
}