Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Roslyn.sln
Original file line number Diff line number Diff line change
Expand Up @@ -2207,8 +2207,11 @@ Global
src\Workspaces\SharedUtilitiesAndExtensions\Workspace\VisualBasic\VisualBasicWorkspaceExtensions.projitems*{57ca988d-f010-4bf2-9a2e-07d6dcd2ff2c}*SharedItemsImports = 5
src\Analyzers\CSharp\Tests\CSharpAnalyzers.UnitTests.projitems*{58969243-7f59-4236-93d0-c93b81f569b3}*SharedItemsImports = 13
src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5
src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As soon as I edit something in VS it adds this. So maybe just keep it?

src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5
src\Dependencies\Threading\Microsoft.CodeAnalysis.Threading.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5
src\Workspaces\SharedUtilitiesAndExtensions\Compiler\Core\CompilerExtensions.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5
src\Workspaces\SharedUtilitiesAndExtensions\Compiler\Extensions\Microsoft.CodeAnalysis.Extensions.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5
src\Workspaces\SharedUtilitiesAndExtensions\Workspace\Core\WorkspaceExtensions.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 5
src\Analyzers\Core\CodeFixes\CodeFixes.projitems*{5ff1e493-69cc-4d0b-83f2-039f469a04e1}*SharedItemsImports = 5
src\Workspaces\SharedUtilitiesAndExtensions\Workspace\Core\WorkspaceExtensions.projitems*{5ff1e493-69cc-4d0b-83f2-039f469a04e1}*SharedItemsImports = 5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public async Task TestNotOnValueType()

class C
{
public C([||]int i)
public C([||]DateTime d)
{
}
}
Expand Down Expand Up @@ -3582,4 +3582,352 @@ void M(object o, DayOfWeek dayOfWeek, string s)
ReferenceAssemblies = ReferenceAssemblies.Net.Net80
}.RunAsync();
}

