|
// 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.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.SimplifyInterpolation;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SimplifyInterpolation;
[Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyInterpolation)]
public partial class SimplifyInterpolationTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor
{
public SimplifyInterpolationTests(ITestOutputHelper logger)
: base(logger)
{
}
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (new CSharpSimplifyInterpolationDiagnosticAnalyzer(), new CSharpSimplifyInterpolationCodeFixProvider());
[Fact]
public async Task SubsequentUnnecessarySpansDoNotRepeatTheSmartTag()
{
var parameters = new TestParameters(retainNonFixableDiagnostics: true, includeDiagnosticsOutsideSelection: true);
using var workspace = CreateWorkspaceFromOptions("""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].ToString()|}{|Unnecessary:.PadLeft(|}3{|Unnecessary:)|}} suffix";
}
}
""", parameters);
var diagnostics = await GetDiagnosticsWorkerAsync(workspace, parameters);
Assert.Equal(
[
("IDE0071", DiagnosticSeverity.Info),
],
diagnostics.Select(d => (d.Descriptor.Id, d.Severity)));
}
[Fact]
public async Task ToStringWithNoParameter()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].ToString()|}} suffix";
}
}
""",
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithParameter()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(int someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].ToString("|}g{|Unnecessary:")|}} suffix";
}
}
""",
"""
class C
{
void M(int someValue)
{
_ = $"prefix {someValue:g} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithEscapeSequences()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(System.DateTime someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].ToString("|}\\d \"d\"{|Unnecessary:")|}} suffix";
}
}
""",
"""
class C
{
void M(System.DateTime someValue)
{
_ = $"prefix {someValue:\\d \"d\"} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithVerbatimEscapeSequencesInsideVerbatimInterpolatedString()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(System.DateTime someValue)
{
_ = $@"prefix {someValue{|Unnecessary:[||].ToString(@"|}\d ""d""{|Unnecessary:")|}} suffix";
}
}
""",
"""
class C
{
void M(System.DateTime someValue)
{
_ = $@"prefix {someValue:\d ""d""} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithVerbatimEscapeSequencesInsideNonVerbatimInterpolatedString()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(System.DateTime someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].ToString(@"|}\d ""d""{|Unnecessary:")|}} suffix";
}
}
""",
"""
class C
{
void M(System.DateTime someValue)
{
_ = $"prefix {someValue:\\d \"d\"} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithNonVerbatimEscapeSequencesInsideVerbatimInterpolatedString()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(System.DateTime someValue)
{
_ = $@"prefix {someValue{|Unnecessary:[||].ToString("|}\\d \"d\"{|Unnecessary:")|}} suffix";
}
}
""",
"""
class C
{
void M(System.DateTime someValue)
{
_ = $@"prefix {someValue:\d ""d""} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithStringConstantParameter()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(System.DateTime someValue)
{
const string someConst = "some format code";
_ = $"prefix {someValue[||].ToString(someConst)} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithCharacterLiteralParameter()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(C someValue)
{
_ = $"prefix {someValue[||].ToString('f')} suffix";
}
public string ToString(object obj) => null;
}
""");
}
[Fact]
public async Task ToStringWithFormatProvider()
{
// (If someone is explicitly specifying culture, an implicit form should not be encouraged.)
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(System.DateTime someValue)
{
_ = $"prefix {someValue[||].ToString("some format code", System.Globalization.CultureInfo.CurrentCulture)} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithInvariantCultureInsideFormattableStringInvariant()
{
// Invariance remains explicit, so this is okay.
await TestInRegularAndScript1Async(
"""
class C
{
void M(System.DateTime someValue)
{
_ = System.FormattableString.Invariant($"prefix {someValue[||]{|Unnecessary:.ToString(System.Globalization.CultureInfo.InvariantCulture)|}} suffix");
}
}
""",
"""
class C
{
void M(System.DateTime someValue)
{
_ = System.FormattableString.Invariant($"prefix {someValue} suffix");
}
}
""");
}
[Fact]
public async Task DateTimeFormatInfoInvariantInfoIsRecognized()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(System.DateTime someValue)
{
_ = System.FormattableString.Invariant($"prefix {someValue[||]{|Unnecessary:.ToString(System.Globalization.DateTimeFormatInfo.InvariantInfo)|}} suffix");
}
}
""",
"""
class C
{
void M(System.DateTime someValue)
{
_ = System.FormattableString.Invariant($"prefix {someValue} suffix");
}
}
""");
}
[Fact]
public async Task NumberFormatInfoInvariantInfoIsRecognized()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(int someValue)
{
_ = System.FormattableString.Invariant($"prefix {someValue[||]{|Unnecessary:.ToString(System.Globalization.NumberFormatInfo.InvariantInfo)|}} suffix");
}
}
""",
"""
class C
{
void M(int someValue)
{
_ = System.FormattableString.Invariant($"prefix {someValue} suffix");
}
}
""");
}
[Fact]
public async Task ToStringWithInvariantCultureOutsideFormattableStringInvariant()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(System.DateTime someValue)
{
_ = $"prefix {someValue[||].ToString(System.Globalization.CultureInfo.InvariantCulture)} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithFormatAndInvariantCultureInsideFormattableStringInvariant()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(System.DateTime someValue)
{
_ = System.FormattableString.Invariant($"prefix {someValue[||]{|Unnecessary:.ToString("|}some format code{|Unnecessary:", System.Globalization.CultureInfo.InvariantCulture)|}} suffix");
}
}
""",
"""
class C
{
void M(System.DateTime someValue)
{
_ = System.FormattableString.Invariant($"prefix {someValue:some format code} suffix");
}
}
""");
}
[Fact]
public async Task ToStringWithFormatAndInvariantCultureOutsideFormattableStringInvariant()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(System.DateTime someValue)
{
_ = $"prefix {someValue[||].ToString("some format code", System.Globalization.CultureInfo.InvariantCulture)} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftWithIntegerLiteral()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].PadLeft(|}3{|Unnecessary:)|}} suffix";
}
}
""",
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue,3} suffix";
}
}
""");
}
[Fact]
public async Task PadRightWithIntegerLiteral()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].PadRight(|}3{|Unnecessary:)|}} suffix";
}
}
""",
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue,-3} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftWithComplexConstantExpression()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
const int someConstant = 1;
_ = $"prefix {someValue{|Unnecessary:[||].PadLeft(|}(byte)3.3 + someConstant{|Unnecessary:)|}} suffix";
}
}
""",
"""
class C
{
void M(string someValue)
{
const int someConstant = 1;
_ = $"prefix {someValue,(byte)3.3 + someConstant} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftWithSpaceChar()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].PadLeft(|}3{|Unnecessary:, ' ')|}} suffix";
}
}
""",
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue,3} suffix";
}
}
""");
}
[Fact]
public async Task PadRightWithSpaceChar()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].PadRight(|}3{|Unnecessary:, ' ')|}} suffix";
}
}
""",
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue,-3} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftWithNonSpaceChar()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].PadLeft(3, '\t')} suffix";
}
}
""");
}
[Fact]
public async Task PadRightWithNonSpaceChar()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].PadRight(3, '\t')} suffix";
}
}
""");
}
[Fact]
public async Task PadRightWithComplexConstantExpressionRequiringParentheses()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
const int someConstant = 1;
_ = $"prefix {someValue{|Unnecessary:[||].PadRight(|}(byte)3.3 + someConstant{|Unnecessary:)|}} suffix";
}
}
""",
"""
class C
{
void M(string someValue)
{
const int someConstant = 1;
_ = $"prefix {someValue,-((byte)3.3 + someConstant)} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithNoParameterWhenFormattingComponentIsSpecified()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].ToString():goo} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithStringLiteralParameterWhenFormattingComponentIsSpecified()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].ToString("bar"):goo} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithNoParameterWhenAlignmentComponentIsSpecified()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].ToString()|},3} suffix";
}
}
""",
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue,3} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithNoParameterWhenBothComponentsAreSpecified()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].ToString(),3:goo} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithStringLiteralParameterWhenBothComponentsAreSpecified()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].ToString("some format code"),3:goo} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftWhenFormattingComponentIsSpecified()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].PadLeft(3):goo} suffix";
}
}
""",
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue,3:goo} suffix";
}
}
""");
}
[Fact]
public async Task PadRightWhenFormattingComponentIsSpecified()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].PadRight(3):goo} suffix";
}
}
""",
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue,-3:goo} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftWhenAlignmentComponentIsSpecified()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].PadLeft(3),3} suffix";
}
}
""");
}
[Fact]
public async Task PadRightWhenAlignmentComponentIsSpecified()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].PadRight(3),3} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftWhenBothComponentsAreSpecified()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].PadLeft(3),3:goo} suffix";
}
}
""");
}
[Fact]
public async Task PadRightWhenBothComponentsAreSpecified()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue[||].PadRight(3),3:goo} suffix";
}
}
""");
}
[Fact]
public async Task ToStringWithoutFormatThenPadLeft()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].ToString()|}{|Unnecessary:.PadLeft(|}3{|Unnecessary:)|}} suffix";
}
}
""", """
class C
{
void M(string someValue)
{
_ = $"prefix {someValue,3} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftThenToStringWithoutFormat()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue.PadLeft(3){|Unnecessary:[||].ToString()|}} suffix";
}
}
""", """
class C
{
void M(string someValue)
{
_ = $"prefix {someValue.PadLeft(3)} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftThenToStringWithoutFormatWhenAlignmentComponentIsSpecified()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue.PadLeft(3){|Unnecessary:[||].ToString()|},3} suffix";
}
}
""", """
class C
{
void M(string someValue)
{
_ = $"prefix {someValue.PadLeft(3),3} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftThenPadRight_WithoutAlignment()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue.PadLeft(3){|Unnecessary:[||].PadRight(|}3{|Unnecessary:)|}} suffix";
}
}
""", """
class C
{
void M(string someValue)
{
_ = $"prefix {someValue.PadLeft(3),-3} suffix";
}
}
""");
}
[Fact]
public async Task PadLeftThenPadRight_WithAlignment()
{
await TestMissingAsync(
"""
class C
{
void M(string someValue)
{
_ = $"prefix {someValue.PadLeft(3)[||].PadRight(3),3} suffix";
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41381")]
public async Task MissingOnImplicitToStringReceiver()
{
await TestMissingAsync(
"""
class C
{
override string ToString() => "Goobar";
string GetViaInterpolation() => $"Hello {ToString[||]()}";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41381")]
public async Task MissingOnImplicitToStringReceiverWithArg()
{
await TestMissingAsync(
"""
class C
{
string ToString(string arg) => "Goobar";
string GetViaInterpolation() => $"Hello {ToString[||]("g")}";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41381")]
public async Task MissingOnStaticToStringReceiver()
{
await TestMissingAsync(
"""
class C
{
public static string ToString() => "Goobar";
string GetViaInterpolation() => $"Hello {ToString[||]()}";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41381")]
public async Task MissingOnStaticToStringReceiverWithArg()
{
await TestMissingAsync(
"""
class C
{
public static string ToString(string arg) => "Goobar";
string GetViaInterpolation() => $"Hello {ToString[||]("g")}";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41381")]
public async Task MissingOnImplicitPadLeft()
{
await TestMissingAsync(
"""
class C
{
public string PadLeft(int val) => "";
void M(string someValue)
{
_ = $"prefix {[||]PadLeft(3)} suffix";
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41381")]
public async Task MissingOnStaticPadLeft()
{
await TestMissingAsync(
"""
class C
{
public static string PadLeft(int val) => "";
void M(string someValue)
{
_ = $"prefix {[||]PadLeft(3)} suffix";
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42247")]
public async Task OnConstantAlignment1()
{
await TestInRegularAndScript1Async(
"""
using System;
using System.Linq;
public static class Sample
{
public static void PrintRightAligned ( String[] strings )
{
const int maxLength = 1;
for ( var i = 0; i < strings.Length; i++ )
{
var str = strings[i];
Console.WriteLine ($"{i}.{str[||].PadRight(maxLength, ' ')}");
}
}
}
""",
"""
using System;
using System.Linq;
public static class Sample
{
public static void PrintRightAligned ( String[] strings )
{
const int maxLength = 1;
for ( var i = 0; i < strings.Length; i++ )
{
var str = strings[i];
Console.WriteLine ($"{i}.{str,-maxLength}");
}
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42247")]
public async Task MissingOnNonConstantAlignment()
{
await TestMissingAsync(
"""
using System;
using System.Linq;
public static class Sample
{
public static void PrintRightAligned ( String[] strings )
{
var maxLength = strings.Max(str => str.Length);
for ( var i = 0; i < strings.Length; i++ )
{
var str = strings[i];
Console.WriteLine ($"{i}.{str[||].PadRight(maxLength, ' ')}");
}
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42669")]
public async Task MissingOnBaseToString()
{
await TestMissingAsync(
"""
class C
{
public override string ToString() => $"Test: {base[||].ToString()}";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42669")]
public async Task MissingOnBaseToStringEvenWhenNotOverridden()
{
await TestMissingAsync(
"""
class C
{
string M() => $"Test: {base[||].ToString()}";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42669")]
public async Task MissingOnBaseToStringWithArgument()
{
await TestMissingAsync(
"""
class Base
{
public string ToString(string format) => format;
}
class Derived : Base
{
public override string ToString() => $"Test: {base[||].ToString("a")}";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42669")]
public async Task PadLeftSimplificationIsStillOfferedOnBaseToString()
{
await TestInRegularAndScript1Async(
"""
class C
{
public override string ToString() => $"Test: {base.ToString()[||].PadLeft(10)}";
}
""",
"""
class C
{
public override string ToString() => $"Test: {base.ToString(),10}";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42887")]
public async Task FormatComponentSimplificationIsNotOfferedOnNonIFormattableType()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
string M(TypeNotImplementingIFormattable value) => $"Test: {value[||].ToString("a")}";
}
struct TypeNotImplementingIFormattable
{
public string ToString(string format) => "A";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42887")]
public async Task FormatComponentSimplificationIsOfferedOnIFormattableType()
{
await TestInRegularAndScript1Async(
"""
using System;
class C
{
string M(TypeImplementingIFormattable value) => $"Test: {value[||].ToString("a")}";
}
struct TypeImplementingIFormattable : IFormattable
{
public string ToString(string format) => "A";
string IFormattable.ToString(string format, IFormatProvider formatProvider) => "B";
}
""",
"""
using System;
class C
{
string M(TypeImplementingIFormattable value) => $"Test: {value:a}";
}
struct TypeImplementingIFormattable : IFormattable
{
public string ToString(string format) => "A";
string IFormattable.ToString(string format, IFormatProvider formatProvider) => "B";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42887")]
public async Task ParameterlessToStringSimplificationIsStillOfferedOnNonIFormattableType()
{
await TestInRegularAndScript1Async(
"""
class C
{
string M(TypeNotImplementingIFormattable value) => $"Test: {value[||].ToString()}";
}
struct TypeNotImplementingIFormattable
{
public string ToString(string format) => "A";
}
""",
"""
class C
{
string M(TypeNotImplementingIFormattable value) => $"Test: {value}";
}
struct TypeNotImplementingIFormattable
{
public string ToString(string format) => "A";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42887")]
public async Task PadLeftSimplificationIsStillOfferedOnNonIFormattableType()
{
await TestInRegularAndScript1Async(
"""
class C
{
string M(TypeNotImplementingIFormattable value) => $"Test: {value.ToString("a")[||].PadLeft(10)}";
}
struct TypeNotImplementingIFormattable
{
public string ToString(string format) => "A";
}
""",
"""
class C
{
string M(TypeNotImplementingIFormattable value) => $"Test: {value.ToString("a"),10}";
}
struct TypeNotImplementingIFormattable
{
public string ToString(string format) => "A";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42936")]
public async Task ToStringSimplificationIsNotOfferedOnRefStruct()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
string M(RefStruct someValue) => $"Test: {someValue[||].ToString()}";
}
ref struct RefStruct
{
public override string ToString() => "A";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42936")]
public async Task PadLeftSimplificationIsStillOfferedOnRefStruct()
{
await TestInRegularAndScript1Async(
"""
class C
{
string M(RefStruct someValue) => $"Test: {someValue.ToString()[||].PadLeft(10)}";
}
ref struct RefStruct
{
public override string ToString() => "A";
}
""",
"""
class C
{
string M(RefStruct someValue) => $"Test: {someValue.ToString(),10}";
}
ref struct RefStruct
{
public override string ToString() => "A";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/46011")]
public async Task ShadowedToString()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
public new string ToString() => "Shadow";
static string M(C c) => $"{c[||].ToString()}";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/46011")]
public async Task OverridenShadowedToString()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
public new string ToString() => "Shadow";
}
class B : C
{
public override string ToString() => "OverrideShadow";
static string M(C c) => $"{c[||].ToString()}";
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/46011")]
public async Task DoubleOverridenToString()
{
await TestInRegularAndScript1Async(
"""
class C
{
public override string ToString() => "Override";
}
class B : C
{
public override string ToString() => "OverrideOverride";
void M(B someValue)
{
_ = $"prefix {someValue{|Unnecessary:[||].ToString()|}} suffix";
}
}
""",
"""
class C
{
public override string ToString() => "Override";
}
class B : C
{
public override string ToString() => "OverrideOverride";
void M(B someValue)
{
_ = $"prefix {someValue} suffix";
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49647")]
public async Task ConditionalExpressionMustRemainParenthesizedWhenUsingParameterlessToString()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(bool cond)
{
_ = $"{(cond ? 1 : 2){|Unnecessary:[||].ToString()|}}";
}
}
""",
"""
class C
{
void M(bool cond)
{
_ = $"{(cond ? 1 : 2)}";
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49647")]
public async Task ConditionalExpressionMustRemainParenthesizedWhenUsingParameterizedToString()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(bool cond)
{
_ = $"{(cond ? 1 : 2){|Unnecessary:[||].ToString("|}g{|Unnecessary:")|}}";
}
}
""",
"""
class C
{
void M(bool cond)
{
_ = $"{(cond ? 1 : 2):g}";
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49647")]
public async Task ConditionalExpressionMustRemainParenthesizedWhenUsingPadLeft()
{
await TestInRegularAndScript1Async(
"""
class C
{
void M(bool cond)
{
_ = $"{(cond ? "1" : "2"){|Unnecessary:[||].PadLeft(|}3{|Unnecessary:)|}}";
}
}
""",
"""
class C
{
void M(bool cond)
{
_ = $"{(cond ? "1" : "2"),3}";
}
}
""");
}
}
|