File: Completion\CompletionProviders\OperatorCompletionProviderTests.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;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Completion.Providers;
using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders;
 
[Trait(Traits.Feature, Traits.Features.Completion)]
public class OperatorCompletionProviderTests : AbstractCSharpCompletionProviderTests
{
    internal override Type GetCompletionProviderType()
        => typeof(UnnamedSymbolCompletionProvider);
 
    // The suggestion is e.g. "+". If the user actually types "+" the completion list is closed. Operators therefore do not support partially written items.
    protected override string? ItemPartiallyWritten(string? expectedItemOrNull) => "";
 
    public static IEnumerable<object[]> BinaryArithmeticAndLogicalOperators()
    {
        yield return new[] { "+" };
        yield return new[] { "&" };
        yield return new[] { "|" };
        yield return new[] { "/" };
        yield return new[] { "^" };
        yield return new[] { "%" };
        yield return new[] { "*" };
        yield return new[] { ">>" };
        yield return new[] { ">>>" };
        yield return new[] { "<<" };
        yield return new[] { "-" };
    }
 
    public static IEnumerable<object[]> BinaryEqualityAndRelationalOperators()
    {
        yield return new[] { "==" };
        yield return new[] { ">" };
        yield return new[] { ">=" };
        yield return new[] { "!=" };
        yield return new[] { "<" };
        yield return new[] { "<=" };
    }
 
    public static IEnumerable<object[]> PostfixOperators()
    {
        yield return new[] { "++" };
        yield return new[] { "--" };
    }
 
    public static IEnumerable<object[]> PrefixOperators()
    {
        yield return new[] { "!" };
        yield return new[] { "~" };
        yield return new[] { "-" };
        yield return new[] { "+" };
    }
 
    public static IEnumerable<object[]> BinaryOperators()
        => BinaryArithmeticAndLogicalOperators().Union(BinaryEqualityAndRelationalOperators());
 
    public static IEnumerable<object[]> UnaryOperators()
        => PostfixOperators().Union(PrefixOperators());
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorIsNotOfferedAfterNumberLiteral()
    {
        // User may want to type a floating point literal.
        await VerifyNoItemsExistAsync("""
            public class C
            {
                public static C operator +(C a, C b) => default;
            }
 
            public class Program
            {
                public static void Main()
                {
                    1.$$
                }
            }
            """, SourceCodeKind.Regular);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorIsSuggestedAfterDot()
    {
        await VerifyItemExistsAsync("""
            public class C
            {
                public static C operator +(C a, C b) => default;
            }
 
            public class Program
            {
                public static void Main()
                {
                    var c = new C();
                    c.$$;
                }
            }
            """, "+", inlineDescription: "x + y", glyph: (int)Glyph.Operator, matchingFilters: [FilterSet.OperatorFilter]);
    }
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    [InlineData("c.$$", true)]
    [InlineData("c.$$;", true)]
    [InlineData("c.a$$", true)]
    [InlineData("c.ab$$", true)]
    [InlineData("c.abc$$", true)]
    [InlineData("c.abcd$$", true)]
    [InlineData("c. a$$", true)]
    [InlineData("c.$$a", true)]
    [InlineData("c.$$ a", true)]
    [InlineData("c?.$$", true)]
    public async Task OperatorSuggestionOnPartiallyWrittenMember(string expression, bool isOffered)
    {
        var verifyAction = isOffered
            ? new Func<string, Task>(markup => VerifyItemExistsAsync(markup, "+", inlineDescription: "x + y"))
            : new Func<string, Task>(markup => VerifyNoItemsExistAsync(markup));
        await verifyAction(@$"
public class C
{{
    public static C operator +(C a, C b) => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        {expression}
    }}
}}
");
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorIsNotSuggestedOnStaticAccess()
    {
        await VerifyNoItemsExistAsync("""
            public class C
            {
                public static C operator +(C a, C b) => default;
            }
 
            public class Program
            {
                public static void Main()
                {
                    C.$$
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorIsNotSuggestedInNameoOfContext()
    {
        await VerifyNoItemsExistAsync("""
            public class C
            {
                public static C operator +(C a, C b) => default;
            }
 
            public class Program
            {
                public static void Main()
                {
                    var c = new C();
                    var name = nameof(c.$$
                }
            }
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorsAreSortedByImporttanceAndGroupedByTopic()
    {
        var items = await GetCompletionItemsAsync("""
            public class C
            {
                public static C operator +(C a, C b) => null;
                public static C operator -(C a, C b) => null;
                public static C operator *(C a, C b) => null;
                public static C operator /(C a, C b) => null;
                public static C operator %(C a, C b) => null;
                public static bool operator ==(C a, C b) => true;
                public static bool operator !=(C a, C b) => false;
                public static bool operator <(C a, C b) => true;
                public static bool operator >(C a, C b) => false;
                public static bool operator <=(C a, C b) => true;
                public static bool operator >=(C a, C b) => false;
                public static C operator +(C a) => null;
                public static C operator -(C a) => null;
                public static C operator ++(C a) => null;
                public static C operator --(C a) => null;
                public static bool operator true(C w) => true;
                public static bool operator false(C w) => false;
                public static bool operator &(C a, C b) => true;
                public static bool operator |(C a, C b) => true;
                public static C operator !(C a) => null;
                public static C operator ^(C a, C b) => null;
                public static C operator <<(C a, int b) => null;
                public static C operator >>(C a, int b) => null;
                public static C operator >>>(C a, int b) => null;
                public static C operator ~(C a) => null;
            }
 
            public class Program
            {
                public static void Main()
                {
                    var c = new C();
                    c.$$;
                }
            }
            """, SourceCodeKind.Regular);
        // true and false operators are not listed
        Assert.Collection(items,
            i => Assert.Equal("==", i.DisplayText),
            i => Assert.Equal("!=", i.DisplayText),
            i => Assert.Equal(">", i.DisplayText),
            i => Assert.Equal(">=", i.DisplayText),
            i => Assert.Equal("<", i.DisplayText),
            i => Assert.Equal("<=", i.DisplayText),
            i => Assert.Equal("!", i.DisplayText),
            i => Assert.Equal("+", i.DisplayText), // Addition a+b
            i => Assert.Equal("-", i.DisplayText), // Subtraction a-b
            i => Assert.Equal("*", i.DisplayText),
            i => Assert.Equal("/", i.DisplayText),
            i => Assert.Equal("%", i.DisplayText),
            i => Assert.Equal("++", i.DisplayText),
            i => Assert.Equal("--", i.DisplayText),
            i => Assert.Equal("+", i.DisplayText), // Unary plus +a
            i => Assert.Equal("-", i.DisplayText), // Unary minus -a
            i => Assert.Equal("&", i.DisplayText),
            i => Assert.Equal("|", i.DisplayText),
            i => Assert.Equal("^", i.DisplayText),
            i => Assert.Equal("<<", i.DisplayText),
            i => Assert.Equal(">>", i.DisplayText),
            i => Assert.Equal(">>>", i.DisplayText),
            i => Assert.Equal("~", i.DisplayText)
        );
    }
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    [InlineData("bool", 0)]
    [InlineData("System.Boolean", 0)]
    [InlineData("char", 0)]
    [InlineData("System.Char", 0)]
    [InlineData("string", 0)]
    [InlineData("System.String", 0)]
    [InlineData("sbyte", 0)]
    [InlineData("System.SByte", 0)]
    [InlineData("byte", 0)]
    [InlineData("System.Byte", 0)]
    [InlineData("short", 0)]
    [InlineData("System.Int16", 0)]
    [InlineData("ushort", 0)]
    [InlineData("System.UInt16", 0)]
    [InlineData("int", 0)]
    [InlineData("System.Int32", 0)]
    [InlineData("uint", 0)]
    [InlineData("System.UInt32", 0)]
    [InlineData("long", 0)]
    [InlineData("System.Int64", 0)]
    [InlineData("ulong", 0)]
    [InlineData("System.UInt64", 0)]
    [InlineData("float", 0)]
    [InlineData("System.Single", 0)]
    [InlineData("double", 0)]
    [InlineData("System.Double", 0)]
    [InlineData("decimal", 0)]
    [InlineData("System.Decimal", 0)]
    [InlineData("nint", 0)]
    [InlineData("System.IntPtr", 0)]
    [InlineData("nuint", 0)]
    [InlineData("System.UIntPtr", 0)]
    [InlineData("System.DateTime", 8)]
    [InlineData("System.TimeSpan", 10)]
    [InlineData("System.DateTimeOffset", 8)]
    [InlineData("System.Guid", 2)]
    public async Task OperatorSuggestionForSpecialTypes(string specialType, int numberOfSuggestions)
    {
        var completionItems = await GetCompletionItemsAsync(@$"
public class Program
{{
    public static void Main()
    {{
        {specialType} i = default({specialType});
        i.$$
    }}
}}
", SourceCodeKind.Regular);
        Assert.Equal(
            numberOfSuggestions,
            completionItems.Count(c => c.GetProperty(UnnamedSymbolCompletionProvider.KindName) == UnnamedSymbolCompletionProvider.OperatorKindName));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorNoSuggestionForTrueAndFalse()
    {
        await VerifyNoItemsExistAsync("""
            public class C
            {
                public static bool operator true(C _) => true;
                public static bool operator false(C _) => true;
            }
 
            public class Program
            {
                public static void Main()
                {
                    var c = new C();
                    c.$$
                }
            }
            """);
    }
 
    [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    [MemberData(nameof(BinaryOperators))]
    public async Task OperatorBinaryIsCompleted(string binaryOperator)
    {
        await VerifyCustomCommitProviderAsync($@"
public class C
{{
    public static C operator {binaryOperator}(C a, C b) => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        c.$$
    }}
}}
", binaryOperator, @$"
public class C
{{
    public static C operator {binaryOperator}(C a, C b) => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        c {binaryOperator} $$
    }}
}}
");
    }
 
    [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    [MemberData(nameof(PostfixOperators))]
    public async Task OperatorPostfixIsCompleted(string postfixOperator)
    {
        await VerifyCustomCommitProviderAsync($@"
public class C
{{
    public static C operator {postfixOperator}(C _) => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        c.$$
    }}
}}
", postfixOperator, @$"
public class C
{{
    public static C operator {postfixOperator}(C _) => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        c{postfixOperator} $$
    }}
}}
");
    }
 
    [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    [MemberData(nameof(PrefixOperators))]
    public async Task OperatorPrefixIsCompleted(string prefixOperator)
    {
        await VerifyCustomCommitProviderAsync($@"
public class C
{{
    public static C operator {prefixOperator}(C _) => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        c.$$
    }}
}}
", prefixOperator, @$"
public class C
{{
    public static C operator {prefixOperator}(C _) => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        {prefixOperator}c$$
    }}
}}
");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorDuplicateOperatorsAreListedBoth()
    {
        var items = await GetCompletionItemsAsync($@"
public class C
{{
    public static C operator +(C a, C b) => default;
    public static C operator +(C _) => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        c.$$
    }}
}}
", SourceCodeKind.Regular);
        Assert.Collection(items,
            i =>
            {
                Assert.Equal("+", i.DisplayText);
                Assert.EndsWith("002_007", i.SortText); // Addition
            },
            i =>
            {
                Assert.Equal("+", i.DisplayText);
                Assert.EndsWith("002_014", i.SortText); // unary plus
            });
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorDuplicateOperatorsAreCompleted()
    {
        await VerifyCustomCommitProviderAsync($@"
public class C
{{
    public static C operator +(C a, C b) => default;
    public static C operator +(C _) => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        c.$$
    }}
}}
", "+", @$"
public class C
{{
    public static C operator +(C a, C b) => default;
    public static C operator +(C _) => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        c + $$
    }}
}}
");
    }
 
    [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    [InlineData("c.$$",
                "c + $$")]
    [InlineData("c. $$",
                "c + $$ ")]
    [InlineData("c .$$",
                "c  + $$")]
    [InlineData("c.$$;",
                "c + $$;")]
    [InlineData("c.abc$$",
                "c + $$")]
    [InlineData("c.a$$bc",
                "c + $$")]
    [InlineData("c.$$abc",
                "c + $$abc")]
    [InlineData("c.$$ abc",
                "c + $$ abc")]
    [InlineData("(true ? c : c).$$",
                "(true ? c : c) + $$")]
    [InlineData("c?.$$",
                "c + $$")]
    [InlineData("(true ? c : c)?.$$",
                "(true ? c : c) + $$")]
    [InlineData("c? .$$",
                "c + $$")]
    [InlineData("c ? .$$",
                "c  + $$")]
    [InlineData("c?.CProp.$$",
                "c?.CProp + $$")]
    [InlineData("c?.CProp?.$$",
                "c?.CProp + $$")]
    [InlineData("c.CProp.CProp?.$$",
                "c.CProp.CProp + $$")]
    [InlineData("c?.CProp.CProp.$$",
                "c?.CProp.CProp + $$")]
    [InlineData("c[0].$$",
                "c[0] + $$")]
    [InlineData("c[0]?.$$",
                "c[0] + $$")]
    [InlineData("c?.CProp[0].$$",
                "c?.CProp[0] + $$")]
    [InlineData("c.CProp[0].CProp?.$$",
                "c.CProp[0].CProp + $$")]
    public async Task OperatorInfixOfferingsAndCompletions(string expression, string completion)
    {
        await VerifyCustomCommitProviderAsync($@"
public class C
{{
    public static C operator +(C a, C b) => default;
    public C CProp {{ get; }}
    public C this[int _] => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        {expression}
    }}
}}
", "+", @$"
public class C
{{
    public static C operator +(C a, C b) => default;
    public C CProp {{ get; }}
    public C this[int _] => default;
}}
 
public class Program
{{
    public static void Main()
    {{
        var c = new C();
        {completion}
    }}
}}
");
    }
 
    [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    [MemberData(nameof(UnaryOperators))]
    public async Task OperatorLiftingUnary(string operatorSign)
    {
        const string template = """
            public struct S
            {{
                {0} => default;
            }}
 
            public class Program
            {{
                public static void Main()
                {{
                    S? s = null;
                    s.$$
                }}
            }}
            """;
        var inlineDescription = operatorSign.Length == 1
            ? $"{operatorSign}x"
            : $"x{operatorSign}";
        await VerifyItemExistsAsync(string.Format(template, $"public static S operator {operatorSign}(S _)"), operatorSign, inlineDescription: inlineDescription);
        await VerifyItemExistsAsync(string.Format(template, $"public static bool operator {operatorSign}(S _)"), operatorSign, inlineDescription: inlineDescription);
        await VerifyNoItemsExistAsync(string.Format(template, $"public static object operator {operatorSign}(S _)"));
        await VerifyNoItemsExistAsync(string.Format(template, $"public static S operator {operatorSign}(S a, S b, S c)"));
    }
 
    [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    [MemberData(nameof(BinaryArithmeticAndLogicalOperators))]
    public async Task OperatorLiftingBinary(string operatorSign)
    {
        const string template = """
            public struct S
            {{
                {0} => default;
            }}
 
            public class Program
            {{
                public static void Main()
                {{
                    S? s = null;
                    s.$$
                }}
            }}
            """;
        var inlineDescription = $"x {operatorSign} y";
        await VerifyItemExistsAsync(string.Format(template, $"public static S operator {operatorSign}(S a, S b)"), operatorSign, inlineDescription: inlineDescription);
        await VerifyItemExistsAsync(string.Format(template, $"public static int operator {operatorSign}(S a, S b)"), operatorSign, inlineDescription: inlineDescription);
        await VerifyNoItemsExistAsync(string.Format(template, $"public static object operator {operatorSign}(S a, S b)"));
        await VerifyNoItemsExistAsync(string.Format(template, $"public static S operator {operatorSign}(S a, object b)"));
        await VerifyNoItemsExistAsync(string.Format(template, $"public static S operator {operatorSign}(S a, S b, S c)"));
    }
 
    [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    [MemberData(nameof(BinaryEqualityAndRelationalOperators))]
    public async Task OperatorLiftingEqualityRelational(string operatorSign)
    {
        const string template = """
            public struct S
            {{
                {0} => default;
            }}
 
            public class Program
            {{
                public static void Main()
                {{
                    S? s = null;
                    s.$$
                }}
            }}
            """;
        await VerifyItemExistsAsync(string.Format(template, $"public static bool operator {operatorSign}(S a, S b)"), operatorSign, inlineDescription: $"x {operatorSign} y");
        await VerifyNoItemsExistAsync(string.Format(template, $"public static int operator {operatorSign}(S a, S b)"));
        await VerifyNoItemsExistAsync(string.Format(template, $"public static bool operator {operatorSign}(S a, S b, S c)"));
        await VerifyNoItemsExistAsync(string.Format(template, $"public static bool operator {operatorSign}(S a, object b)"));
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorLiftingIsApplied()
    {
        await VerifyCustomCommitProviderAsync("""
            public struct S
            {
                public static bool operator ==(S a, S b) => default;
            }
 
            public class Program
            {
                public static void Main()
                {
                    S? s = null;
                    s.$$
                }
            }
            """, "==", """
            public struct S
            {
                public static bool operator ==(S a, S b) => default;
            }
 
            public class Program
            {
                public static void Main()
                {
                    S? s = null;
                    s == $$
                }
            }
            """);
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorOfBaseTypeIsSuggested()
    {
        await VerifyItemExistsAsync("""
            public class Base {
                public static int operator +(Base b, int a)=>0;
            }
            public class Derived: Base
            {
            }
 
            public class Program
            {
                public static void Main()
                {
                    var d = new Derived();
                    d.$$
                }
            }
            """, "+", inlineDescription: "x + y", glyph: (int)Glyph.Operator, matchingFilters: [FilterSet.OperatorFilter]);
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorForRecordsAreSuggested()
    {
        await VerifyItemExistsAsync("""
            public record R {
            }
 
            public class Program
            {
                public static void Main()
                {
                    var r = new R();
                    r.$$
                }
            }
            """, "==", inlineDescription: "x == y", glyph: (int)Glyph.Operator, matchingFilters: [FilterSet.OperatorFilter]);
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task TestEditorBrowsableOnOperatorIsRespected_EditorBrowsableStateNever()
    {
        var markup = """
            namespace N
            {
                public class Program
                {
                    public static void Main()
                    {
                        var c = new C();
                        c.$$
                    }
                }
            }
            """;
        var referencedCode = """
            using System.ComponentModel;
 
            namespace N
            {
                public class C
                {
                    [EditorBrowsable(EditorBrowsableState.Never)]
                    public static C operator -(C a, C b) => default;
                }
            }
            """;
 
        await VerifyItemInEditorBrowsableContextsAsync(
            markup: markup,
            referencedCode: referencedCode,
            item: "-",
            expectedSymbolsSameSolution: 1,
            expectedSymbolsMetadataReference: 0,
            sourceLanguage: LanguageNames.CSharp,
            referencedLanguage: LanguageNames.CSharp);
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task TestEditorBrowsableOnOperatorIsRespected_EditorBrowsableStateAdvanced()
    {
        var markup = """
            namespace N
            {
                public class Program
                {
                    public static void Main()
                    {
                        var c = new C();
                        c.$$
                    }
                }
            }
            """;
        var referencedCode = """
            using System.ComponentModel;
 
            namespace N
            {
                public class C
                {
                    [EditorBrowsable(EditorBrowsableState.Advanced)]
                    public static C operator -(C a, C b) => default;
                }
            }
            """;
 
        HideAdvancedMembers = false;
 
        await VerifyItemInEditorBrowsableContextsAsync(
            markup: markup,
            referencedCode: referencedCode,
            item: "-",
            expectedSymbolsSameSolution: 1,
            expectedSymbolsMetadataReference: 1,
            sourceLanguage: LanguageNames.CSharp,
            referencedLanguage: LanguageNames.CSharp);
 
        HideAdvancedMembers = true;
 
        await VerifyItemInEditorBrowsableContextsAsync(
            markup: markup,
            referencedCode: referencedCode,
            item: "-",
            expectedSymbolsSameSolution: 1,
            expectedSymbolsMetadataReference: 0,
            sourceLanguage: LanguageNames.CSharp,
            referencedLanguage: LanguageNames.CSharp);
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/47511")]
    public async Task OperatorBinaryNullForgivingHandling()
    {
        await VerifyCustomCommitProviderAsync("""
            #nullable enable
 
            public class C
            {
                public static C operator +(C a, C b) => default;
            }
 
            public class Program
            {
                public static void Main()
                {
                    C? c = null;
                    var _ = c!.$$
                }
            }
            """, "+", """
            #nullable enable
 
            public class C
            {
                public static C operator +(C a, C b) => default;
            }
 
            public class Program
            {
                public static void Main()
                {
                    C? c = null;
                    var _ = c! + $$
                }
            }
            """);
    }
}