[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/37653")]
[InlineData("sbyte")]
[InlineData("short")]
[InlineData("int")]
[InlineData("long")]
public async Task TestSimpleNumericChecks_ModernOverloads(string validNumericType)
{
var code = $$"""
using System;

class C
{
void M({{validNumericType}} [|num|])
{
}
}
""";

await new VerifyCS.Test()
{
TestCode = code,
FixedCode = $$"""
using System;

class C
{
void M({{validNumericType}} [|num|])
{
ArgumentOutOfRangeException.ThrowIfNegative(num);
}
}
""",
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
CodeActionIndex = 0,
}.RunAsync();

await new VerifyCS.Test()
{
TestCode = code,
FixedCode = $$"""
using System;

class C
{
void M({{validNumericType}} [|num|])
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(num);
}
}
""",
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
CodeActionIndex = 1,
}.RunAsync();
}

[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/37653")]
[InlineData("sbyte")]
[InlineData("short")]
[InlineData("int")]
[InlineData("long")]
public async Task TestSimpleNumericChecks_OldStyleCheckStatement(string validNumericType)
{
var code = $$"""
using System;

class C
{
void M({{validNumericType}} [|num|])
{
}
}
""";

await new VerifyCS.Test()
{
TestCode = code,
FixedCode = $$"""
using System;

class C
{
void M({{validNumericType}} [|num|])
{
if (num < 0)
{
throw new ArgumentOutOfRangeException(nameof(num), num, $"{{string.Format(FeaturesResources._0_cannot_be_negative, "{nameof(num)}").Replace("\"", "\\\"")}}");
}
}
}
""",
ReferenceAssemblies = ReferenceAssemblies.NetStandard.NetStandard20,
CodeActionIndex = 0,
}.RunAsync();

await new VerifyCS.Test()
{
TestCode = code,
FixedCode = $$"""
using System;

class C
{
void M({{validNumericType}} [|num|])
{
if (num <= 0)
{
throw new ArgumentOutOfRangeException(nameof(num), num, $"{{string.Format(FeaturesResources._0_cannot_be_negative_or_zero, "{nameof(num)}").Replace("\"", "\\\"")}}");
}
}
}
""",
ReferenceAssemblies = ReferenceAssemblies.NetStandard.NetStandard20,
CodeActionIndex = 1,
}.RunAsync();
}

[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/37653")]
[InlineData("byte")]
[InlineData("ushort")]
[InlineData("uint")]
[InlineData("ulong")]
[InlineData("float")]
[InlineData("double")]
public async Task TestNoNumericChecksForUnsignedAndFloatingPointNumericTypes(string invalidNumericType)
{
await VerifyCS.VerifyRefactoringAsync($$"""
using System;

class C
{
void M({{invalidNumericType}} [|num|])
{
}
}
""");
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37653")]
public async Task TestNoNumericChecksForOutParameter()
{
await VerifyCS.VerifyRefactoringAsync("""
using System;

class C
{
void M(out int [|num|])
{
num = 0;
}
}
""");
}

[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/37653")]
[InlineData("ThrowIfNegative(num)")]
[InlineData("ThrowIfNegativeOrZero(num)")]
[InlineData("ThrowIfEqual(num, 5)")]
[InlineData("ThrowIfGreaterThan(num, 6)")]
[InlineData("ThrowIfGreaterThanOrEqual(num, 1)")]
[InlineData("ThrowIfLessThan(num, 2)")]
[InlineData("ThrowIfLessThanOrEqual(num, 3)")]
[InlineData("ThrowIfEqual(num, 15)")]
[InlineData("ThrowIfNotEqual(num, 10)")]
[InlineData("ThrowIfZero(num)")]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although we have refactorrings only for ThrowIfNegative and ThrowIfNegativeOrZero as the most common ones we recognize other numeric checks as well since adding our own if one of this is present doesn't make much sense

public async Task TestNoNumericChecksIfAlreadyExist_ModernOverloads(string methodInvocation)
{
await new VerifyCS.Test()
{
TestCode = $$"""
using System;

class C
{
void M(int [|num|])
{
ArgumentOutOfRangeException.{{methodInvocation}};
}
}
""",
ReferenceAssemblies = ReferenceAssemblies.Net.Net80
}.RunAsync();
}

[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/37653")]
[InlineData("num < 0")]
[InlineData("num <= 0")]
[InlineData("num > 11")]
[InlineData("num >= 12")]
[InlineData("0 > num")]
[InlineData("0 >= num")]
[InlineData("14 < num")]
[InlineData("22 <= num")]
[InlineData("num is < 0")]
[InlineData("num is <= 0")]
[InlineData("num < 1")]
[InlineData("num <= 39")]
[InlineData("25 > num")]
[InlineData("29 >= num")]
[InlineData("num is < 8")]
[InlineData("num is <= 18")]
[InlineData("num is > 5")]
[InlineData("num is >= 3")]
public async Task TestNoNumericChecksIfAlreadyExist_OldStyleCheckStatements(string numericCheck)
{
await new VerifyCS.Test()
{
TestCode = $$"""
using System;

class C
{
void M(int [|num|])
{
if ({{numericCheck}})
{
throw new ArgumentOutOfRangeException(nameof(num));
}
}
}
""",
LanguageVersion = LanguageVersion.Latest,
ReferenceAssemblies = ReferenceAssemblies.Net.Net80
}.RunAsync();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37653")]
public async Task TestNumericChecksAfterAnotherNumericCheck()
{
await new VerifyCS.Test()
{
TestCode = """
using System;

class C
{
void M(sbyte a, short [|b|])
{
ArgumentOutOfRangeException.ThrowIfNegative(a);
}
}
""",
FixedCode = """
using System;

class C
{
void M(sbyte a, short [|b|])
{
ArgumentOutOfRangeException.ThrowIfNegative(a);
ArgumentOutOfRangeException.ThrowIfNegative(b);
}
}
""",
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
}.RunAsync();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37653")]
public async Task TestNumericChecksBeforeAnotherNumericCheck()
{
await new VerifyCS.Test()
{
TestCode = """
using System;

class C
{
void M(long [|a|], int b)
{
if (b < 0)
{
throw new ArgumentOutOfRangeException(nameof(b));
}
}
}
""",
FixedCode = """
using System;

class C
{
void M(long a, int b)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(a);
if (b < 0)
{
throw new ArgumentOutOfRangeException(nameof(b));
}
}
}
""",
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
CodeActionIndex = 1
}.RunAsync();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37653")]
public async Task TestNumericChecksInBetweenDifferentChecks()
{
await new VerifyCS.Test()
{
TestCode = """
using System;

class C
{
void M(DayOfWeek day, int [|i|], string s)
{
if (!Enum.IsDefined(typeof(DayOfWeek), day))
{
throw new System.ComponentModel.InvalidEnumArgumentException(nameof(day), (int)day, typeof(DayOfWeek));
}

if (string.IsNullOrEmpty(s))
{
throw new ArgumentNullException(nameof(s));
}
}
}
""",
FixedCode = $$"""
using System;

class C
{
void M(DayOfWeek day, int i, string s)
{
if (!Enum.IsDefined(typeof(DayOfWeek), day))
{
throw new System.ComponentModel.InvalidEnumArgumentException(nameof(day), (int)day, typeof(DayOfWeek));
}

if (i < 0)
{
throw new ArgumentOutOfRangeException(nameof(i), i, $"{{string.Format(FeaturesResources._0_cannot_be_negative, "{nameof(i)}").Replace("\"", "\\\"")}}");
}

if (string.IsNullOrEmpty(s))
{
throw new ArgumentNullException(nameof(s));
}
}
}
""",
ReferenceAssemblies = ReferenceAssemblies.NetStandard.NetStandard20
}.RunAsync();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ end class")
Imports System

class C
public sub new([||]i as integer)
public sub new([||]i as DateTime)
end sub
end class")
End Function
Expand Down
Loading
Loading