提交 27633bf4 编写于 作者: G Gen Lu

Initial step to separate sync namespace refactoring and change namespace service

上级 7666140e
......@@ -8,7 +8,6 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace;
using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.SyncNamespace;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
......@@ -26,7 +25,7 @@ public abstract class CSharpSyncNamespaceTestsBase : AbstractCodeActionTest
protected override string GetLanguage() => LanguageNames.CSharp;
protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters)
=> new SyncNamespaceCodeRefactoringProvider();
=> new CSharpSyncNamespaceCodeRefactoringProvider();
protected override TestWorkspace CreateWorkspaceFromFile(string initialMarkup, TestParameters parameters)
{
......@@ -102,8 +101,8 @@ protected async Task TestMoveFileToMatchNamespace(string initialMarkup, List<str
var (actions, _) = await GetCodeActionsAsync(workspace, testOptions);
if (actions.Length > 0)
{
var renameFileAction = actions.Any(action => action is CSharpSyncNamespaceService.MoveFileCodeAction);
Assert.False(renameFileAction, "Rename File to match type code action was not expected, but shows up.");
var renameFileAction = actions.Any(action => !(action is CodeAction.SolutionChangeAction));
Assert.False(renameFileAction, "Move File to match namespace code action was not expected, but shows up.");
}
}
}
......@@ -116,7 +115,7 @@ protected async Task TestMoveFileToMatchNamespace(string initialMarkup, List<str
var results = new List<Tuple<Solution, Solution>>();
var (actions, _) = await GetCodeActionsAsync(workspace, parameters);
var moveFileActions = actions.Where(a => a is CSharpSyncNamespaceService.MoveFileCodeAction);
var moveFileActions = actions.Where(a => !(a is CodeAction.SolutionChangeAction));
foreach (var action in moveFileActions)
{
......@@ -207,7 +206,7 @@ protected async Task TestMoveFileToMatchNamespace(string initialMarkup, List<str
var (actions, _) = await GetCodeActionsAsync(workspace, testOptions);
if (actions.Length > 0)
{
var hasChangeNamespaceAction = actions.Any(action => action is CSharpSyncNamespaceService.ChangeNamespaceCodeAction);
var hasChangeNamespaceAction = actions.Any(action => action is CodeAction.SolutionChangeAction);
Assert.False(hasChangeNamespaceAction, "Change namespace to match folder action was not expected, but shows up.");
}
}
......@@ -216,7 +215,7 @@ protected async Task TestMoveFileToMatchNamespace(string initialMarkup, List<str
async Task<Tuple<Solution, Solution>> TestOperationAsync(TestParameters parameters, TestWorkspace workspace)
{
var (actions, _) = await GetCodeActionsAsync(workspace, parameters);
var changeNamespaceAction = actions.Single(a => a is CSharpSyncNamespaceService.ChangeNamespaceCodeAction);
var changeNamespaceAction = actions.Single(a => a is CodeAction.SolutionChangeAction);
var operations = await changeNamespaceAction.GetOperationsAsync(CancellationToken.None);
return ApplyOperationsAndGetSolution(workspace, operations);
......
......@@ -4,24 +4,20 @@
using System.Composition;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace;
using Microsoft.CodeAnalysis.CSharp.CodeGeneration;
using Microsoft.CodeAnalysis.ChangeNamespace;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.SyncNamespace
namespace Microsoft.CodeAnalysis.CSharp.ChangeNamespace
{
[ExportLanguageService(typeof(ISyncNamespaceService), LanguageNames.CSharp), Shared]
internal sealed class CSharpSyncNamespaceService :
AbstractSyncNamespaceService<NamespaceDeclarationSyntax, CompilationUnitSyntax, MemberDeclarationSyntax>
[ExportLanguageService(typeof(IChangeNamespaceService), LanguageNames.CSharp), Shared]
internal sealed class CSharpChangeNamespaceService :
AbstractChangeNamespaceService<NamespaceDeclarationSyntax, CompilationUnitSyntax, MemberDeclarationSyntax>
{
protected override SyntaxList<MemberDeclarationSyntax> GetMemberDeclarationsInContainer(SyntaxNode compilationUnitOrNamespaceDecl)
{
......@@ -138,72 +134,6 @@ protected override SyntaxList<MemberDeclarationSyntax> GetMemberDeclarationsInCo
return false;
}
protected override string EscapeIdentifier(string identifier)
=> identifier.EscapeIdentifier();
protected override async Task<SyntaxNode> ShouldPositionTriggerRefactoringAsync(Document document, int position, CancellationToken cancellationToken)
{
var compilationUnit = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false) as CompilationUnitSyntax;
// Here's conditions that trigger the refactoring (all have to be true in each scenario):
//
// - There's only one namespace declaration in the document and all types are declared in it:
// 1. No nested namespace declaration (even it's empty).
// 2. The cursor is on the name of the namespace declaration.
// 3. The name of the namespace is valid (i.e. no errors).
// 4. No partial type declared in the namespace. Otherwise its multiple declaration will
// end up in different namespace.
//
// - There's no namespace declaration and all types in the document are declared in global namespace:
// 1. The cursor is on the name of first declared type.
// 2. No partial type declared in the document. Otherwise its multiple declaration will
// end up in different namespace.
var triggeringNode = GetTriggeringNode(compilationUnit, position);
if (triggeringNode != null)
{
var containsPartial = await ContainsPartialTypeWithMultipleDeclarationsAsync(document, triggeringNode, cancellationToken)
.ConfigureAwait(false);
if (!containsPartial)
{
return triggeringNode;
}
}
return default;
SyntaxNode GetTriggeringNode(CompilationUnitSyntax compUnit, int pos)
{
var namespaceDecls = compilationUnit.DescendantNodes(n => n is CompilationUnitSyntax || n is NamespaceDeclarationSyntax)
.OfType<NamespaceDeclarationSyntax>().ToImmutableArray();
if (namespaceDecls.Length == 1 && compilationUnit.Members.Count == 1)
{
var namespaceDeclaration = namespaceDecls[0];
Debug.Assert(namespaceDeclaration == compilationUnit.Members[0]);
if (namespaceDeclaration.Name.Span.IntersectsWith(position)
&& namespaceDeclaration.Name.GetDiagnostics().All(diag => diag.DefaultSeverity != DiagnosticSeverity.Error))
{
return namespaceDeclaration;
}
}
else if (namespaceDecls.Length == 0)
{
var firstMemberDeclarationName = compilationUnit.Members.FirstOrDefault().GetNameToken();
if (firstMemberDeclarationName != default
&& firstMemberDeclarationName.Span.IntersectsWith(position))
{
return compilationUnit;
}
}
return null;
}
}
/// <summary>
/// Try to change the namespace declaration based on the refacoring rules:
/// - if neither declared and target namespace are "" (i.e. global namespace),
......
// 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.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.SyncNamespace
{
[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.SyncNamespace), Shared]
internal sealed class CSharpSyncNamespaceCodeRefactoringProvider
: AbstractSyncNamespaceCodeRefactoringProvider<NamespaceDeclarationSyntax, CompilationUnitSyntax, MemberDeclarationSyntax>
{
protected override async Task<SyntaxNode> ShouldPositionTriggerRefactoringAsync(Document document, int position, CancellationToken cancellationToken)
{
var compilationUnit = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false) as CompilationUnitSyntax;
// Here's conditions that trigger the refactoring (all have to be true in each scenario):
//
// - There's only one namespace declaration in the document and all types are declared in it:
// 1. No nested namespace declaration (even it's empty).
// 2. The cursor is on the name of the namespace declaration.
// 3. The name of the namespace is valid (i.e. no errors).
// 4. No partial type declared in the namespace. Otherwise its multiple declaration will
// end up in different namespace.
//
// - There's no namespace declaration and all types in the document are declared in global namespace:
// 1. The cursor is on the name of first declared type.
// 2. No partial type declared in the document. Otherwise its multiple declaration will
// end up in different namespace.
var triggeringNode = GetTriggeringNode(compilationUnit, position);
if (triggeringNode != null)
{
var containsPartial = await ContainsPartialTypeWithMultipleDeclarationsAsync(document, triggeringNode, cancellationToken)
.ConfigureAwait(false);
if (!containsPartial)
{
return triggeringNode;
}
}
return default;
SyntaxNode GetTriggeringNode(CompilationUnitSyntax compUnit, int pos)
{
var namespaceDecls = compilationUnit.DescendantNodes(n => n is CompilationUnitSyntax || n is NamespaceDeclarationSyntax)
.OfType<NamespaceDeclarationSyntax>().ToImmutableArray();
if (namespaceDecls.Length == 1 && compilationUnit.Members.Count == 1)
{
var namespaceDeclaration = namespaceDecls[0];
Debug.Assert(namespaceDeclaration == compilationUnit.Members[0]);
if (namespaceDeclaration.Name.Span.IntersectsWith(position)
&& namespaceDeclaration.Name.GetDiagnostics().All(diag => diag.DefaultSeverity != DiagnosticSeverity.Error))
{
return namespaceDeclaration;
}
}
else if (namespaceDecls.Length == 0)
{
var firstMemberDeclarationName = compilationUnit.Members.FirstOrDefault().GetNameToken();
if (firstMemberDeclarationName != default
&& firstMemberDeclarationName.Span.IntersectsWith(position))
{
return compilationUnit;
}
}
return null;
}
}
protected override SyntaxList<MemberDeclarationSyntax> GetMemberDeclarationsInContainer(SyntaxNode compilationUnitOrNamespaceDecl)
{
if (compilationUnitOrNamespaceDecl is NamespaceDeclarationSyntax namespaceDecl)
{
return namespaceDecl.Members;
}
else if (compilationUnitOrNamespaceDecl is CompilationUnitSyntax compilationUnit)
{
return compilationUnit.Members;
}
throw ExceptionUtilities.Unreachable;
}
protected override string EscapeIdentifier(string identifier)
=> identifier.EscapeIdentifier();
}
}
......@@ -14,12 +14,13 @@
namespace Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace
{
internal abstract partial class AbstractSyncNamespaceService<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax>
internal abstract partial class AbstractSyncNamespaceCodeRefactoringProvider<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax>
: CodeRefactoringProvider
where TNamespaceDeclarationSyntax : SyntaxNode
where TCompilationUnitSyntax : SyntaxNode
where TMemberDeclarationSyntax : SyntaxNode
{
internal sealed class MoveFileCodeAction : CodeAction
private class MoveFileCodeAction : CodeAction
{
private readonly State _state;
private readonly ImmutableArray<string> _newfolders;
......
......@@ -16,7 +16,8 @@
namespace Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace
{
internal abstract partial class AbstractSyncNamespaceService<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax>
internal abstract partial class AbstractSyncNamespaceCodeRefactoringProvider<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax>
: CodeRefactoringProvider
where TNamespaceDeclarationSyntax : SyntaxNode
where TCompilationUnitSyntax : SyntaxNode
where TMemberDeclarationSyntax : SyntaxNode
......@@ -153,7 +154,7 @@ private static string GetDefaultNamespace(ImmutableArray<Document> documents, IS
private static async Task<(bool shouldTrigger, string declaredNamespace)> TryGetNamespaceDeclarationAsync(
TextSpan textSpan,
ImmutableArray<Document> documents,
AbstractSyncNamespaceService<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax> service,
AbstractSyncNamespaceCodeRefactoringProvider<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax> provider,
CancellationToken cancellationToken)
{
// If the cursor location doesn't meet the requirement to trigger the refactoring in any of the documents
......@@ -167,7 +168,7 @@ private static string GetDefaultNamespace(ImmutableArray<Document> documents, IS
{
foreach (var document in documents)
{
var compilationUnitOrNamespaceDeclOpt = await service.ShouldPositionTriggerRefactoringAsync(document, textSpan.Start, cancellationToken)
var compilationUnitOrNamespaceDeclOpt = await provider.ShouldPositionTriggerRefactoringAsync(document, textSpan.Start, cancellationToken)
.ConfigureAwait(false);
if (compilationUnitOrNamespaceDeclOpt is TNamespaceDeclarationSyntax namespaceDeclaration)
......@@ -208,7 +209,7 @@ private static string GetDefaultNamespace(ImmutableArray<Document> documents, IS
}
public static async Task<State> CreateAsync(
AbstractSyncNamespaceService<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax> service,
AbstractSyncNamespaceCodeRefactoringProvider<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax> provider,
Document document,
TextSpan textSpan,
CancellationToken cancellationToken)
......@@ -237,7 +238,7 @@ private static string GetDefaultNamespace(ImmutableArray<Document> documents, IS
}
var (shouldTrigger, declaredNamespace) =
await TryGetNamespaceDeclarationAsync(textSpan, documents, service, cancellationToken).ConfigureAwait(false);
await TryGetNamespaceDeclarationAsync(textSpan, documents, provider, cancellationToken).ConfigureAwait(false);
if (!shouldTrigger)
{
......@@ -246,7 +247,7 @@ private static string GetDefaultNamespace(ImmutableArray<Document> documents, IS
// Namespace can't be changed if we can't construct a valid qualified identifier from folder names.
// In this case, we might still be able to provide refactoring to move file to new location.
var namespaceFromFolders = TryBuildNamespaceFromFolders(service, document.Folders, syntaxFacts);
var namespaceFromFolders = TryBuildNamespaceFromFolders(provider, document.Folders, syntaxFacts);
var targetNamespace = namespaceFromFolders == null
? null
: ConcatNamespace(defaultNamespace, namespaceFromFolders);
......@@ -277,7 +278,7 @@ private static string GetDefaultNamespace(ImmutableArray<Document> documents, IS
/// Create a qualified identifier as the suffix of namespace based on a list of folder names.
/// </summary>
private static string TryBuildNamespaceFromFolders(
AbstractSyncNamespaceService<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax> service,
AbstractSyncNamespaceCodeRefactoringProvider<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax> service,
IEnumerable<string> folders,
ISyntaxFactsService syntaxFacts)
{
......
// 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.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.ChangeNamespace;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using static Microsoft.CodeAnalysis.CodeActions.CodeAction;
namespace Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace
{
internal abstract partial class AbstractSyncNamespaceService<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax> :
ISyncNamespaceService
internal abstract partial class AbstractSyncNamespaceCodeRefactoringProvider<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax>
: CodeRefactoringProvider
where TNamespaceDeclarationSyntax : SyntaxNode
where TCompilationUnitSyntax : SyntaxNode
where TMemberDeclarationSyntax : SyntaxNode
{
public async Task<ImmutableArray<CodeAction>> GetRefactoringsAsync(
Document document, TextSpan textSpan, CancellationToken cancellationToken)
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var document = context.Document;
var textSpan = context.Span;
var cancellationToken = context.CancellationToken;
var state = await State.CreateAsync(this, document, textSpan, cancellationToken).ConfigureAwait(false);
if (state == null)
{
return default;
return;
}
return CreateCodeActions(this, state);
// No move file action if rootnamespace isn't a prefix of current declared namespace
if (state.RelativeDeclaredNamespace != null)
{
context.RegisterRefactorings(MoveFileCodeAction.Create(state));
}
public abstract bool TryGetReplacementReferenceSyntax(
SyntaxNode reference, ImmutableArray<string> newNamespaceParts, ISyntaxFactsService syntaxFacts, out SyntaxNode old, out SyntaxNode @new);
protected abstract string EscapeIdentifier(string identifier);
protected abstract TCompilationUnitSyntax ChangeNamespaceDeclaration(
TCompilationUnitSyntax root, ImmutableArray<string> declaredNamespaceParts, ImmutableArray<string> targetNamespaceParts);
protected abstract SyntaxList<TMemberDeclarationSyntax> GetMemberDeclarationsInContainer(SyntaxNode compilationUnitOrNamespaceDecl);
// No change namespace action if we can't construct a valid namespace from rootnamespace and folder names.
if (state.TargetNamespace != null)
{
var service = document.GetLanguageService<IChangeNamespaceService>();
var solutionChangeAction = new SolutionChangeAction(ChangeNamespaceActionTitle(state), token => service.ChangeNamespaceAsync(state.Solution, state.DocumentIds, state.DeclaredNamespace, state.TargetNamespace, token));
context.RegisterRefactoring(solutionChangeAction);
}
}
/// <summary>
/// Determine if this refactoring should be triggered based on current cursor position and if there's any partial
......@@ -55,9 +56,9 @@ internal abstract partial class AbstractSyncNamespaceService<TNamespaceDeclarati
/// </returns>
protected abstract Task<SyntaxNode> ShouldPositionTriggerRefactoringAsync(Document document, int position, CancellationToken cancellationToken);
protected static SyntaxAnnotation WarningAnnotation { get; }
= CodeActions.WarningAnnotation.Create(
FeaturesResources.Warning_colon_changing_namespace_may_produce_invalid_code_and_change_code_meaning);
protected abstract string EscapeIdentifier(string identifier);
protected abstract SyntaxList<TMemberDeclarationSyntax> GetMemberDeclarationsInContainer(SyntaxNode compilationUnitOrNamespaceDecl);
protected async Task<bool> ContainsPartialTypeWithMultipleDeclarationsAsync(
Document document, SyntaxNode compilationUnitOrNamespaceDecl, CancellationToken cancellationToken)
......@@ -81,6 +82,11 @@ internal abstract partial class AbstractSyncNamespaceService<TNamespaceDeclarati
return false;
}
private static string ChangeNamespaceActionTitle(State state)
=> state.TargetNamespace.Length == 0
? FeaturesResources.Change_to_global_namespace
: string.Format(FeaturesResources.Change_namespace_to_0, state.TargetNamespace);
/// <summary>
/// Try get the relative namespace for <paramref name="namespace"/> based on <paramref name="relativeTo"/>,
/// if <paramref name="relativeTo"/> is the containing namespace of <paramref name="namespace"/>.
......@@ -115,25 +121,5 @@ private static string GetRelativeNamespace(string relativeTo, string @namespace,
? @namespace.Substring(relativeTo.Length + 1)
: null;
}
private static ImmutableArray<CodeAction> CreateCodeActions(
AbstractSyncNamespaceService<TNamespaceDeclarationSyntax, TCompilationUnitSyntax, TMemberDeclarationSyntax> service, State state)
{
var builder = ArrayBuilder<CodeAction>.GetInstance();
// No move file action if rootnamespace isn't a prefix of current declared namespace
if (state.RelativeDeclaredNamespace != null)
{
builder.AddRange(MoveFileCodeAction.Create(state));
}
// No change namespace action if we can't construct a valid namespace from rootnamespace and folder names.
if (state.TargetNamespace != null)
{
builder.Add(new ChangeNamespaceCodeAction(service, state));
}
return builder.ToImmutableAndFree();
}
}
}
// 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.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageServices;
namespace Microsoft.CodeAnalysis.ChangeNamespace
{
internal interface IChangeNamespaceService : ILanguageService
{
Task<Solution> ChangeNamespaceAsync(Solution solution, ImmutableArray<DocumentId> documentIds, string declaredNamespace, string targetNamespace, CancellationToken cancellationToken);
bool TryGetReplacementReferenceSyntax(SyntaxNode reference, ImmutableArray<string> newNamespaceParts, ISyntaxFactsService syntaxFacts, out SyntaxNode old, out SyntaxNode @new);
}
}
// 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.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace
{
internal interface ISyncNamespaceService : ILanguageService
{
Task<ImmutableArray<CodeAction>> GetRefactoringsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken);
/// <summary>
/// Try to get a new node to replace given node, which is a reference to a top-level type declared inside the
/// namespce to be changed. If this reference is the right side of a qualified name, the new node returned would
/// be the entire qualified name. Depends on whether <paramref name="newNamespaceParts"/> is provided, the name
/// in the new node might be qualified with this new namespace instead.
/// </summary>
/// <param name="reference">A reference to a type declared inside the namespce to be changed, which is calculated
/// based on results from `SymbolFinder.FindReferencesAsync`.</param>
/// <param name="newNamespaceParts">If specified, the namespace of original reference will be replaced with given
/// namespace in the replacement node.</param>
/// <param name="old">The node to be replaced. This might be an ancestor of original </param>
/// <param name="new">The replacement node.</param>
bool TryGetReplacementReferenceSyntax(
SyntaxNode reference,
ImmutableArray<string> newNamespaceParts,
ISyntaxFactsService syntaxFacts,
out SyntaxNode old,
out SyntaxNode @new);
}
}
// 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.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace
{
[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.SyncNamespace), Shared]
internal sealed class SyncNamespaceCodeRefactoringProvider : CodeRefactoringProvider
{
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var document = context.Document;
var textSpan = context.Span;
var cancellationToken = context.CancellationToken;
var service = document.GetLanguageService<ISyncNamespaceService>();
var actions = await service.GetRefactoringsAsync(document, textSpan, cancellationToken).ConfigureAwait(false);
context.RegisterRefactorings(actions);
}
}
}
......@@ -2,16 +2,15 @@
Imports System.Collections.Immutable
Imports System.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace
Imports Microsoft.CodeAnalysis.ChangeNamespace
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.SyncNamespace
<ExportLanguageService(GetType(ISyncNamespaceService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicSyncNamespaceService
Inherits AbstractSyncNamespaceService(Of NamespaceStatementSyntax, CompilationUnitSyntax, StatementSyntax)
Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeNamespace
<ExportLanguageService(GetType(IChangeNamespaceService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicChangeNamespaceService
Inherits AbstractChangeNamespaceService(Of NamespaceStatementSyntax, CompilationUnitSyntax, StatementSyntax)
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)
......@@ -37,10 +36,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.SyncNamespace
End If
End Function
Protected Overrides Function EscapeIdentifier(identifier As String) As String
Return identifier.EscapeIdentifier()
End Function
' This is only reachable when called from a VB refacoring provider, which is not implemented yet.
Protected Overrides Function ChangeNamespaceDeclaration(root As CompilationUnitSyntax, declaredNamespaceParts As ImmutableArray(Of String), targetNamespaceParts As ImmutableArray(Of String)) As CompilationUnitSyntax
Throw ExceptionUtilities.Unreachable
......@@ -51,11 +46,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.SyncNamespace
Throw ExceptionUtilities.Unreachable
End Function
' This is only reachable when called from a VB refacoring provider, which is not implemented yet.
Protected Overrides Function ShouldPositionTriggerRefactoringAsync(document As Document, position As Integer, cancellationToken As CancellationToken) As Task(Of SyntaxNode)
Throw ExceptionUtilities.Unreachable
End Function
Private Function CreateNameSyntax(namespaceParts As ImmutableArray(Of String), index As Integer) As NameSyntax
Dim part = namespaceParts(index).EscapeIdentifier()
Dim namePiece = SyntaxFactory.IdentifierName(part)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册