From 3ec21f6fab20ab4c95ef1e9ec9f453a832259f37 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 23 May 2025 19:29:17 +0200 Subject: [PATCH 1/2] Fix crash with introduce local within a compilation unit --- .../CSharpInlineMethodRefactoringProvider.cs | 21 ++++--- .../CSharpIntroduceVariableService.cs | 23 ++++---- .../IntroduceVariableTests.cs | 33 +++++++++++ .../AbstractIntroduceVariableService.cs | 57 ++++++------------- .../VisualBasicIntroduceVariableService.vb | 4 ++ 5 files changed, 73 insertions(+), 65 deletions(-) diff --git a/src/Features/CSharp/Portable/CodeRefactorings/InlineMethod/CSharpInlineMethodRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/InlineMethod/CSharpInlineMethodRefactoringProvider.cs index 400a1438d45e9..65949c1b36341 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/InlineMethod/CSharpInlineMethodRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/InlineMethod/CSharpInlineMethodRefactoringProvider.cs @@ -85,17 +85,16 @@ protected override bool IsValidExpressionUnderExpressionStatement(ExpressionSynt // ; var isNullConditionalInvocationExpression = IsNullConditionalInvocationExpression(expressionNode); - return expressionNode.IsKind(SyntaxKind.InvocationExpression) - || isNullConditionalInvocationExpression - || expressionNode is AssignmentExpressionSyntax - || expressionNode.Kind() - is SyntaxKind.InvocationExpression - or SyntaxKind.ObjectCreationExpression - or SyntaxKind.PreIncrementExpression - or SyntaxKind.PreDecrementExpression - or SyntaxKind.PostIncrementExpression - or SyntaxKind.PostDecrementExpression - or SyntaxKind.AwaitExpression; + return isNullConditionalInvocationExpression + || expressionNode is AssignmentExpressionSyntax + || expressionNode.Kind() + is SyntaxKind.InvocationExpression + or SyntaxKind.ObjectCreationExpression + or SyntaxKind.PreIncrementExpression + or SyntaxKind.PreDecrementExpression + or SyntaxKind.PostIncrementExpression + or SyntaxKind.PostDecrementExpression + or SyntaxKind.AwaitExpression; } protected override bool CanBeReplacedByThrowExpression(SyntaxNode syntaxNode) diff --git a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService.cs b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService.cs index 8e783027e7240..cac25638ca343 100644 --- a/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService.cs +++ b/src/Features/CSharp/Portable/IntroduceVariable/CSharpIntroduceVariableService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Composition; @@ -11,22 +9,22 @@ using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.IntroduceVariable; +using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.IntroduceVariable; [ExportLanguageService(typeof(IIntroduceVariableService), LanguageNames.CSharp), Shared] -internal sealed partial class CSharpIntroduceVariableService : +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed partial class CSharpIntroduceVariableService() : AbstractIntroduceVariableService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpIntroduceVariableService() - { - } + protected override ISyntaxFacts SyntaxFacts => CSharpSyntaxFacts.Instance; protected override bool IsInNonFirstQueryClause(ExpressionSyntax expression) { @@ -45,10 +43,9 @@ protected override bool IsInNonFirstQueryClause(ExpressionSyntax expression) } protected override bool IsInFieldInitializer(ExpressionSyntax expression) - { - return expression.GetAncestorOrThis() - .GetAncestorOrThis() != null; - } + => expression + .GetAncestorOrThis() + .GetAncestorOrThis() != null; protected override bool IsInParameterInitializer(ExpressionSyntax expression) => expression.GetAncestorOrThis().IsParentKind(SyntaxKind.Parameter); @@ -62,7 +59,7 @@ protected override bool IsInAutoPropertyInitializer(ExpressionSyntax expression) protected override bool IsInExpressionBodiedMember(ExpressionSyntax expression) { // walk up until we find a nearest enclosing block or arrow expression. - for (SyntaxNode node = expression; node != null; node = node.Parent) + for (SyntaxNode? node = expression; node != null; node = node.Parent) { // If we are in an expression bodied member and if the expression has a block body, then, // act as if we're in a block context and not in an expression body context at all. diff --git a/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs b/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs index 34fa0af9300fa..c0fc56fb1ba84 100644 --- a/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs +++ b/src/Features/CSharpTest/IntroduceVariable/IntroduceVariableTests.cs @@ -9535,4 +9535,37 @@ void M() } """); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78680")] + public async Task FixReferenceInMemberAccessNameInTopLevel() + { + await TestAsync( + """ + C c = null; + C d = null; + Console.WriteLine([|c.c|]); + Console.WriteLine(d.c.c); + + class C + { + public C c; + } + """, + """ + C c = null; + C d = null; + + C {|Rename:c1|} = c.c; + + Console.WriteLine(c1); + Console.WriteLine(d.c.c); + + class C + { + public C c; + } + """, + parseOptions: null, + index: 1); + } } diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs index e109d42cf8e86..8a08783135d93 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; @@ -32,6 +31,8 @@ internal abstract partial class AbstractIntroduceVariableService operation is IMemberReferenceOperation { Instance.Kind: OperationKind.InstanceReference }; } protected TNode Rewrite( diff --git a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb index 1500f8128a0b6..928e170d0308c 100644 --- a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb +++ b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb @@ -9,6 +9,8 @@ Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports System.Composition +Imports Microsoft.CodeAnalysis.LanguageService +Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable @@ -20,6 +22,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Public Sub New() End Sub + Protected Overrides ReadOnly Property SyntaxFacts As ISyntaxFacts = VisualBasicSyntaxFacts.Instance + Protected Overrides Function GetContainingExecutableBlocks(expression As ExpressionSyntax) As IEnumerable(Of SyntaxNode) Return expression.GetContainingExecutableBlocks() End Function From 14844516b75a3a4b6e7afb7f7d33727eb49138df Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 23 May 2025 19:30:59 +0200 Subject: [PATCH 2/2] Sort --- .../VisualBasicIntroduceVariableService.vb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb index 928e170d0308c..541e715f7810e 100644 --- a/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb +++ b/src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.IntroduceVariable Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports System.Composition +Imports Microsoft.CodeAnalysis.IntroduceVariable Imports Microsoft.CodeAnalysis.LanguageService +Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable