diff --git a/src/EditorFeatures/CSharpTest/CodeActions/IntroduceVariable/IntroduceVariableTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/IntroduceVariable/IntroduceVariableTests.cs index 0ac81d19a13ee24e50be8dc65365cf8dfc460f54..d0b1caa7109fbb4261711f0b34615e1aca38c129 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/IntroduceVariable/IntroduceVariableTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/IntroduceVariable/IntroduceVariableTests.cs @@ -613,13 +613,12 @@ public void TestMissingOnVariableWrite() } [WorkItem(544577)] + [WorkItem(909152)] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] public void TestExpressionTLambda() { - Test( -@"using System ; using System . Linq . Expressions ; class Program { static Expression < Func < int ? , char ? > > e1 = c => [|null|] ; } ", -@"using System ; using System . Linq . Expressions ; class Program { private const char ? {|Rename:P|} = null ; static Expression < Func < int ? , char ? > > e1 = c => P ; } ", -index: 1); + TestMissing( +@"using System ; using System . Linq . Expressions ; class Program { static Expression < Func < int ? , char ? > > e1 = c => [|null|] ; } "); } [WorkItem(544915)] @@ -2328,5 +2327,23 @@ class TestClass Test(code, expected, index: 2, compareTokens: false); } + + [WorkItem(909152)] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)] + public void TestMissingOnNullLiteral() + { + TestMissing( +@"class C1 { } +class C2 { } +class Test +{ + void M() + { + C1 c1 = [|null|]; + C2 c2 = null; + } +} +"); + } } } diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceVariable/IntroduceVariableTests.vb b/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceVariable/IntroduceVariableTests.vb index fbd8a41ae896de2641ad6a346ab5617a3cde80cb..e32e2106a7e4144d723784151ac6d4f823b00de6 100644 --- a/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceVariable/IntroduceVariableTests.vb +++ b/src/EditorFeatures/VisualBasicTest/CodeActions/IntroduceVariable/IntroduceVariableTests.vb @@ -794,11 +794,10 @@ index:=1) End Sub + Public Sub TestInStatementlessConstructorParameter() - Test( -NewLines("Class C1 \n Sub New(Optional ByRef x As String = [|Nothing|]) \n End Sub \n End Class"), -NewLines("Class C1 \n Private Const {|Rename:P|} As String = Nothing \n Sub New(Optional ByRef x As String = P) \n End Sub \n End Class")) + TestMissing(NewLines("Class C1 \n Sub New(Optional ByRef x As String = [|Nothing|]) \n End Sub \n End Class")) End Sub @@ -910,12 +909,10 @@ NewLines("Module M \n Sub Main() \n Dim x = <[|x|]/> \n End Sub \n End Module")) End Sub + Public Sub TestInTernaryConditional() - Test( -NewLines("Module Program \n Sub Main(args As String()) \n Dim p As Object = Nothing \n Dim Obj1 = If(New With {.a = True}.a, p, [|Nothing|]) \n End Sub \n End Module"), -NewLines("Module Program \n Sub Main(args As String()) \n Dim p As Object = Nothing \n Const {|Rename:P1|} As Object = Nothing \n Dim Obj1 = If(New With {.a = True}.a, p, P1) \n End Sub \n End Module"), -index:=2) + TestMissing(NewLines("Module Program \n Sub Main(args As String()) \n Dim p As Object = Nothing \n Dim Obj1 = If(New With {.a = True}.a, p, [|Nothing|]) \n End Sub \n End Module")) End Sub @@ -1401,6 +1398,24 @@ End Module Test(code, expected, index:=3, compareTokens:=False) End Sub + + + Public Sub TestMissingOnNothingLiteral() + TestMissing( + +Imports System +Module Program + Sub Main(args As String()) + Main([|Nothing|]) + M(Nothing) + End Sub + + Sub M(i As Integer) + End Sub +End Module +) + End Sub + Public Sub TestIntroduceVariableTextDoesntSpanLines() diff --git a/src/Features/CSharp/IntroduceVariable/CSharpIntroduceVariableService.cs b/src/Features/CSharp/IntroduceVariable/CSharpIntroduceVariableService.cs index 404a00d6afee55b885de26d583eae721d4ae8a31..500cb7a0f309c28c51a0e6bc4358d5703dd1b048 100644 --- a/src/Features/CSharp/IntroduceVariable/CSharpIntroduceVariableService.cs +++ b/src/Features/CSharp/IntroduceVariable/CSharpIntroduceVariableService.cs @@ -96,13 +96,24 @@ protected override bool IsInAttributeArgumentInitializer(ExpressionSyntax expres return false; } + /// + /// Checks for conditions where we should not generate a variable for an expression + /// protected override bool CanIntroduceVariableFor(ExpressionSyntax expression) { + // (a) If that's the only expression in a statement. + // Otherwise we'll end up with something like "v;" which is not legal in C#. if (expression.WalkUpParentheses().IsParentKind(SyntaxKind.ExpressionStatement)) { return false; } + // (b) For Null Literals, as AllOccurences could introduce semantic errors. + if (expression.IsKind(SyntaxKind.NullLiteralExpression)) + { + return false; + } + return true; } diff --git a/src/Features/Core/IntroduceVariable/AbstractIntroduceVariableService.State.cs b/src/Features/Core/IntroduceVariable/AbstractIntroduceVariableService.State.cs index 7b2f890a4a2e5d66c5c88e36609774e2b67a1af7..24eb9f8489770ea86cef146e797d820a8b44854b 100644 --- a/src/Features/Core/IntroduceVariable/AbstractIntroduceVariableService.State.cs +++ b/src/Features/Core/IntroduceVariable/AbstractIntroduceVariableService.State.cs @@ -216,9 +216,6 @@ private TExpressionSyntax GetExpressionUnderSpan(SyntaxTree tree, TextSpan textS private bool CanIntroduceVariable( CancellationToken cancellationToken) { - // Don't generate a variable for an expression that's the only expression in a - // statement. Otherwise we'll end up with something like "v;" which is not - // legal in C#. if (!_service.CanIntroduceVariableFor(this.Expression)) { return false; diff --git a/src/Features/VisualBasic/IntroduceVariable/VisualBasicIntroduceVariableService.vb b/src/Features/VisualBasic/IntroduceVariable/VisualBasicIntroduceVariableService.vb index 709e4d69be01d843bd35e897a26fc2f08537eefe..783520419ce3f4525e662e93f7f6fff8b2ebd7b1 100644 --- a/src/Features/VisualBasic/IntroduceVariable/VisualBasicIntroduceVariableService.vb +++ b/src/Features/VisualBasic/IntroduceVariable/VisualBasicIntroduceVariableService.vb @@ -77,6 +77,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Return False End If + ' For Nothing Literals, AllOccurences could introduce semantic errors. + If expression.IsKind(SyntaxKind.NothingLiteralExpression) Then + Return False + End If + Return True End Function