未验证 提交 e5165219 编写于 作者: S Sam Harwell 提交者: GitHub

Merge pull request #36054 from sharwell/avoid-rename

Avoid renaming methods that don't change return type
......@@ -17,6 +17,7 @@ internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProvider
=> (null, new CSharpMakeMethodAsynchronousCodeFixProvider());
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task AwaitInVoidMethodWithModifiers()
{
var initial =
......@@ -37,7 +38,7 @@ public static void Test()
class Program
{
public static async void TestAsync()
public static async void Test()
{
await Task.Delay(1);
}
......@@ -81,6 +82,7 @@ public static async Task Main()
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(26312, "https://github.com/dotnet/roslyn/issues/26312")]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task AwaitInVoidMainMethodWithModifiers_NotEntryPoint()
{
var initial =
......@@ -101,7 +103,7 @@ public void Main()
class Program
{
public async void MainAsync()
public async void Main()
{
await Task.Delay(1);
}
......@@ -139,6 +141,7 @@ public static async Task TestAsync()
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task AwaitInTaskMethodNoModifiers()
{
var initial =
......@@ -159,7 +162,7 @@ Task Test()
class Program
{
async Task TestAsync()
async Task Test()
{
await Task.Delay(1);
}
......@@ -168,6 +171,7 @@ async Task TestAsync()
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task AwaitInTaskMethodWithModifiers()
{
var initial =
......@@ -188,7 +192,7 @@ class Program
class Program
{
public/*Comment*/static/*Comment*/async Task/*Comment*/TestAsync()
public/*Comment*/static/*Comment*/async Task/*Comment*/Test()
{
await Task.Delay(1);
}
......@@ -257,6 +261,7 @@ static void Main(string[] args)
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task BadAwaitInNonAsyncMethod()
{
var initial =
......@@ -273,7 +278,7 @@ void Test()
@"using System.Threading.Tasks;
class Program
{
async void TestAsync()
async void Test()
{
await Task.Delay(1);
}
......@@ -282,6 +287,7 @@ async void TestAsync()
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task BadAwaitInNonAsyncMethod2()
{
var initial =
......@@ -298,7 +304,7 @@ Task Test()
@"using System.Threading.Tasks;
class Program
{
async Task TestAsync()
async Task Test()
{
await Task.Delay(1);
}
......@@ -307,6 +313,7 @@ async Task TestAsync()
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task BadAwaitInNonAsyncMethod3()
{
var initial =
......@@ -323,7 +330,7 @@ Task<int> Test()
@"using System.Threading.Tasks;
class Program
{
async Task<int> TestAsync()
async Task<int> Test()
{
await Task.Delay(1);
}
......@@ -357,6 +364,7 @@ async Task<int> TestAsync()
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task BadAwaitInNonAsyncMethod5()
{
var initial =
......@@ -371,7 +379,7 @@ void Test()
var expected =
@"class Program
{
async void TestAsync()
async void Test()
{
await Task.Delay(1);
}
......@@ -380,6 +388,7 @@ async void TestAsync()
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task BadAwaitInNonAsyncMethod6()
{
var initial =
......@@ -394,7 +403,7 @@ Task Test()
var expected =
@"class Program
{
async Task TestAsync()
async Task Test()
{
await Task.Delay(1);
}
......@@ -403,6 +412,7 @@ async Task TestAsync()
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task BadAwaitInNonAsyncMethod7()
{
var initial =
......@@ -417,7 +427,7 @@ Task<int> Test()
var expected =
@"class Program
{
async Task<int> TestAsync()
async Task<int> Test()
{
await Task.Delay(1);
}
......@@ -714,6 +724,7 @@ async IAsyncEnumerator<int> TestAsync()
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task BadAwaitInIAsyncEnumerableMethod()
{
var initial =
......@@ -733,7 +744,7 @@ IAsyncEnumerable<int> Test()
using System.Collections.Generic;
class Program
{
async IAsyncEnumerable<int> TestAsync()
async IAsyncEnumerable<int> Test()
{
yield return 1;
await Task.Delay(1);
......@@ -743,6 +754,7 @@ async IAsyncEnumerable<int> TestAsync()
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task BadAwaitInIAsyncEnumeratorMethod()
{
var initial =
......@@ -762,7 +774,7 @@ IAsyncEnumerator<int> Test()
using System.Collections.Generic;
class Program
{
async IAsyncEnumerator<int> TestAsync()
async IAsyncEnumerator<int> Test()
{
yield return 1;
await Task.Delay(1);
......@@ -927,6 +939,7 @@ static async void Main()
[WorkItem(17470, "https://github.com/dotnet/roslyn/issues/17470")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task AwaitInValueTaskMethod()
{
var initial =
......@@ -959,7 +972,7 @@ struct ValueTask<T>
class Program
{
async ValueTask<int> TestAsync()
async ValueTask<int> Test()
{
await Task.Delay(1);
}
......@@ -1010,6 +1023,7 @@ async Task<int> M3Async()
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(14133, "https://github.com/dotnet/roslyn/issues/14133")]
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task AddAsyncInLocalFunctionKeepVoidReturn()
{
await TestInRegularAndScriptAsync(
......@@ -1036,7 +1050,7 @@ class C
{
public void M1()
{
async void M2Async()
async void M2()
{
await M3Async();
}
......@@ -1051,13 +1065,14 @@ async Task<int> M3Async()
}
[Theory]
[InlineData(0, "void", "Task")]
[InlineData(1, "void", "void")]
[InlineData(0, "int", "Task<int>")]
[InlineData(0, "Task", "Task")]
[InlineData(0, "void", "Task", "M2Async")]
[InlineData(1, "void", "void", "M2")]
[InlineData(0, "int", "Task<int>", "M2Async")]
[InlineData(0, "Task", "Task", "M2")]
[Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(18307, "https://github.com/dotnet/roslyn/issues/18307")]
public async Task AddAsyncInLocalFunctionKeepsTrivia(int codeFixIndex, string initialReturn, string expectedReturn)
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task AddAsyncInLocalFunctionKeepsTrivia(int codeFixIndex, string initialReturn, string expectedReturn, string expectedName)
{
await TestInRegularAndScriptAsync(
$@"using System.Threading.Tasks;
......@@ -1085,7 +1100,7 @@ class C
public void M1()
{{
// Leading trivia
/*1*/ async {expectedReturn} /*2*/ M2Async/*3*/() /*4*/
/*1*/ async {expectedReturn} /*2*/ {expectedName}/*3*/() /*4*/
{{
await M3Async();
}}
......@@ -1100,13 +1115,14 @@ async Task<int> M3Async()
}
[Theory]
[InlineData("", 0, "Task")]
[InlineData("", 1, "void")]
[InlineData("public", 0, "Task")]
[InlineData("public", 1, "void")]
[InlineData("", 0, "Task", "M2Async")]
[InlineData("", 1, "void", "M2")]
[InlineData("public", 0, "Task", "M2Async")]
[InlineData("public", 1, "void", "M2")]
[Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
[WorkItem(18307, "https://github.com/dotnet/roslyn/issues/18307")]
public async Task AddAsyncKeepsTrivia(string modifiers, int codeFixIndex, string expectedReturn)
[WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")]
public async Task AddAsyncKeepsTrivia(string modifiers, int codeFixIndex, string expectedReturn, string expectedName)
{
await TestInRegularAndScriptAsync(
$@"using System.Threading.Tasks;
......@@ -1129,7 +1145,7 @@ async Task<int> M3Async()
class C
{{
// Leading trivia
{modifiers}/*1*/ async {expectedReturn} /*2*/ M2Async/*3*/() /*4*/
{modifiers}/*1*/ async {expectedReturn} /*2*/ {expectedName}/*3*/() /*4*/
{{
await M3Async();
}}
......
......@@ -13,6 +13,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.MakeMe
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)>
<WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")>
Public Async Function TestAwaitInSubNoModifiers() As Task
Await TestInRegularAndScriptAsync(
"Imports System
......@@ -25,7 +26,7 @@ End Module",
"Imports System
Imports System.Threading.Tasks
Module Program
Async Sub TestAsync()
Async Sub Test()
Await Task.Delay(1)
End Sub
End Module",
......@@ -33,6 +34,7 @@ End Module",
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)>
<WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")>
Public Async Function TestAwaitInSubWithModifiers() As Task
Await TestInRegularAndScriptAsync(
"Imports System
......@@ -45,7 +47,7 @@ End Module",
"Imports System
Imports System.Threading.Tasks
Module Program
Public Shared Async Sub TestAsync()
Public Shared Async Sub Test()
Await Task.Delay(1)
End Sub
End Module",
......@@ -137,6 +139,7 @@ Module Program
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)>
<WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")>
Public Async Function TestBadAwaitInNonAsyncMethod() As Task
Dim initial =
<ModuleDeclaration>
......@@ -146,7 +149,7 @@ Module Program
</ModuleDeclaration>
Dim expected =
<ModuleDeclaration>
Async Function rtrtAsync() As Task
Async Function rtrt() As Task
Await Nothing
End Function
</ModuleDeclaration>
......@@ -154,6 +157,7 @@ Async Function rtrtAsync() As Task
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)>
<WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")>
Public Async Function TestBadAwaitInNonAsyncVoidMethod() As Task
Dim initial =
<ModuleDeclaration>
......@@ -163,7 +167,7 @@ Async Function rtrtAsync() As Task
</ModuleDeclaration>
Dim expected =
<ModuleDeclaration>
Async Sub rtrtAsync()
Async Sub rtrt()
Await Nothing
End Sub
</ModuleDeclaration>
......@@ -188,6 +192,7 @@ Async Function rtrtAsync() As Threading.Tasks.Task
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)>
<WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")>
Public Async Function TestBadAwaitInNonAsyncFunction() As Task
Dim initial =
<ModuleDeclaration>
......@@ -197,7 +202,7 @@ Async Function rtrtAsync() As Threading.Tasks.Task
</ModuleDeclaration>
Dim expected =
<ModuleDeclaration>
Async Function rtrtAsync() As Task
Async Function rtrt() As Task
Await Nothing
End Function
</ModuleDeclaration>
......@@ -205,6 +210,7 @@ Async Function rtrtAsync() As Task
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)>
<WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")>
Public Async Function TestBadAwaitInNonAsyncFunction2() As Task
Dim initial =
<ModuleDeclaration>
......@@ -214,7 +220,7 @@ Async Function rtrtAsync() As Task
</ModuleDeclaration>
Dim expected =
<ModuleDeclaration>
Async Function rtrtAsync() As Task(Of Integer)
Async Function rtrt() As Task(Of Integer)
Await Nothing
End Function
</ModuleDeclaration>
......@@ -239,6 +245,7 @@ Async Function rtrtAsync() As Threading.Tasks.Task(Of Integer)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)>
<WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")>
Public Async Function TestBadAwaitInNonAsyncFunction4() As Task
Dim initial =
<File>
......@@ -251,7 +258,7 @@ End Class
Dim expected =
<File>
Class Program
Async Function rtrtAsync() As Task
Async Function rtrt() As Task
Await Nothing
End Function
End Class
......@@ -260,6 +267,7 @@ End Class
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)>
<WorkItem(33082, "https://github.com/dotnet/roslyn/issues/33082")>
Public Async Function TestBadAwaitInNonAsyncFunction5() As Task
Dim initial =
<File>
......@@ -272,7 +280,7 @@ End Class
Dim expected =
<File>
Class Program
Async Function rtrtAsync() As Task(Of Integer)
Async Function rtrt() As Task(Of Integer)
Await Nothing
End Function
End Class
......
......@@ -44,6 +44,12 @@ protected override string GetMakeAsyncVoidFunctionResource()
protected override bool IsAsyncSupportingFunctionSyntax(SyntaxNode node)
=> node.IsAsyncSupportingFunctionSyntax();
protected override bool IsAsyncReturnType(ITypeSymbol type, KnownTypes knownTypes)
{
return IsIAsyncEnumerableOrEnumerator(type, knownTypes)
|| IsTaskLike(type, knownTypes);
}
protected override SyntaxNode AddAsyncTokenAndFixReturnType(
bool keepVoid, IMethodSymbol methodSymbolOpt, SyntaxNode node,
KnownTypes knownTypes)
......
......@@ -17,6 +17,8 @@ internal abstract partial class AbstractMakeMethodAsynchronousCodeFixProvider :
{
protected abstract bool IsAsyncSupportingFunctionSyntax(SyntaxNode node);
protected abstract bool IsAsyncReturnType(ITypeSymbol type, KnownTypes knownTypes);
protected abstract SyntaxNode AddAsyncTokenAndFixReturnType(
bool keepVoid, IMethodSymbol methodSymbolOpt, SyntaxNode node,
KnownTypes knownTypes);
......@@ -93,17 +95,49 @@ private bool IsLikelyEntryPointName(string name, Document document)
// if it has the 'Async' suffix, and remove that suffix if so.
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var methodSymbolOpt = semanticModel.GetDeclaredSymbol(node) as IMethodSymbol;
var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var knownTypes = new KnownTypes(compilation);
bool isOrdinaryOrLocalFunction = methodSymbolOpt.IsOrdinaryMethodOrLocalFunction();
if (isOrdinaryOrLocalFunction && !methodSymbolOpt.Name.EndsWith(AsyncSuffix) && !isEntryPoint)
if (NeedsRename(this, methodSymbolOpt, keepVoid, isEntryPoint, in knownTypes))
{
return await RenameThenAddAsyncTokenAsync(
keepVoid, document, node, methodSymbolOpt, cancellationToken).ConfigureAwait(false);
keepVoid, document, node, methodSymbolOpt, knownTypes, cancellationToken).ConfigureAwait(false);
}
else
{
return await AddAsyncTokenAsync(
keepVoid, document, methodSymbolOpt, node, cancellationToken).ConfigureAwait(false);
keepVoid, document, methodSymbolOpt, knownTypes, node, cancellationToken).ConfigureAwait(false);
}
static bool NeedsRename(AbstractMakeMethodAsynchronousCodeFixProvider @this, IMethodSymbol methodSymbol, bool keepVoid, bool isEntryPoint, in KnownTypes knownTypes)
{
if (!methodSymbol.IsOrdinaryMethodOrLocalFunction())
{
// We don't need to rename methods that don't have a name
return false;
}
if (methodSymbol.Name.EndsWith(AsyncSuffix))
{
// We don't need to rename methods that already have an Async suffix
return false;
}
if (isEntryPoint)
{
// We don't need to rename entry point methods
return false;
}
// Only rename if the return type will change
if (methodSymbol.ReturnsVoid)
{
return !keepVoid;
}
else
{
return !@this.IsAsyncReturnType(methodSymbol.ReturnType, knownTypes);
}
}
}
......@@ -115,8 +149,12 @@ private SyntaxNode GetContainingFunction(Diagnostic diagnostic, CancellationToke
}
private async Task<Solution> RenameThenAddAsyncTokenAsync(
bool keepVoid, Document document, SyntaxNode node,
IMethodSymbol methodSymbol, CancellationToken cancellationToken)
bool keepVoid,
Document document,
SyntaxNode node,
IMethodSymbol methodSymbol,
KnownTypes knownTypes,
CancellationToken cancellationToken)
{
var name = methodSymbol.Name;
var newName = name + AsyncSuffix;
......@@ -134,18 +172,20 @@ private SyntaxNode GetContainingFunction(Diagnostic diagnostic, CancellationToke
{
var semanticModel = await newDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var newMethod = (IMethodSymbol)semanticModel.GetDeclaredSymbol(newNode, cancellationToken);
return await AddAsyncTokenAsync(keepVoid, newDocument, newMethod, newNode, cancellationToken).ConfigureAwait(false);
return await AddAsyncTokenAsync(keepVoid, newDocument, newMethod, knownTypes, newNode, cancellationToken).ConfigureAwait(false);
}
return newSolution;
}
private async Task<Solution> AddAsyncTokenAsync(
bool keepVoid, Document document, IMethodSymbol methodSymbolOpt,
SyntaxNode node, CancellationToken cancellationToken)
bool keepVoid,
Document document,
IMethodSymbol methodSymbolOpt,
KnownTypes knownTypes,
SyntaxNode node,
CancellationToken cancellationToken)
{
var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var knownTypes = new KnownTypes(compilation);
var newNode = AddAsyncTokenAndFixReturnType(keepVoid, methodSymbolOpt, node, knownTypes);
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
......
......@@ -43,6 +43,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.MakeMethodAsynchronous
Return node.IsAsyncSupportedFunctionSyntax()
End Function
Protected Overrides Function IsAsyncReturnType(type As ITypeSymbol, knownTypes As KnownTypes) As Boolean
Return IsTaskLike(type, knownTypes)
End Function
Protected Overrides Function AddAsyncTokenAndFixReturnType(
keepVoid As Boolean, methodSymbolOpt As IMethodSymbol, node As SyntaxNode,
knownTypes As KnownTypes) As SyntaxNode
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册