diff --git a/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs b/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs index b935477b81d21..b821b64c58ad0 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/SyncNamespace/SyncNamespaceTests_ChangeNamespace.cs @@ -1448,6 +1448,72 @@ class Class1 await TestChangeNamespaceAsync(code, expectedSourceOriginal); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/34707")] + public async Task ChangeFromGlobalNamespace_DoNotSimplifyUnrelatedCode() + { + var defaultNamespace = "A"; + var (folder, filePath) = CreateDocumentFilePath(["B", "C"], "File1.cs"); + var documentPath2 = CreateDocumentFilePath([], "File2.cs"); + var code = + $$""" + + + + class [||]Class1 + { + private A.Class2 c2; + private A.B.Class3 c3; + private A.B.C.Class4 c4; + + void M1() + { + int i = 0; + // This cast should not be touched. + int j = (int)i; + } + } + + + namespace A + { + class Class2{} + + namespace B + { + class Class3 {} + + namespace C + { + class Class4 {} + } + } + } + + + """; + + var expectedSourceOriginal = + """ + namespace A.B.C + { + class Class1 + { + private Class2 c2; + private Class3 c3; + private Class4 c4; + + void M1() + { + int i = 0; + // This cast should not be touched. + int j = (int)i; + } + } + } + """; + await TestChangeNamespaceAsync(code, expectedSourceOriginal); + } + [Fact] public async Task ChangeFromGlobalNamespace_ChangeUsingsInMultipleContainers() { @@ -2169,7 +2235,7 @@ namespace {{defaultNamespace}} { public static class Extensions { - public static bool Foo(this string s) => true; + public static bool Foo(this String s) => true; } } """; diff --git a/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpChangeNamespaceService.cs b/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpChangeNamespaceService.cs index 62b99076757e4..e5e5f299ddb32 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpChangeNamespaceService.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpChangeNamespaceService.cs @@ -13,11 +13,13 @@ using Microsoft.CodeAnalysis.ChangeNamespace; using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -27,14 +29,18 @@ namespace Microsoft.CodeAnalysis.CSharp.ChangeNamespace; using static SyntaxFactory; [ExportLanguageService(typeof(IChangeNamespaceService), LanguageNames.CSharp), Shared] -internal sealed class CSharpChangeNamespaceService : - AbstractChangeNamespaceService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpChangeNamespaceService() : + AbstractChangeNamespaceService< + CompilationUnitSyntax, + MemberDeclarationSyntax, + BaseNamespaceDeclarationSyntax, + NameSyntax, + SimpleNameSyntax, + QualifiedCrefSyntax> { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpChangeNamespaceService() - { - } + public override AbstractReducer NameReducer { get; } = new CSharpNameReducer(); protected override async Task> GetValidContainersFromAllLinkedDocumentsAsync( Document document, diff --git a/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpSyncNamespaceCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpSyncNamespaceCodeRefactoringProvider.cs index 0dcbb8db822a5..2ebf4708298b3 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpSyncNamespaceCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/SyncNamespace/CSharpSyncNamespaceCodeRefactoringProvider.cs @@ -17,15 +17,11 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.SyncNamespace; [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.SyncNamespace), Shared] -internal sealed class CSharpSyncNamespaceCodeRefactoringProvider - : AbstractSyncNamespaceCodeRefactoringProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class CSharpSyncNamespaceCodeRefactoringProvider() + : AbstractSyncNamespaceCodeRefactoringProvider { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public CSharpSyncNamespaceCodeRefactoringProvider() - { - } - protected override async Task TryGetApplicableInvocationNodeAsync(Document document, TextSpan span, CancellationToken cancellationToken) { if (!span.IsEmpty) @@ -58,7 +54,4 @@ public CSharpSyncNamespaceCodeRefactoringProvider() return null; } - - protected override string EscapeIdentifier(string identifier) - => identifier.EscapeIdentifier(); } diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs index d78c5d574e0e7..2684264135022 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs @@ -34,7 +34,7 @@ namespace Microsoft.CodeAnalysis.ChangeNamespace; /// /// This intermediate class is used to hide method `TryGetReplacementReferenceSyntax` from . /// -internal abstract class AbstractChangeNamespaceService : IChangeNamespaceService +internal abstract partial class AbstractChangeNamespaceService : IChangeNamespaceService { public abstract Task CanChangeNamespaceAsync(Document document, SyntaxNode container, CancellationToken cancellationToken); @@ -42,6 +42,8 @@ internal abstract class AbstractChangeNamespaceService : IChangeNamespaceService public abstract Task TryChangeTopLevelNamespacesAsync(Document document, string targetNamespace, CancellationToken cancellationToken); + public abstract AbstractReducer NameReducer { get; } + /// /// Try to get a new node to replace given node, which is a reference to a top-level type declared inside the /// namespace to be changed. If this reference is the right side of a qualified name, the new node returned would @@ -57,11 +59,20 @@ internal abstract class AbstractChangeNamespaceService : IChangeNamespaceService public abstract bool TryGetReplacementReferenceSyntax(SyntaxNode reference, ImmutableArray newNamespaceParts, ISyntaxFactsService syntaxFacts, [NotNullWhen(returnValue: true)] out SyntaxNode? old, [NotNullWhen(returnValue: true)] out SyntaxNode? @new); } -internal abstract class AbstractChangeNamespaceService +internal abstract partial class AbstractChangeNamespaceService< + TCompilationUnitSyntax, + TMemberDeclarationSyntax, + TNamespaceDeclarationSyntax, + TNameSyntax, + TSimpleNameSyntax, + TCrefSyntax> : AbstractChangeNamespaceService - where TNamespaceDeclarationSyntax : SyntaxNode where TCompilationUnitSyntax : SyntaxNode where TMemberDeclarationSyntax : SyntaxNode + where TNamespaceDeclarationSyntax : TMemberDeclarationSyntax + where TNameSyntax : SyntaxNode + where TSimpleNameSyntax : TNameSyntax + where TCrefSyntax : SyntaxNode { private static readonly char[] s_dotSeparator = ['.']; @@ -125,9 +136,7 @@ public override async Task CanChangeNamespaceAsync(Document document, Synt var originalNamespaceDeclarations = await GetTopLevelNamespacesAsync(document, cancellationToken).ConfigureAwait(false); if (originalNamespaceDeclarations.Length == 0) - { return null; - } var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var originalNamespaceName = semanticModel.GetRequiredDeclaredSymbol(originalNamespaceDeclarations.First(), cancellationToken).ToDisplayString(); @@ -139,12 +148,10 @@ public override async Task CanChangeNamespaceAsync(Document document, Synt for (var i = 0; i < originalNamespaceDeclarations.Length; i++) { var namespaceName = semanticModel.GetRequiredDeclaredSymbol(originalNamespaceDeclarations[i], cancellationToken).ToDisplayString(); + + // Skip all namespaces that didn't match the original namespace name that we were syncing. if (namespaceName != originalNamespaceName) - { - // Skip all namespaces that didn't match the original namespace name that - // we were syncing. continue; - } syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -194,16 +201,12 @@ public override async Task ChangeNamespaceAsync( var containersFromAllDocuments = await GetValidContainersFromAllLinkedDocumentsAsync(document, container, cancellationToken).ConfigureAwait(false); if (containersFromAllDocuments.IsDefault) - { return solution; - } // No action required if declared namespace already matches target. var declaredNamespace = GetDeclaredNamespace(container); if (syntaxFacts.StringComparer.Equals(targetNamespace, declaredNamespace)) - { return solution; - } // Annotate the container nodes so we can still find and modify them after syntax tree has changed. var annotatedSolution = await AnnotateContainersAsync(solution, containersFromAllDocuments, cancellationToken).ConfigureAwait(false); @@ -222,9 +225,8 @@ public override async Task ChangeNamespaceAsync( foreach (var documentId in documentIds) { - var (newSolution, refDocumentIds) = - await ChangeNamespaceInSingleDocumentAsync(solutionAfterNamespaceChange, documentId, declaredNamespace, targetNamespace, cancellationToken) - .ConfigureAwait(false); + var (newSolution, refDocumentIds) = await ChangeNamespaceInSingleDocumentAsync( + solutionAfterNamespaceChange, documentId, declaredNamespace, targetNamespace, cancellationToken).ConfigureAwait(false); solutionAfterNamespaceChange = newSolution; referenceDocuments.AddRange(refDocumentIds); } @@ -463,8 +465,8 @@ private static SyntaxNode CreateImport(SyntaxGenerator syntaxGenerator, string n } } - var documentWithNewNamespace = await FixDeclarationDocumentAsync(document, refLocationsInCurrentDocument, oldNamespace, newNamespace, cancellationToken) - .ConfigureAwait(false); + var documentWithNewNamespace = await FixDeclarationDocumentAsync( + document, refLocationsInCurrentDocument, oldNamespace, newNamespace, cancellationToken).ConfigureAwait(false); var solutionWithChangedNamespace = documentWithNewNamespace.Project.Solution; var refLocationsInSolution = refLocationsInOtherDocuments @@ -501,15 +503,6 @@ private static SyntaxNode CreateImport(SyntaxGenerator syntaxGenerator, string n return (solutionWithFixedReferences, refLocationGroups.SelectAsArray(g => g.Key)); } - private readonly struct LocationForAffectedSymbol(ReferenceLocation location, bool isReferenceToExtensionMethod) - { - public ReferenceLocation ReferenceLocation { get; } = location; - - public bool IsReferenceToExtensionMethod { get; } = isReferenceToExtensionMethod; - - public Document Document => ReferenceLocation.Document; - } - private static async Task> FindReferenceLocationsForSymbolAsync( Document document, ISymbol symbol, CancellationToken cancellationToken) { @@ -631,9 +624,49 @@ private async Task FixDeclarationDocumentAsync( var services = documentWithAddedImports.Project.Solution.Services; root = Formatter.Format(root, Formatter.Annotation, services, documentOptions.FormattingOptions, cancellationToken); - root = root.WithAdditionalAnnotations(Simplifier.Annotation); + using var _ = PooledHashSet.GetInstance(out var allNamespaceNameParts); + allNamespaceNameParts.AddRange(oldNamespaceParts); + allNamespaceNameParts.AddRange(newNamespaceParts); + + var syntaxFacts = document.GetRequiredLanguageService(); + root = AddSimplifierAnnotationToPotentialReferences(syntaxFacts, root, allNamespaceNameParts); + var formattedDocument = documentWithAddedImports.WithSyntaxRoot(root); - return await Simplifier.ReduceAsync(formattedDocument, documentOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); + return await SimplifyTypeNamesAsync(formattedDocument, documentOptions, cancellationToken).ConfigureAwait(false); + } + + private static SyntaxNode AddSimplifierAnnotationToPotentialReferences( + ISyntaxFactsService syntaxFacts, SyntaxNode root, HashSet allNamespaceNameParts) + { + // Find all identifiers in this tree that use at least one of the namespace names of either the old or new + // namespace. Mark those as needing potential complexification/simplification to preserve meaning. + // + // Note: we could go further here and actually bind these nodes to make sure they are actually references + // to one of the namespaces in question. But that doesn't seem super necessary as the chance that these names + // are actually to something else *and* they would reduce without issue seems very low. This can be revisited + // if we get feedback on this. + + using var _ = PooledHashSet.GetInstance(out var namesToUpdate); + foreach (var descendent in root.DescendantNodes(descendIntoTrivia: true)) + { + if (descendent is TSimpleNameSyntax simpleName && + allNamespaceNameParts.Contains(syntaxFacts.GetIdentifierOfSimpleName(simpleName).ValueText)) + { + namesToUpdate.Add(GetHighestNameOrCref(simpleName)); + } + } + + return root.ReplaceNodes( + namesToUpdate, + (_, current) => current.WithAdditionalAnnotations(Simplifier.Annotation)); + + static SyntaxNode GetHighestNameOrCref(TNameSyntax name) + { + while (name.Parent is TNameSyntax parentName) + name = parentName; + + return name.Parent is TCrefSyntax ? name.Parent : name; + } } private static async Task FixReferencingDocumentAsync( @@ -651,9 +684,8 @@ private static async Task FixReferencingDocumentAsync( var newNamespaceParts = GetNamespaceParts(newNamespace); - var (documentWithRefFixed, containers) = - await FixReferencesAsync(document, changeNamespaceService, addImportService, refLocations, newNamespaceParts, cancellationToken) - .ConfigureAwait(false); + var (documentWithRefFixed, containers) = await FixReferencesAsync( + document, changeNamespaceService, addImportService, refLocations, newNamespaceParts, cancellationToken).ConfigureAwait(false); var documentOptions = await document.GetCodeCleanupOptionsAsync(cancellationToken).ConfigureAwait(false); @@ -666,10 +698,24 @@ await FixReferencesAsync(document, changeNamespaceService, addImportService, ref cancellationToken).ConfigureAwait(false); // Need to invoke formatter explicitly since we are doing the diff merge ourselves. - var formattedDocument = await Formatter.FormatAsync(documentWithAdditionalImports, Formatter.Annotation, documentOptions.FormattingOptions, cancellationToken) - .ConfigureAwait(false); + var formattedDocument = await Formatter.FormatAsync( + documentWithAdditionalImports, Formatter.Annotation, documentOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); - return await Simplifier.ReduceAsync(formattedDocument, documentOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); + return await SimplifyTypeNamesAsync(formattedDocument, documentOptions, cancellationToken).ConfigureAwait(false); + } + + private static async Task SimplifyTypeNamesAsync( + Document document, CodeCleanupOptions documentOptions, CancellationToken cancellationToken) + { + var changeNamespaceService = document.GetRequiredLanguageService(); + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var service = document.GetRequiredLanguageService(); + return await service.ReduceAsync( + document, + [new TextSpan(0, text.Length)], + documentOptions.SimplifierOptions, + [changeNamespaceService.NameReducer], + cancellationToken).ConfigureAwait(false); } /// @@ -708,9 +754,7 @@ await FixReferencesAsync(document, changeNamespaceService, addImportService, ref // it will be handled properly because it is one of the reference to the type symbol. Otherwise, we don't // attempt to make a potential fix, and user might end up with errors as a result. if (refLoc.ReferenceLocation.Alias != null) - { continue; - } // Other documents in the solution might have changed after we calculated those ReferenceLocation, // so we can't trust anything to be still up-to-date except their spans. @@ -743,9 +787,7 @@ await FixReferencesAsync(document, changeNamespaceService, addImportService, ref } foreach (var container in containers) - { editor.TrackNode(container); - } var fixedDocument = editor.GetChangedDocument(); root = await fixedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -858,7 +900,7 @@ private SyntaxNodeSpanStartComparer() { } - public static SyntaxNodeSpanStartComparer Instance { get; } = new SyntaxNodeSpanStartComparer(); + public static SyntaxNodeSpanStartComparer Instance { get; } = new(); public int Compare(SyntaxNode? x, SyntaxNode? y) { diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs index 02e2bb37a7f5a..aa2df2e5388e1 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs @@ -17,6 +17,18 @@ internal abstract partial class AbstractSyncNamespaceCodeRefactoringProvider + /// Try to get the node that can be used to trigger the refactoring based on current cursor position. + /// + /// + /// (1) a node of type node, if cursor in the name and it's the + /// only namespace declaration in the document. + /// (2) a node of type node, if the cursor is in the name of first + /// declaration in global namespace and there's no namespace declaration in this document. + /// (3) otherwise, null. + /// + protected abstract Task TryGetApplicableInvocationNodeAsync(Document document, TextSpan span, CancellationToken cancellationToken); + public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; @@ -28,9 +40,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var state = await State.CreateAsync(this, document, textSpan, cancellationToken).ConfigureAwait(false); if (state == null) - { return; - } // No move file action if rootnamespace isn't a prefix of current declared namespace if (state.RelativeDeclaredNamespace != null) @@ -79,18 +89,4 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte context.RegisterRefactoring(solutionChangeAction, textSpan); } } - - /// - /// Try to get the node that can be used to trigger the refactoring based on current cursor position. - /// - /// - /// (1) a node of type node, if cursor in the name and it's the - /// only namespace declaration in the document. - /// (2) a node of type node, if the cursor is in the name of first - /// declaration in global namespace and there's no namespace declaration in this document. - /// (3) otherwise, null. - /// - protected abstract Task TryGetApplicableInvocationNodeAsync(Document document, TextSpan span, CancellationToken cancellationToken); - - protected abstract string EscapeIdentifier(string identifier); } diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/LocationForAffectedSymbol.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/LocationForAffectedSymbol.cs new file mode 100644 index 0000000000000..7832d47981ee0 --- /dev/null +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/LocationForAffectedSymbol.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.FindSymbols; + +namespace Microsoft.CodeAnalysis.ChangeNamespace; + +internal abstract partial class AbstractChangeNamespaceService +{ + protected readonly struct LocationForAffectedSymbol(ReferenceLocation location, bool isReferenceToExtensionMethod) + { + public ReferenceLocation ReferenceLocation { get; } = location; + + public bool IsReferenceToExtensionMethod { get; } = isReferenceToExtensionMethod; + + public Document Document => ReferenceLocation.Document; + } +} diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/SyncNamespace/VisualBasicChangeNamespaceService.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/SyncNamespace/VisualBasicChangeNamespaceService.vb index 41fd0cc2fa77b..a333205724464 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/SyncNamespace/VisualBasicChangeNamespaceService.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/SyncNamespace/VisualBasicChangeNamespaceService.vb @@ -8,19 +8,29 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.ChangeNamespace Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.LanguageService +Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeNamespace - Friend Class VisualBasicChangeNamespaceService - Inherits AbstractChangeNamespaceService(Of NamespaceStatementSyntax, CompilationUnitSyntax, StatementSyntax) + Friend NotInheritable Class VisualBasicChangeNamespaceService + Inherits AbstractChangeNamespaceService(Of + CompilationUnitSyntax, + StatementSyntax, + NamespaceStatementSyntax, + NameSyntax, + SimpleNameSyntax, + CrefReferenceSyntax) Public Sub New() End Sub + Public Overrides ReadOnly Property NameReducer As AbstractReducer = New VisualBasicNameReducer() + Public Overrides Function TryGetReplacementReferenceSyntax(reference As SyntaxNode, newNamespaceParts As ImmutableArray(Of String), syntaxFacts As ISyntaxFactsService, ByRef old As SyntaxNode, ByRef [new] As SyntaxNode) As Boolean Dim nameRef = TryCast(reference, SimpleNameSyntax) old = nameRef @@ -41,7 +51,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeNamespace [new] = [new].WithTriviaFrom(old) - ElseIf syntaxFacts.IsNameOfsimpleMemberAccessExpression(nameRef) Then + ElseIf syntaxFacts.IsNameOfSimpleMemberAccessExpression(nameRef) Then old = nameRef.Parent If IsGlobalNamespace(newNamespaceParts) Then [new] = SyntaxFactory.SimpleMemberAccessExpression(SyntaxFactory.GlobalName(), nameRef.WithoutTrivia()) diff --git a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNameReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNameReducer.cs index ab1209fb94670..97cab33d7bedd 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNameReducer.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Reducers/CSharpNameReducer.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.Threading; using Microsoft.CodeAnalysis.CSharp.Simplification.Simplifiers; diff --git a/src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs b/src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs index 971b57a606e9a..491404e0e62d2 100644 --- a/src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs +++ b/src/Workspaces/Core/Portable/ChangeNamespace/IChangeNamespaceService.cs @@ -5,11 +5,14 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.ChangeNamespace; internal interface IChangeNamespaceService : ILanguageService { + AbstractReducer NameReducer { get; } + /// /// Determine whether we can change the namespace for given in the document. /// Linked documents are not supported, except for a regular document in a multi-targeting project, diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicNameReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicNameReducer.vb index 6ce8c2a21f676..caca8e31a6be3 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicNameReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicNameReducer.vb @@ -5,7 +5,6 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Formatting -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Text diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb index 5d59bc8eeecd9..f7b6cd943910b 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb @@ -21,12 +21,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Private Sub New() End Sub - Public Overrides Function TrySimplify(expression As ExpressionSyntax, - semanticModel As SemanticModel, - options As VisualBasicSimplifierOptions, - ByRef replacementNode As ExpressionSyntax, - ByRef issueSpan As TextSpan, - cancellationToken As CancellationToken) As Boolean + Public Overrides Function TrySimplify( + expression As ExpressionSyntax, + semanticModel As SemanticModel, + options As VisualBasicSimplifierOptions, + ByRef replacementNode As ExpressionSyntax, + ByRef issueSpan As TextSpan, + cancellationToken As CancellationToken) As Boolean Dim memberAccessExpression = TryCast(expression, MemberAccessExpressionSyntax) If memberAccessExpression?.Expression?.Kind() = SyntaxKind.MeExpression Then