From 31fa7894b6b9ed0327f80f10f64f5fd735b5a368 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Wed, 4 Apr 2018 12:12:16 -0700 Subject: [PATCH] IntroduceLocal on simple names (#25856) --- .../IntroduceVariableTests.cs | 167 ++++++++++++++++++ .../IntroduceVariableTests.vb | 66 +++++++ .../CSharpIntroduceVariableService.cs | 2 +- ...ice.AbstractIntroduceVariableCodeAction.cs | 2 +- ...ractIntroduceVariableService.CodeAction.cs | 2 +- ...ntroduceVariableAllOccurrenceCodeAction.cs | 2 +- .../AbstractIntroduceVariableService.State.cs | 14 +- ...ntroduceVariableService.State_Attribute.cs | 2 +- ...actIntroduceVariableService.State_Block.cs | 2 +- ...bleService.State_ConstructorInitializer.cs | 2 +- ...actIntroduceVariableService.State_Field.cs | 2 +- ...ntroduceVariableService.State_Parameter.cs | 2 +- ...actIntroduceVariableService.State_Query.cs | 2 +- .../AbstractIntroduceVariableService.cs | 5 +- .../VisualBasicIntroduceVariableService.vb | 4 +- 15 files changed, 259 insertions(+), 17 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/CodeActions/IntroduceVariable/IntroduceVariableTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/IntroduceVariable/IntroduceVariableTests.cs index 235c84df71f..e898d6929cc 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/IntroduceVariable/IntroduceVariableTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/IntroduceVariable/IntroduceVariableTests.cs @@ -4616,6 +4616,173 @@ void M() }"); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] + [WorkItem(10123, "https://github.com/dotnet/roslyn/issues/10123")] + public async Task TestSimpleParameterName() + { + await TestInRegularAndScriptAsync( +@" +class C +{ + void M(int a) + { + System.Console.Write([|a|]); + } +}", +@" +class C +{ + void M(int a) + { + int {|Rename:a1|} = a; + System.Console.Write(a1); + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] + [WorkItem(10123, "https://github.com/dotnet/roslyn/issues/10123")] + public async Task TestSimpleParamterName_EmptySelection() + { + await TestMissingAsync( +@"class C +{ + void M(int a) + { + System.Console.Write([||]a); + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] + [WorkItem(10123, "https://github.com/dotnet/roslyn/issues/10123")] + public async Task TestSimpleParamterName_SmallSelection() + { + await TestMissingAsync( +@"class C +{ + void M(int parameter) + { + System.Console.Write([|par|]ameter); + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] + [WorkItem(10123, "https://github.com/dotnet/roslyn/issues/10123")] + public async Task TestFieldName_QualifiedWithThis() + { + await TestInRegularAndScriptAsync( +@" +class C +{ + int a; + void M() + { + System.Console.Write([|this.a|]); + } +}", +@" +class C +{ + int a; + void M() + { + int {|Rename:a1|} = this.a; + System.Console.Write(a1); + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] + [WorkItem(10123, "https://github.com/dotnet/roslyn/issues/10123")] + public async Task TestFieldName_QualifiedWithType() + { + await TestInRegularAndScriptAsync( +@" +class C +{ + static int a; + void M() + { + System.Console.Write([|C.a|]); + } +}", +@" +class C +{ + static int a; + void M() + { + int {|Rename:a1|} = C.a; + System.Console.Write(a1); + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] + [WorkItem(10123, "https://github.com/dotnet/roslyn/issues/10123")] + public async Task TestFieldName_QualifiedWithType_TinySelection1() + { + await TestMissingAsync( +@" +class C +{ + static int a; + void M() + { + System.Console.Write(C[|.|]a); + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] + [WorkItem(10123, "https://github.com/dotnet/roslyn/issues/10123")] + public async Task TestFieldName_QualifiedWithType_TinySelection2() + { + await TestMissingAsync( +@" +class C +{ + static int a; + void M() + { + System.Console.Write([|C.|]a); + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] + [WorkItem(10123, "https://github.com/dotnet/roslyn/issues/10123")] + public async Task TestFieldName_QualifiedWithType_TinySelection3() + { + await TestMissingAsync( +@" +class C +{ + static int a; + void M() + { + System.Console.Write(C.[|a|]); + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] + [WorkItem(10123, "https://github.com/dotnet/roslyn/issues/10123")] + public async Task TestFieldName_QualifiedWithType_EmptySelection() + { + await TestMissingAsync( +@"class C +{ + static int a; + void M() + { + System.Console.Write(C.[||]a); + } +}"); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] public async Task TestIntroduceLocalInCallRefExpression() { diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceVariable/IntroduceVariableTests.vb b/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceVariable/IntroduceVariableTests.vb index 32e13d205d1..b43cb5ed648 100644 --- a/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceVariable/IntroduceVariableTests.vb +++ b/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceVariable/IntroduceVariableTests.vb @@ -2953,6 +2953,72 @@ structure TextSpan end structure") End Function + + + Public Async Function TestSimpleParameterName() As Task + Dim source = "Module Program + Sub Main(x As Integer) + Goo([|x|]) + End Sub +End Module" + Dim expected = "Module Program + Sub Main(x As Integer) + Dim {|Rename:x1|} As Integer = x + Goo(x1) + End Sub +End Module" + Await TestInRegularAndScriptAsync(source, expected) + End Function + + + + Public Async Function TestSimpleParameterName_EmptySelection() As Task + Dim source = "Module Program + Sub Main(x As Integer) + Goo([||]x) + End Sub +End Module" + Await TestMissingAsync(source) + End Function + + + + Public Async Function TestFieldName_QualifiedWithMe() As Task + Dim source = "Module Program + Dim x As Integer + Sub Main() + Goo([|x|]) + End Sub +End Module" + Dim expected = "Module Program + Dim x As Integer + Sub Main() + Dim {|Rename:x1|} As Integer = x + Goo(x1) + End Sub +End Module" + Await TestInRegularAndScriptAsync(source, expected) + End Function + + + + Public Async Function TestFieldName_QualifiedWithType() As Task + Dim source = "Module Program + Shared Dim x As Integer + Sub Main() + Goo([|Program.x|]) + End Sub +End Module" + Dim expected = "Module Program + Shared Dim x As Integer + Sub Main() + Dim {|Rename:x1|} As Integer = Program.x + Goo(x1) + End Sub +End Module" + Await TestInRegularAndScriptAsync(source, expected) + End Function + Public Async Function TestInAttribute() As Task diff --git a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService.cs b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService.cs index 221e717f83a..dfa866f410c 100644 --- a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService.cs +++ b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.CSharp.IntroduceVariable { [ExportLanguageService(typeof(IIntroduceVariableService), LanguageNames.CSharp), Shared] internal partial class CSharpIntroduceVariableService : - AbstractIntroduceVariableService + AbstractIntroduceVariableService { protected override bool IsInNonFirstQueryClause(ExpressionSyntax expression) { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs index 5786f88c6a7..34a61ba9183 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal partial class AbstractIntroduceVariableService + internal partial class AbstractIntroduceVariableService { internal abstract class AbstractIntroduceVariableCodeAction : CodeAction { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.CodeAction.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.CodeAction.cs index ae03a34fbb8..7d0a89d96b5 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.CodeAction.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.CodeAction.cs @@ -3,7 +3,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal partial class AbstractIntroduceVariableService + internal partial class AbstractIntroduceVariableService { private class IntroduceVariableCodeAction : AbstractIntroduceVariableCodeAction { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs index 7f91b16bbb4..f0f16e6cbaa 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal partial class AbstractIntroduceVariableService + internal partial class AbstractIntroduceVariableService { private class IntroduceVariableAllOccurrenceCodeAction : AbstractIntroduceVariableCodeAction { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs index 18b9b6e8313..d5a0c1f5c0b 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal partial class AbstractIntroduceVariableService + internal partial class AbstractIntroduceVariableService { private partial class State { @@ -82,7 +82,7 @@ public State(TService service, SemanticDocument document) return false; } - if (!CanIntroduceVariable(cancellationToken)) + if (!CanIntroduceVariable(textSpan.IsEmpty, cancellationToken)) { return false; } @@ -229,6 +229,7 @@ private TExpressionSyntax GetExpressionUnderSpan(SyntaxTree tree, TextSpan textS } private bool CanIntroduceVariable( + bool isSpanEmpty, CancellationToken cancellationToken) { if (!_service.CanIntroduceVariableFor(this.Expression)) @@ -236,8 +237,15 @@ private TExpressionSyntax GetExpressionUnderSpan(SyntaxTree tree, TextSpan textS return false; } - if (this.Expression is TTypeSyntax) + if (isSpanEmpty && this.Expression is TNameSyntax) { + // to extract a name, you must have a selection (this avoids making the refactoring too noisy) + return false; + } + + if (this.Expression is TTypeSyntax && !(this.Expression is TNameSyntax)) + { + // name syntax can introduce variables, but not other type syntaxes return false; } diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs index 477aa58de4b..172db039334 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs @@ -4,7 +4,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal partial class AbstractIntroduceVariableService + internal partial class AbstractIntroduceVariableService { private partial class State { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs index 47bbd4e8504..d7481a57bcf 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal partial class AbstractIntroduceVariableService + internal partial class AbstractIntroduceVariableService { private partial class State { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs index cb9c199d4f3..16b087b4c1b 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal partial class AbstractIntroduceVariableService + internal partial class AbstractIntroduceVariableService { private partial class State { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs index 61898fa0446..027b7032895 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal partial class AbstractIntroduceVariableService + internal partial class AbstractIntroduceVariableService { private partial class State { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs index c79015ce917..d583abfae84 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal partial class AbstractIntroduceVariableService + internal partial class AbstractIntroduceVariableService { private partial class State { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs index cf75dbe7dac..13479919a29 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal partial class AbstractIntroduceVariableService + internal partial class AbstractIntroduceVariableService { private partial class State { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs index 55c1b79ece4..aa4ecc6e920 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs @@ -18,12 +18,13 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable { - internal abstract partial class AbstractIntroduceVariableService : IIntroduceVariableService - where TService : AbstractIntroduceVariableService + internal abstract partial class AbstractIntroduceVariableService : IIntroduceVariableService + where TService : AbstractIntroduceVariableService where TExpressionSyntax : SyntaxNode where TTypeSyntax : TExpressionSyntax where TTypeDeclarationSyntax : SyntaxNode where TQueryExpressionSyntax : TExpressionSyntax + where TNameSyntax : TTypeSyntax { protected abstract bool IsInNonFirstQueryClause(TExpressionSyntax expression); protected abstract bool IsInFieldInitializer(TExpressionSyntax expression); diff --git a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb index e0b80d85ea8..a44a164b2bd 100644 --- a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb +++ b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb @@ -10,8 +10,8 @@ Imports System.Composition Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable - Friend Class VisualBasicIntroduceVariableService - Inherits AbstractIntroduceVariableService(Of VisualBasicIntroduceVariableService, ExpressionSyntax, TypeSyntax, TypeBlockSyntax, QueryExpressionSyntax) + Partial Friend Class VisualBasicIntroduceVariableService + Inherits AbstractIntroduceVariableService(Of VisualBasicIntroduceVariableService, ExpressionSyntax, TypeSyntax, TypeBlockSyntax, QueryExpressionSyntax, NameSyntax) Protected Overrides Function GetContainingExecutableBlocks(expression As ExpressionSyntax) As IEnumerable(Of SyntaxNode) Return expression.GetContainingExecutableBlocks() -- GitLab