From 0870135ee8b231a33117f4a62b3802ee78245899 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 13 Sep 2018 14:30:40 -0700 Subject: [PATCH] Create AddAwait refactoring (#28930) --- .../CodeActions/AddAwait/AddAwaitTests.cs | 227 ++++++++++++++++++ .../CodeActions/AddAwait/AddAwaitTests.vb | 157 ++++++++++++ .../CSharpFeaturesResources.Designer.cs | 18 ++ .../Portable/CSharpFeaturesResources.resx | 6 + .../AddAwaitCodeRefactoringProvider.cs | 24 ++ .../xlf/CSharpFeaturesResources.cs.xlf | 10 + .../xlf/CSharpFeaturesResources.de.xlf | 10 + .../xlf/CSharpFeaturesResources.es.xlf | 10 + .../xlf/CSharpFeaturesResources.fr.xlf | 10 + .../xlf/CSharpFeaturesResources.it.xlf | 10 + .../xlf/CSharpFeaturesResources.ja.xlf | 10 + .../xlf/CSharpFeaturesResources.ko.xlf | 10 + .../xlf/CSharpFeaturesResources.pl.xlf | 10 + .../xlf/CSharpFeaturesResources.pt-BR.xlf | 10 + .../xlf/CSharpFeaturesResources.ru.xlf | 10 + .../xlf/CSharpFeaturesResources.tr.xlf | 10 + .../xlf/CSharpFeaturesResources.zh-Hans.xlf | 10 + .../xlf/CSharpFeaturesResources.zh-Hant.xlf | 10 + ...AbstractAddAwaitCodeRefactoringProvider.cs | 122 ++++++++++ .../PredefinedCodeRefactoringProviderNames.cs | 1 + .../AddAwaitCodeRefactoringProvider.vb | 21 ++ .../Portable/VBFeaturesResources.Designer.vb | 18 ++ .../Portable/VBFeaturesResources.resx | 6 + .../Portable/xlf/VBFeaturesResources.cs.xlf | 10 + .../Portable/xlf/VBFeaturesResources.de.xlf | 10 + .../Portable/xlf/VBFeaturesResources.es.xlf | 10 + .../Portable/xlf/VBFeaturesResources.fr.xlf | 10 + .../Portable/xlf/VBFeaturesResources.it.xlf | 10 + .../Portable/xlf/VBFeaturesResources.ja.xlf | 10 + .../Portable/xlf/VBFeaturesResources.ko.xlf | 10 + .../Portable/xlf/VBFeaturesResources.pl.xlf | 10 + .../xlf/VBFeaturesResources.pt-BR.xlf | 10 + .../Portable/xlf/VBFeaturesResources.ru.xlf | 10 + .../Portable/xlf/VBFeaturesResources.tr.xlf | 10 + .../xlf/VBFeaturesResources.zh-Hans.xlf | 10 + .../xlf/VBFeaturesResources.zh-Hant.xlf | 10 + src/Test/Utilities/Portable/Traits/Traits.cs | 1 + .../CodeGeneration/CSharpSyntaxGenerator.cs | 5 + .../Core/Portable/Editing/SyntaxGenerator.cs | 5 + .../VisualBasicSyntaxGenerator.vb | 4 + 40 files changed, 875 insertions(+) create mode 100644 src/EditorFeatures/CSharpTest/CodeActions/AddAwait/AddAwaitTests.cs create mode 100644 src/EditorFeatures/VisualBasicTest/CodeActions/AddAwait/AddAwaitTests.vb create mode 100644 src/Features/CSharp/Portable/CodeRefactorings/AddAwait/AddAwaitCodeRefactoringProvider.cs create mode 100644 src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs create mode 100644 src/Features/VisualBasic/Portable/CodeRefactorings/AddAwait/AddAwaitCodeRefactoringProvider.vb diff --git a/src/EditorFeatures/CSharpTest/CodeActions/AddAwait/AddAwaitTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/AddAwait/AddAwaitTests.cs new file mode 100644 index 00000000000..99b5ee213e3 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/CodeActions/AddAwait/AddAwaitTests.cs @@ -0,0 +1,227 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.AddAwait; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.AddAwait +{ + [Trait(Traits.Feature, Traits.Features.AddAwait)] + public class AddAwaitTests : AbstractCSharpCodeActionTest + { + protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters) + => new CSharpAddAwaitCodeRefactoringProvider(); + + [Fact] + public async Task Simple() + { + await TestInRegularAndScriptAsync(@" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = GetNumberAsync()[||]; + } +}", @" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = await GetNumberAsync(); + } +}"); + } + + [Fact] + public async Task SimpleWithConfigureAwait() + { + await TestInRegularAndScriptAsync(@" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = GetNumberAsync()[||]; + } +}", @" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = await GetNumberAsync().ConfigureAwait(false); + } +}", index: 1); + } + + [Fact] + public async Task InArgument() + { + await TestInRegularAndScriptAsync(@" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync(int argument) + { + var x = GetNumberAsync(arg[||]ument); + } +}", @" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync(int argument) + { + var x = await GetNumberAsync(argument); + } +}"); + } + + [Fact] + public async Task AlreadyAwaited() + { + await TestMissingInRegularAndScriptAsync(@" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = await GetNumberAsync()[||]; + } +}"); + } + + [Fact] + public async Task SimpleWithTrivia() + { + await TestInRegularAndScriptAsync(@" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = // comment + GetNumberAsync()[||] /* comment */ + } +}", @" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = // comment + await GetNumberAsync()[||] /* comment */ + } +}"); + } + + [Fact] + public async Task SimpleWithTrivia2() + { + await TestInRegularAndScriptAsync(@" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = /* comment */ GetNumberAsync()[||] // comment + } +}", @" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = /* comment */ await GetNumberAsync()[||] // comment + } +}"); + } + + [Fact] + public async Task SimpleWithTriviaWithConfigureAwait() + { + await TestInRegularAndScriptAsync(@" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = // comment + GetNumberAsync()[||] /* comment */ + } +}", @" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = // comment + await GetNumberAsync().ConfigureAwait(false) /* comment */ + } +}", index: 1); + } + + [Fact] + public async Task SimpleWithTrivia2WithConfigureAwait() + { + await TestInRegularAndScriptAsync(@" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = /* comment */ GetNumberAsync()[||] // comment + } +}", @" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = /* comment */ await GetNumberAsync().ConfigureAwait(false) // comment + } +}", index: 1); + } + + [Fact] + public async Task MissingOnSemiColon() + { + await TestMissingInRegularAndScriptAsync(@" +using System.Threading.Tasks; +class Program +{ + async Task GetNumberAsync() + { + var x = GetNumberAsync();[||] + } +}"); + } + + [Fact] + public async Task ChainedInvocation() + { + await TestInRegularAndScriptAsync(@" +using System.Threading.Tasks; +class Program +{ + Task GetNumberAsync() => throw null; + async void M() + { + var x = GetNumberAsync()[||].ToString(); + } +}", @" +using System.Threading.Tasks; +class Program +{ + Task GetNumberAsync() => throw null; + async void M() + { + var x = (await GetNumberAsync()).ToString(); + } +}"); + } + } +} diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/AddAwait/AddAwaitTests.vb b/src/EditorFeatures/VisualBasicTest/CodeActions/AddAwait/AddAwaitTests.vb new file mode 100644 index 00000000000..ed687bdb2c5 --- /dev/null +++ b/src/EditorFeatures/VisualBasicTest/CodeActions/AddAwait/AddAwaitTests.vb @@ -0,0 +1,157 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Option Strict Off +Imports Microsoft.CodeAnalysis.CodeRefactorings +Imports Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.AddAwait + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings.AddAwait + + Public Class AddAwaitTests + Inherits AbstractVisualBasicCodeActionTest + + Protected Overrides Function CreateCodeRefactoringProvider(workspace As Workspace, parameters As TestParameters) As CodeRefactoringProvider + Return New VisualBasicAddAwaitCodeRefactoringProvider() + End Function + + + Public Async Function Simple() As Task + Dim markup = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = GetNumberAsync()[||] + End Function +End Module + + + Dim expected = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = Await GetNumberAsync() + End Function +End Module + + + Await TestAsync(markup, expected) + End Function + + + Public Async Function SimpleWithConfigureAwait() As Task + Dim markup = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = GetNumberAsync()[||] + End Function +End Module + + + Dim expected = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = Await GetNumberAsync().ConfigureAwait(False) + End Function +End Module + + + Await TestAsync(markup, expected, index:=1) + End Function + + + Public Async Function AlreadyAwaited() As Task + Dim markup = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = Await GetNumberAsync()[||] + End Function +End Module + + + Await TestMissingAsync(markup) + End Function + + + Public Async Function SimpleWithTrivia() As Task + Dim markup = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = GetNumberAsync()[||] ' Comment + End Function +End Module + + + Dim expected = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = Await GetNumberAsync() ' Comment + End Function +End Module + + + Await TestAsync(markup, expected) + End Function + + + Public Async Function SimpleWithTriviaAndConfigureAwait() As Task + Dim markup = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = GetNumberAsync()[||] ' Comment + End Function +End Module + + + Dim expected = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = Await GetNumberAsync().ConfigureAwait(False) ' Comment + End Function +End Module + + + Await TestAsync(markup, expected, index:=1) + End Function + + + Public Async Function ChainedInvocation() As Task + Dim markup = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = GetNumberAsync()[||].ToString() + End Function +End Module + + + Dim expected = + +Imports System.Threading.Tasks +Module Program + Async Function GetNumberAsync() As Task(Of Integer) + Dim x = (Await GetNumberAsync()).ToString() + End Function +End Module + + + Await TestAsync(markup, expected) + End Function + + End Class +End Namespace diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs index 2b719a7b07f..09c6b4b58ab 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs @@ -79,6 +79,24 @@ internal class CSharpFeaturesResources { } } + /// + /// Looks up a localized string similar to Add await. + /// + internal static string Add_await { + get { + return ResourceManager.GetString("Add_await", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Add await and ConfigureAwait(false). + /// + internal static string Add_Await_and_ConfigureAwaitFalse { + get { + return ResourceManager.GetString("Add_Await_and_ConfigureAwaitFalse", resourceCulture); + } + } + /// /// Looks up a localized string similar to Add parentheses. /// diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx index 1c9c3a7bfa9..5877fe0a509 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx @@ -126,6 +126,12 @@ Invert if + + Add await + + + Add await and ConfigureAwait(false) + Simplify lambda expression diff --git a/src/Features/CSharp/Portable/CodeRefactorings/AddAwait/AddAwaitCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/AddAwait/AddAwaitCodeRefactoringProvider.cs new file mode 100644 index 00000000000..821a124349b --- /dev/null +++ b/src/Features/CSharp/Portable/CodeRefactorings/AddAwait/AddAwaitCodeRefactoringProvider.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Composition; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CodeRefactorings.AddAwait; +using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.AddAwait +{ + /// + /// This refactoring complements the AddAwait fixer. It allows adding `await` and `await ... .ConfigureAwait(false)` even there is no compiler error to trigger the fixer. + /// + [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.AddAwait), Shared] + internal partial class CSharpAddAwaitCodeRefactoringProvider : AbstractAddAwaitCodeRefactoringProvider + { + protected override string GetTitle() + => CSharpFeaturesResources.Add_await; + + protected override string GetTitleWithConfigureAwait() + => CSharpFeaturesResources.Add_Await_and_ConfigureAwaitFalse; + } +} diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf index bedfe29449f..cff609b744f 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers Přidat modifikátory dostupnosti + + Add await + Add await + + Add/remove braces for single-line control statements Přidat/odebrat složené závorky pro řídicí příkazy na jeden řádek diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf index 59909441e3c..a3ac97d0011 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers Zugriffsmodifizierer hinzufügen + + Add await + Add await + + Add/remove braces for single-line control statements Geschweifte Klammern für einzeilige Steuerungsanweisungen hinzufügen/entfernen diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf index a1c1b6e1165..355deb292ef 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers Agregar modificadores de accesibilidad + + Add await + Add await + + Add/remove braces for single-line control statements Agregar o quitar llaves para instrucciones de control de una línea diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf index b0ed9950d1f..17bf0966cc4 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers Ajouter des modificateurs d'accessibilité + + Add await + Add await + + Add/remove braces for single-line control statements Ajouter/supprimer des accolades pour les instructions de contrôle sur une seule ligne diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf index f98efd95ea1..21243ef8e23 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers Aggiungi modificatori di accessibilità + + Add await + Add await + + Add/remove braces for single-line control statements Aggiungi/rimuovi le parentesi graffe per le istruzioni di controllo a riga singola diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf index 50cd6250b86..08f078460f6 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers アクセシビリティ修飾子を追加します + + Add await + Add await + + Add/remove braces for single-line control statements 単一行のコントロール ステートメントに対する波かっこの追加/削除を行います diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf index 28e7834d4ff..876f59ebf94 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers 접근성 한정자 추가 + + Add await + Add await + + Add/remove braces for single-line control statements 한 줄 제어문에 대해 중괄호 추가/제거 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf index d896987d907..cd9df6baa18 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers Dodaj modyfikatory dostępności + + Add await + Add await + + Add/remove braces for single-line control statements Dodaj/usuń nawiasy klamrowe w przypadku jednowierszowych instrukcji sterowania diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf index cc48ec1928c..11fbf1c1c79 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers Adicionar modificadores de acessibilidade + + Add await + Add await + + Add/remove braces for single-line control statements Adicionar/remover as chaves das instruções de controle de linha única diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf index c15270fe6ec..5ea32ab3c65 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers Добавьте модификаторы доступности + + Add await + Add await + + Add/remove braces for single-line control statements Добавлять или удалять фигурные скобки для однострочных операторов управления diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf index a7d1f4d6caf..f1b44e5d0fc 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers Erişilebilirlik değiştiricileri ekle + + Add await + Add await + + Add/remove braces for single-line control statements Tek satır denetim deyimleri için küme ayracı ekle/küme ayraçlarını kaldır diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf index 6ef276a0549..472ebf4e7c6 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers 添加可访问性修饰符 + + Add await + Add await + + Add/remove braces for single-line control statements 添加/删除单行控制语句的括号 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf index c0667950b73..21e6c5855d4 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf @@ -2,11 +2,21 @@ + + Add await and ConfigureAwait(false) + Add await and ConfigureAwait(false) + + Add accessibility modifiers 新增協助工具修飾詞 + + Add await + Add await + + Add/remove braces for single-line control statements 新增/移除單行控制項陳述式的括弧 diff --git a/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs new file mode 100644 index 00000000000..53e15d341cd --- /dev/null +++ b/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.CodeRefactorings.AddAwait +{ + /// + /// Refactor: + /// var x = GetAsync(); + /// + /// Into: + /// var x = await GetAsync(); + /// + /// Or: + /// var x = await GetAsync().ConfigureAwait(false); + /// + internal abstract class AbstractAddAwaitCodeRefactoringProvider : CodeRefactoringProvider + where TExpressionSyntax : SyntaxNode + where TInvocationExpressionSyntax : TExpressionSyntax + { + protected abstract string GetTitle(); + protected abstract string GetTitleWithConfigureAwait(); + + public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) + { + var document = context.Document; + var textSpan = context.Span; + var cancellationToken = context.CancellationToken; + + if (!textSpan.IsEmpty) + { + return; + } + + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var token = root.FindTokenOnLeftOfPosition(textSpan.Start); + + var model = await document.GetSemanticModelAsync(cancellationToken); + var syntaxFacts = document.GetLanguageService(); + var awaitable = GetAwaitableExpression(textSpan, token, model, syntaxFacts, cancellationToken); + if (awaitable == null) + { + return; + } + + if (awaitable.OverlapsHiddenPosition(cancellationToken)) + { + return; + } + + context.RegisterRefactoring( + new MyCodeAction( + GetTitle(), + c => AddAwaitAsync(document, awaitable, withConfigureAwait: false, c))); + + + context.RegisterRefactoring( + new MyCodeAction( + GetTitleWithConfigureAwait(), + c => AddAwaitAsync(document, awaitable, withConfigureAwait: true, c))); + } + + private TExpressionSyntax GetAwaitableExpression(TextSpan textSpan, SyntaxToken token, SemanticModel model, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken) + { + var invocation = token.GetAncestor(); + if (invocation is null) + { + return null; + } + + if (syntaxFacts.IsExpressionOfAwaitExpression(invocation)) + { + return null; + } + + var type = model.GetTypeInfo(invocation).Type; + if (type?.IsAwaitableNonDynamic(model, token.SpanStart) == true) + { + return invocation; + } + + return null; + } + + private async Task AddAwaitAsync( + Document document, + TExpressionSyntax invocation, + bool withConfigureAwait, + CancellationToken cancellationToken) + { + var syntaxGenerator = SyntaxGenerator.GetGenerator(document); + SyntaxNode withoutTrivia = invocation.WithoutTrivia(); + if (withConfigureAwait) + { + withoutTrivia = syntaxGenerator.InvocationExpression( + syntaxGenerator.MemberAccessExpression(withoutTrivia, "ConfigureAwait"), + syntaxGenerator.FalseLiteralExpression()); + } + + var awaitExpression = syntaxGenerator + .AddParentheses(syntaxGenerator.AwaitExpression(withoutTrivia)) + .WithTriviaFrom(invocation); + + return await document.ReplaceNodeAsync(invocation, awaitExpression, cancellationToken); + } + + private class MyCodeAction : CodeAction.DocumentChangeAction + { + public MyCodeAction(string title, Func> createChangedDocument) : + base(title, createChangedDocument) + { + } + } + } +} diff --git a/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs b/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs index 6303404954d..d4d5801bd88 100644 --- a/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs +++ b/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs @@ -4,6 +4,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings { internal static class PredefinedCodeRefactoringProviderNames { + public const string AddAwait = "Add Await Code Action Provider"; public const string AddFileBanner = "Add Banner To File Code Action Provider"; public const string AddConstructorParametersFromMembers = "Add Parameters From Members Code Action Provider"; public const string ChangeSignature = "Change Signature Code Action Provider"; diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/AddAwait/AddAwaitCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/AddAwait/AddAwaitCodeRefactoringProvider.vb new file mode 100644 index 00000000000..57f1ec4361f --- /dev/null +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/AddAwait/AddAwaitCodeRefactoringProvider.vb @@ -0,0 +1,21 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Composition +Imports Microsoft.CodeAnalysis.CodeRefactorings +Imports Microsoft.CodeAnalysis.CodeRefactorings.AddAwait +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.AddAwait + + Friend Class VisualBasicAddAwaitCodeRefactoringProvider + Inherits AbstractAddAwaitCodeRefactoringProvider(Of ExpressionSyntax, InvocationExpressionSyntax) + + Protected Overrides Function GetTitle() As String + Return VBFeaturesResources.Add_Await + End Function + + Protected Overrides Function GetTitleWithConfigureAwait() As String + Return VBFeaturesResources.Add_Await_and_ConfigureAwaitFalse + End Function + End Class +End Namespace diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb b/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb index 42fbf260c35..7ac370c2805 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb @@ -93,6 +93,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.VBFeaturesResources End Get End Property + ''' + ''' Looks up a localized string similar to Add Await. + ''' + Friend ReadOnly Property Add_Await() As String + Get + Return ResourceManager.GetString("Add_Await", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Add Await and 'ConfigureAwait(false)'. + ''' + Friend ReadOnly Property Add_Await_and_ConfigureAwaitFalse() As String + Get + Return ResourceManager.GetString("Add_Await_and_ConfigureAwaitFalse", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to Add 'Me.'. ''' diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx index b8bf3fa92e8..605510e1e94 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx @@ -141,6 +141,12 @@ Invert If + + Add Await + + + Add Await and 'ConfigureAwait(false)' + Move the '{0}' statement to line {1}. diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf index de470a5fafb..357fda7e35f 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified Příkaz if lze zjednodušit. diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf index 50358ebacf2..a7f52185518 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified Die If-Anweisung kann vereinfacht werden. diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf index 377b2c5daba..390a1cbf7a8 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified La instrucción "if" se puede simplificar diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf index 981d6f0a07c..f752b9edf8a 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified L'instruction 'If' peut être simplifiée diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf index f3d103b68b2..4b045b09f4f 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified L'istruzione 'If' può essere semplificata diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf index d7e9489480a..e18a7171672 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified 'if' ステートメントは簡素化できます diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf index 77115b78fdc..c7576aee8e3 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified 'if' 문을 간단하게 줄일 수 있습니다. diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf index 0a18a506a85..0647bc2479c 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified Instrukcja „if” może zostać uproszczona diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf index c7ff481d9e2..6b870837a17 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified A instrução 'If' pode ser simplificada diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf index 991bc5a47d0..9a0773b72ce 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified Оператор if можно упростить diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf index a9de98fa47d..2723072227c 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified 'If' deyimi basitleştirilebilir diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf index 3cd6acec32e..f194fae1521 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified 可简化“If”语句 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf index 0faeba7bf3b..07eb8d32f53 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf @@ -2,6 +2,16 @@ + + Add Await + Add Await + + + + Add Await and 'ConfigureAwait(false)' + Add Await and 'ConfigureAwait(false)' + + 'If' statement can be simplified 'If' 陳述式可簡化 diff --git a/src/Test/Utilities/Portable/Traits/Traits.cs b/src/Test/Utilities/Portable/Traits/Traits.cs index 8d73f3dab8a..5f921d6bd5c 100644 --- a/src/Test/Utilities/Portable/Traits/Traits.cs +++ b/src/Test/Utilities/Portable/Traits/Traits.cs @@ -162,6 +162,7 @@ public static class Features public const string ErrorSquiggles = nameof(ErrorSquiggles); public const string EventHookup = nameof(EventHookup); public const string Expansion = nameof(Expansion); + public const string AddAwait = "Refactoring.AddAwait"; public const string ExtractInterface = "Refactoring.ExtractInterface"; public const string ExtractMethod = "Refactoring.ExtractMethod"; public const string F1Help = nameof(F1Help); diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index 3885944b7d4..425f8092c63 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -3766,6 +3766,11 @@ public override SyntaxNode DefaultExpression(ITypeSymbol type) return DefaultExpression(type.GenerateTypeSyntax()); } + internal override SyntaxNode AddParentheses(SyntaxNode expression) + { + return Parenthesize(expression); + } + private static ExpressionSyntax Parenthesize(SyntaxNode expression) { return ((ExpressionSyntax)expression).Parenthesize(); diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs index 348308b79b4..e3af49fd485 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs @@ -2215,6 +2215,11 @@ public SyntaxNode LambdaParameter(string identifier, ITypeSymbol type) /// public abstract SyntaxNode AwaitExpression(SyntaxNode expression); + /// + /// Wraps with parens. + /// + internal abstract SyntaxNode AddParentheses(SyntaxNode expression); + /// /// Creates an nameof expression. /// diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb index c6dcd37f294..6b20dc320ef 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb @@ -54,6 +54,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return SyntaxFactory.TupleExpression(SyntaxFactory.SeparatedList(arguments.Select(AddressOf AsSimpleArgument))) End Function + Friend Overrides Function AddParentheses(expression As SyntaxNode) As SyntaxNode + Return Parenthesize(expression) + End Function + Private Function Parenthesize(expression As SyntaxNode) As ParenthesizedExpressionSyntax Return DirectCast(expression, ExpressionSyntax).Parenthesize() End Function -- GitLab