Skip to content

Commit

Permalink
Prevent CA2016 fixer from removing generic type parameter (#4974)
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidBoike authored Jul 10, 2021
1 parent cbe86f3 commit f64768f
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Threading;
using System.Threading.Tasks;
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Editing;
Expand Down Expand Up @@ -104,7 +103,7 @@ Task<Document> CreateChangedDocumentAsync(CancellationToken _)
context.Diagnostics);
}

private SyntaxNode TryGenerateNewDocumentRoot(
private static SyntaxNode TryGenerateNewDocumentRoot(
Document doc,
SyntaxNode root,
IInvocationOperation invocation,
Expand All @@ -128,30 +127,8 @@ private SyntaxNode TryGenerateNewDocumentRoot(

newArguments = newArguments.Add(cancellationTokenArgument);

SyntaxNode newInstance;
// The instance is null when calling a static method from another type
switch (invocation.Instance)
{
case null:
newInstance = expression;
break;
case IConditionalAccessInstanceOperation:
newInstance = GetConditionalOperationInvocationExpression(invocation.Syntax);
break;
default:
if (invocation.Instance.IsImplicit)
{
newInstance = invocation.GetInstanceSyntax()!;
}
// Calling a method from an object, we must include the instance variable name
else
{
newInstance = generator.MemberAccessExpression(invocation.GetInstanceSyntax(), invocation.TargetMethod.Name);
}
break;
}
// Insert the new arguments to the new invocation
SyntaxNode newInvocationWithArguments = generator.InvocationExpression(newInstance, newArguments).WithTriviaFrom(invocation.Syntax);
SyntaxNode newInvocationWithArguments = generator.InvocationExpression(expression, newArguments).WithTriviaFrom(invocation.Syntax);

return generator.ReplaceNode(root, invocation.Syntax, newInvocationWithArguments);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2249,6 +2249,156 @@ void LocalMethod()
return CS8VerifyCodeFixAsync(originalCode, fixedCode);
}

[Fact]
[WorkItem(4870, "https://github.com/dotnet/roslyn-analyzers/issues/4870")]
public Task CS_Diagnostic_GenericTypeParamOnInstanceMethod()
{
string originalCode = @"
using System;
using System.Threading;
using System.Threading.Tasks;
public class SqlDataReader
{
public Task<T> GetFieldValueAsync<T>(int i, CancellationToken c = default) => Task.FromResult(default(T));
}
class C
{
public async Task<Guid> M(SqlDataReader r, CancellationToken c)
{
return await [|r.GetFieldValueAsync<Guid>|](0);
}
}
";
string fixedCode = @"
using System;
using System.Threading;
using System.Threading.Tasks;
public class SqlDataReader
{
public Task<T> GetFieldValueAsync<T>(int i, CancellationToken c = default) => Task.FromResult(default(T));
}
class C
{
public async Task<Guid> M(SqlDataReader r, CancellationToken c)
{
return await r.GetFieldValueAsync<Guid>(0, c);
}
}
";
return CS8VerifyCodeFixAsync(originalCode, fixedCode);
}

[Fact]
[WorkItem(4870, "https://github.com/dotnet/roslyn-analyzers/issues/4870")]
public Task CS_Diagnostic_GenericTypeParamOnStaticMethod()
{
string originalCode = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class C
{
public static Task<T> GetFieldValueAsync<T>(int i, CancellationToken c = default) => Task.FromResult(default(T));
public async Task<Guid> M(CancellationToken c)
{
return await [|GetFieldValueAsync<Guid>|](0);
}
}
";
string fixedCode = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class C
{
public static Task<T> GetFieldValueAsync<T>(int i, CancellationToken c = default) => Task.FromResult(default(T));
public async Task<Guid> M(CancellationToken c)
{
return await GetFieldValueAsync<Guid>(0, c);
}
}
";
return CS8VerifyCodeFixAsync(originalCode, fixedCode);
}

[Fact]
[WorkItem(4870, "https://github.com/dotnet/roslyn-analyzers/issues/4870")]
public Task CS_Diagnostic_NullCoalescedDelegates()
{
string originalCode = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class C
{
delegate Task F(CancellationToken c = default);
static Task DoF(CancellationToken c = default) => Task.CompletedTask;
public async Task M(CancellationToken c)
{
F f1 = null;
F f2 = DoF;
await [|(f1 ?? f2)|]();
}
}
";
string fixedCode = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class C
{
delegate Task F(CancellationToken c = default);
static Task DoF(CancellationToken c = default) => Task.CompletedTask;
public async Task M(CancellationToken c)
{
F f1 = null;
F f2 = DoF;
await [|(f1 ?? f2)|](c);
}
}
";
return CS8VerifyCodeFixAsync(originalCode, fixedCode);
}

[Fact]
[WorkItem(4870, "https://github.com/dotnet/roslyn-analyzers/issues/4870")]
public Task CS_Diagnostic_NullCoalescedDelegatesWithInvoke()
{
string originalCode = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class C
{
delegate Task F(CancellationToken c = default);
static Task DoF(CancellationToken c = default) => Task.CompletedTask;
public async Task M(CancellationToken c)
{
F f1 = null;
F f2 = DoF;
await [|(f1 ?? f2).Invoke|]();
}
}
";
string fixedCode = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class C
{
delegate Task F(CancellationToken c = default);
static Task DoF(CancellationToken c = default) => Task.CompletedTask;
public async Task M(CancellationToken c)
{
F f1 = null;
F f2 = DoF;
await (f1 ?? f2).Invoke(c);
}
}
";
return CS8VerifyCodeFixAsync(originalCode, fixedCode);
}

[Fact]
[WorkItem(4985, "https://github.com/dotnet/roslyn-analyzers/issues/4985")]
public Task CS_Diagnostic_ReturnTypeIsConvertable()
Expand Down Expand Up @@ -4325,6 +4475,76 @@ End Class
return VerifyVB.VerifyCodeFixAsync(originalCode, fixedCode);
}

[Fact]
[WorkItem(4870, "https://github.com/dotnet/roslyn-analyzers/issues/4870")]
public Task VB_Diagnostic_GenericTypeParamOnInstanceMethod()
{
string originalCode = @"
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Public Class SqlDataReader
Public Function GetFieldValueAsync(Of T)(ByVal i As Integer, ByVal Optional c As CancellationToken = Nothing) As Task(Of T)
Return Task.CompletedTask
End Function
End Class
Class C
Public Async Function M(ByVal r As SqlDataReader, ByVal c As CancellationToken) As Task(Of Guid)
Return Await r.[|GetFieldValueAsync(Of Guid)|](0)
End Function
End Class
";
string fixedCode = @"
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Public Class SqlDataReader
Public Function GetFieldValueAsync(Of T)(ByVal i As Integer, ByVal Optional c As CancellationToken = Nothing) As Task(Of T)
Return Task.CompletedTask
End Function
End Class
Class C
Public Async Function M(ByVal r As SqlDataReader, ByVal c As CancellationToken) As Task(Of Guid)
Return Await r.GetFieldValueAsync(Of Guid)(0, c)
End Function
End Class
";
return VerifyVB.VerifyCodeFixAsync(originalCode, fixedCode);
}

[Fact]
[WorkItem(4870, "https://github.com/dotnet/roslyn-analyzers/issues/4870")]
public Task VB_Diagnostic_GenericTypeParamOnStaticMethod()
{
string originalCode = @"
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Class C
Public Shared Function GetFieldValueAsync(Of T)(ByVal i As Integer, Optional ByVal c As CancellationToken = Nothing) As Task(Of T)
Return Task.CompletedTask
End Function
Public Async Function M(ByVal c As CancellationToken) As Task(Of Guid)
Return Await [|GetFieldValueAsync(Of Guid)|](0)
End Function
End Class
";
string fixedCode = @"
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Class C
Public Shared Function GetFieldValueAsync(Of T)(ByVal i As Integer, Optional ByVal c As CancellationToken = Nothing) As Task(Of T)
Return Task.CompletedTask
End Function
Public Async Function M(ByVal c As CancellationToken) As Task(Of Guid)
Return Await GetFieldValueAsync(Of Guid)(0, c)
End Function
End Class
";
return VerifyVB.VerifyCodeFixAsync(originalCode, fixedCode);
}

[Fact]
[WorkItem(4985, "https://github.com/dotnet/roslyn-analyzers/issues/4985")]
public Task VB_Diagnostic_ReturnTypeIsConvertable()
Expand Down

0 comments on commit f64768f

Please sign in to comment.