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
7 changes: 7 additions & 0 deletions docs/Rules/MA0109.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@ void A(System.ReadOnlySpan<string> a) { }
void A(string[] a) { } // report diagnostic
````

The type parameters of generic methods are matched by position:

````c#
void A<T>(T[] a) { } // ok as there is an overload with Span
void A<TItem>(System.ReadOnlySpan<TItem> a) { }
````

The rule does not report a diagnostic for the program entry point (`Main(string[] args)`), as its signature is mandated by the runtime.
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ private bool IsValidOverload(IMethodSymbol method, IMethodSymbol overload)
if (overload.Parameters.Length != method.Parameters.Length)
return false;

// Match the type parameters of the methods by ordinal, so M<T>(T[]) and M<TItem>(ReadOnlySpan<TItem>) are compared using the same T
if (method.TypeParameters.Length > 0 && overload.TypeParameters.Length == method.TypeParameters.Length)
{
overload = overload.Construct([.. method.TypeParameters]);
}

for (var i = 0; i < method.Parameters.Length; i++)
{
var methodParameter = method.Parameters[i].Type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,68 @@ public void A({{overloadType}} a) { }

return test.RunAsync();
}

[Theory]
[InlineData("System.Span<T>")]
[InlineData("System.ReadOnlySpan<T>")]
[InlineData("System.Memory<T>")]
[InlineData("System.ReadOnlyMemory<T>")]
public Task GenericArrayWithSpanOverload(string overloadType)
{
var test = CreateTest();
test.TestCode = $$"""
public class Sample
{
public void M<T>(T[] values) { }
public void M<T>({{overloadType}} values) { }
}
""";

return test.RunAsync();
}

[Fact]
public Task GenericArrayWithSpanOverload_DifferentTypeParameterNames()
{
var test = CreateTest();
test.TestCode = """
public class Sample
{
public void M<T>(T[] values, T value) { }
public void M<TItem>(System.ReadOnlySpan<TItem> values, TItem value) { }
}
""";

return test.RunAsync();
}

[Fact]
public Task GenericArrayWithNonGenericSpanOverload()
{
var test = CreateTest();
test.TestCode = """
public class Sample
{
public void {|MA0109:M|}<T>(T[] values) { }
public void M(System.ReadOnlySpan<int> values) { }
}
""";

return test.RunAsync();
}

[Fact]
public Task GenericArrayWithSpanOverloadOfAnotherTypeParameter()
{
var test = CreateTest();
test.TestCode = """
public class Sample
{
public void {|MA0109:M|}<T1, T2>(T1[] values, T2 value) { }
public void M<T1, T2>(System.ReadOnlySpan<T2> values, T2 value) { }
}
""";

return test.RunAsync();
}
}
Loading