Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't raise CA1849 when async version has fewer parameters #7318

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,31 @@ private static ImmutableArray<IMethodSymbol> GetExcludedMethods(WellKnownTypePro
/// </returns>
private static bool HasSupersetOfParameterTypes(IMethodSymbol candidateMethod, IMethodSymbol baselineMethod)
{
return candidateMethod.Parameters.All(candidateParameter => candidateParameter.HasExplicitDefaultValue || baselineMethod.Parameters.Any(baselineParameter => baselineParameter.Type?.Equals(candidateParameter.Type) ?? false));
var baselineMethodTypeCount = GetTypeCount(baselineMethod);
var candidateMethodTypeCount = GetTypeCount(candidateMethod);
foreach (var (type, baselineCount) in baselineMethodTypeCount)
{
if (!candidateMethodTypeCount.TryGetValue(type, out var candidateCount) || baselineCount > candidateCount)
{
return false;
}
}

return true;

// Returns a dictionary of a count of the method's non-optional parameters by type.
// For a method with the signature:
// void M(string s, string s2, bool b, char c = 'c')
// the dictionary would contain the following key value pairs:
// - (string, 2)
// - (bool, 1)
static IDictionary<ITypeSymbol, int> GetTypeCount(IMethodSymbol methodSymbol)
{
return methodSymbol.Parameters
.Where(p => !p.HasExplicitDefaultValue)
.GroupBy<IParameterSymbol, ITypeSymbol>(p => p.Type, SymbolEqualityComparer.Default)
.ToDictionary<IGrouping<ITypeSymbol, IParameterSymbol>, ITypeSymbol, int>(g => g.Key, g => g.Count(), SymbolEqualityComparer.Default);
}
}

private static bool HasAsyncCompatibleReturnType(IMethodSymbol methodSymbol, ConcurrentDictionary<string, INamedTypeSymbol> syncBlockingTypes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,33 @@ public async Task<string> Foo()
return VerifyCS.VerifyAnalyzerAsync(code);
}

[Theory]
[InlineData("string s", "")]
[InlineData("string s", "bool b")]
[InlineData("string s", "bool b = true")]
[WorkItem(7289, "https://github.com/dotnet/roslyn-analyzers/issues/7289")]
public Task WhenAsyncVersionHasFewerParameters_NoDiagnostic(string syncParameters, string asyncParameters)
{
var code = $$"""
using System.Threading.Tasks;

class Test
{
private void Run({{syncParameters}}) { }
private Task RunAsync({{asyncParameters}}) => Task.CompletedTask;

private async Task ReproAsync()
{
await Task.Yield();

Run("");
}
}
""";

return CreateCSTestAndRunAsync(code);
}

private static async Task CreateCSTestAndRunAsync(string testCS)
{
var csTestVerify = new VerifyCS.Test
Expand Down