提交 a31ac79d 编写于 作者: A Andrew Hall (METAL)

Add new function to IMoveTypeService

上级 0196c9d5
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings.MoveType;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeActions.MoveType
{
public partial class MoveTypeTests : CSharpMoveTypeTestsBase
{
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_SingleItem()
{
var code =
@"namespace N1
{
class [||]Class1
{
}
}";
var expected =
@"namespace N1
{
class Class1
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemAtTop()
{
var code =
@"namespace N1
{
class [||]Class1
{
}
class Class2
{
}
}";
var expected =
@"namespace N1
{
class Class1
{
}
}
namespace N1
{
class Class2
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemAtTopWithComments()
{
var code =
@"namespace N1
{
// Class1 Comment
class [||]Class1
{
}
// Class2 Comment
class Class2
{
}
}";
var expected =
@"namespace N1
{
// Class1 Comment
class Class1
{
}
}
namespace N1
{
// Class2 Comment
class Class2
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemAtTopWithXmlComments()
{
var code =
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class [||]Class1
{
}
/// <summary>
/// Class2 summary
/// </summary>
class Class2
{
}
}";
var expected =
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class Class1
{
}
}
namespace N1
{
/// <summary>
/// Class2 summary
/// </summary>
class Class2
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemAtBottom()
{
var code =
@"namespace N1
{
class Class1
{
}
class [||]Class2
{
}
}";
var expected =
@"namespace N1
{
class Class1
{
}
}
namespace N1
{
class Class2
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemAtBottomWithComments()
{
var code =
@"namespace N1
{
// Class1 comment
class Class1
{
}
// Class2 comment
class [||]Class2
{
}
}";
var expected =
@"namespace N1
{
// Class1 comment
class Class1
{
}
}
namespace N1
{
// Class2 comment
class Class2
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemAtBottomWithXmlComments()
{
var code =
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class Class1
{
}
/// <summary>
/// Class2 summary
/// </summary>
class [||]Class2
{
}
}";
var expected =
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class Class1
{
}
}
namespace N1
{
/// <summary>
/// Class2 summary
/// </summary>
class Class2
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemInMiddle()
{
var code =
@"namespace N1
{
class Class1
{
}
class Class2
{
}
class [||]Class3
{
}
class Class4
{
}
class Class5
{
}
}";
var expected =
@"namespace N1
{
class Class1
{
}
class Class2
{
}
}
namespace N1
{
class Class3
{
}
}
namespace N1
{
class Class4
{
}
class Class5
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemInMiddleWithComments()
{
var code =
@"namespace N1
{
// Class1 comment
class Class1
{
}
// Class2 comment
class Class2
{
}
// Class3 comment
class [||]Class3
{
}
// Class4 comment
class Class4
{
}
// Class5 comment
class Class5
{
}
}";
var expected =
@"namespace N1
{
// Class1 comment
class Class1
{
}
// Class2 comment
class Class2
{
}
}
namespace N1
{
// Class3 comment
class Class3
{
}
}
namespace N1
{
// Class4 comment
class Class4
{
}
// Class5 comment
class Class5
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemInMiddleWithXmlComments()
{
var code =
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class Class1
{
}
/// <summary>
/// Class2 summary
/// </summary>
class Class2
{
}
/// <summary>
/// Class3 summary
/// </summary>
class [||]Class3
{
}
/// <summary>
/// Class4 summary
/// </summary>
class Class4
{
}
/// <summary>
/// Class5 summary
/// </summary>
class Class5
{
}
}";
var expected =
@"namespace N1
{
/// <summary>
/// Class1 summary
/// </summary>
class Class1
{
}
/// <summary>
/// Class2 summary
/// </summary>
class Class2
{
}
}
namespace N1
{
/// <summary>
/// Class3 summary
/// </summary>
class Class3
{
}
}
namespace N1
{
/// <summary>
/// Class4 summary
/// </summary>
class Class4
{
}
/// <summary>
/// Class5 summary
/// </summary>
class Class5
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemInMiddleWithInterface()
{
var code =
@"namespace N1
{
// Class1 comment
class Class1
{
}
// IClass3 comment
interface IClass3
{
void DoStuff();
}
// Class3 comment
class [||]Class3 : IClass3
{
public void DoStuff() { }
}
// Class4 comment
class Class4
{
}
// Class5 comment
class Class5
{
}
}";
var expected =
@"namespace N1
{
// Class1 comment
class Class1
{
}
// IClass3 comment
interface IClass3
{
void DoStuff();
}
}
namespace N1
{
// Class3 comment
class Class3 : IClass3
{
public void DoStuff() { }
}
}
namespace N1
{
// Class4 comment
class Class4
{
}
// Class5 comment
class Class5
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_TwoItemsInDifferentNamespace()
{
var code =
@"namespace N1
{
class [||]Class1
{
}
}
namespace N2
{
class Class2
{
}
}";
var expected =
@"namespace N1
{
class Class1
{
}
}
namespace N2
{
class Class2
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveType)]
public Task MoveType_NamespaceScope_ItemsInDifferentNamespace()
{
var code =
@"namespace N1
{
interface IClass1
{
}
class [||]Class1 : IClass1
{
}
}
namespace N2
{
class Class2
{
}
}";
var expected =
@"namespace N1
{
interface IClass1
{
}
}
namespace N1
{
class Class1 : IClass1
{
}
}
namespace N2
{
class Class2
{
}
}";
return TestNamespaceMove(code, expected, expectOperation: false);
}
private async Task TestNamespaceMove(string originalCode, string expectedCode, bool expectOperation = true)
{
using (var workspace = CreateWorkspaceFromOptions(originalCode, default))
{
var documentToModifyId = workspace.Documents[0].Id;
var textSpan = workspace.Documents[0].SelectedSpans[0];
var documentToModify = workspace.CurrentSolution.GetDocument(documentToModifyId);
var moveTypeService = documentToModify.GetLanguageService<IMoveTypeService>();
Assert.NotNull(moveTypeService);
var refactorings = await moveTypeService.GetRefactoringAsync(documentToModify, textSpan, MoveTypeOperationKind.MoveTypeScope, CancellationToken.None).ConfigureAwait(false);
Assert.NotEmpty(refactorings);
foreach (var refactoring in refactorings)
{
Assert.True(refactoring.IsApplicable(workspace));
var operations = await refactoring.GetOperationsAsync(CancellationToken.None).ConfigureAwait(false);
if (expectOperation)
{
Assert.NotEmpty(operations);
}
foreach (var operation in operations)
{
operation.Apply(workspace, CancellationToken.None);
}
}
var modifiedDocument = workspace.CurrentSolution.GetDocument(documentToModifyId);
var formattedDocument = await Formatter.FormatAsync(modifiedDocument).ConfigureAwait(false);
var formattedText = await formattedDocument.GetTextAsync().ConfigureAwait(false);
Assert.Equal(expectedCode, formattedText.ToString());
}
}
}
}
...@@ -15,14 +15,14 @@ private class MoveTypeCodeAction : CodeAction ...@@ -15,14 +15,14 @@ private class MoveTypeCodeAction : CodeAction
{ {
private readonly State _state; private readonly State _state;
private readonly TService _service; private readonly TService _service;
private readonly OperationKind _operationKind; private readonly MoveTypeOperationKind _operationKind;
private readonly string _title; private readonly string _title;
private readonly string _fileName; private readonly string _fileName;
public MoveTypeCodeAction( public MoveTypeCodeAction(
TService service, TService service,
State state, State state,
OperationKind operationKind, MoveTypeOperationKind operationKind,
string fileName) string fileName)
{ {
_state = state; _state = state;
...@@ -36,12 +36,14 @@ private string CreateDisplayText() ...@@ -36,12 +36,14 @@ private string CreateDisplayText()
{ {
switch (_operationKind) switch (_operationKind)
{ {
case OperationKind.MoveType: case MoveTypeOperationKind.MoveType:
return string.Format(FeaturesResources.Move_type_to_0, _fileName); return string.Format(FeaturesResources.Move_type_to_0, _fileName);
case OperationKind.RenameType: case MoveTypeOperationKind.RenameType:
return string.Format(FeaturesResources.Rename_type_to_0, _state.DocumentNameWithoutExtension); return string.Format(FeaturesResources.Rename_type_to_0, _state.DocumentNameWithoutExtension);
case OperationKind.RenameFile: case MoveTypeOperationKind.RenameFile:
return string.Format(FeaturesResources.Rename_file_to_0, _fileName); return string.Format(FeaturesResources.Rename_file_to_0, _fileName);
case MoveTypeOperationKind.MoveTypeScope:
return string.Empty;
default: default:
throw ExceptionUtilities.UnexpectedValue(_operationKind); throw ExceptionUtilities.UnexpectedValue(_operationKind);
} }
...@@ -59,12 +61,14 @@ private Editor GetEditor(CancellationToken cancellationToken) ...@@ -59,12 +61,14 @@ private Editor GetEditor(CancellationToken cancellationToken)
{ {
switch (_operationKind) switch (_operationKind)
{ {
case OperationKind.MoveType: case MoveTypeOperationKind.MoveType:
return new MoveTypeEditor(_service, _state, _fileName, cancellationToken); return new MoveTypeEditor(_service, _state, _fileName, cancellationToken);
case OperationKind.RenameType: case MoveTypeOperationKind.RenameType:
return new RenameTypeEditor(_service, _state, _fileName, cancellationToken); return new RenameTypeEditor(_service, _state, _fileName, cancellationToken);
case OperationKind.RenameFile: case MoveTypeOperationKind.RenameFile:
return new RenameFileEditor(_service, _state, _fileName, cancellationToken); return new RenameFileEditor(_service, _state, _fileName, cancellationToken);
case MoveTypeOperationKind.MoveTypeScope:
return new MoveTypeScopeEditor(_service, _state, _fileName, cancellationToken);
default: default:
throw ExceptionUtilities.UnexpectedValue(_operationKind); throw ExceptionUtilities.UnexpectedValue(_operationKind);
} }
...@@ -76,8 +80,10 @@ internal override bool IsApplicable(Workspace workspace) ...@@ -76,8 +80,10 @@ internal override bool IsApplicable(Workspace workspace)
{ {
switch (_operationKind) switch (_operationKind)
{ {
case OperationKind.RenameFile: case MoveTypeOperationKind.RenameFile:
return workspace.CanRenameFilesDuringCodeActions(_state.SemanticDocument.Document.Project); return workspace.CanRenameFilesDuringCodeActions(_state.SemanticDocument.Document.Project);
case MoveTypeOperationKind.MoveTypeScope:
return _state.TypeNode.Parent is TNamespaceDeclarationSyntax;
} }
return true; return true;
......
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType
{
internal abstract partial class AbstractMoveTypeService<TService, TTypeDeclarationSyntax, TNamespaceDeclarationSyntax, TMemberDeclarationSyntax, TCompilationUnitSyntax>
{
/// <summary>
/// Editor that takes a type in a scope and creates a scope beside it. For example, if the type is contained within a namespace
/// it will evaluate if the namespace scope needs to be closed and reopened to create a new scope.
/// </summary>
private class MoveTypeScopeEditor : Editor
{
public MoveTypeScopeEditor(TService service, State state, string fileName, CancellationToken cancellationToken)
: base(service, state, fileName, cancellationToken)
{
}
internal override async Task<ImmutableArray<CodeActionOperation>> GetOperationsAsync()
{
var node = State.TypeNode;
var documentToEdit = State.SemanticDocument.Document;
var parent = node.Parent;
if (parent == null)
{
return ImmutableArray<CodeActionOperation>.Empty;
}
CodeActionOperation operationToPerform = null;
switch (parent)
{
case TNamespaceDeclarationSyntax namespaceDeclaration:
operationToPerform = await GetNamespaceScopeOperationAsync(namespaceDeclaration, node, documentToEdit, CancellationToken.None).ConfigureAwait(false);
break;
case TTypeDeclarationSyntax _:
Debug.Assert(false, "Moving a nested type is not supported");
break;
}
if (operationToPerform == null)
{
return ImmutableArray<CodeActionOperation>.Empty;
}
return ImmutableArray.Create(operationToPerform);
}
private async Task<CodeActionOperation> GetNamespaceScopeOperationAsync(TNamespaceDeclarationSyntax namespaceDeclaration, TTypeDeclarationSyntax typeToMove, Document documentToEdit, CancellationToken cancellationToken)
{
var syntaxFactsService = documentToEdit.GetLanguageService<ISyntaxFactsService>();
var childNodes = syntaxFactsService.GetMembersOfNamespaceDeclaration(namespaceDeclaration);
if (childNodes.Count <= 1)
{
return null;
}
var editor = await DocumentEditor.CreateAsync(documentToEdit, cancellationToken).ConfigureAwait(false);
var syntaxGenerator = editor.Generator;
var index = childNodes.IndexOf(typeToMove);
var itemsBefore = index > 0 ? childNodes.Take(index) : Enumerable.Empty<SyntaxNode>();
var itemsAfter = index < childNodes.Count - 1 ? childNodes.Skip(index + 1) : Enumerable.Empty<SyntaxNode>();
var name = syntaxFactsService.GetDisplayName(namespaceDeclaration, DisplayNameOptions.IncludeNamespaces);
var newNamespaceDeclaration = syntaxGenerator.NamespaceDeclaration(name, WithElasticTrivia(typeToMove));
editor.RemoveNode(typeToMove, SyntaxRemoveOptions.KeepNoTrivia);
if (itemsBefore.Any() && itemsAfter.Any())
{
var itemsAfterNamespaceDeclaration = syntaxGenerator.NamespaceDeclaration(name, WithElasticTrivia(itemsAfter));
foreach (var nodeToRemove in itemsAfter)
{
editor.RemoveNode(nodeToRemove, SyntaxRemoveOptions.KeepNoTrivia);
}
editor.InsertAfter(namespaceDeclaration, new[] { newNamespaceDeclaration, itemsAfterNamespaceDeclaration });
}
else if (itemsBefore.Any())
{
editor.InsertAfter(namespaceDeclaration, newNamespaceDeclaration);
var nodeToCleanup = itemsBefore.Last();
editor.ReplaceNode(nodeToCleanup, WithElasticTrivia(nodeToCleanup, leading: false));
}
else if (itemsAfter.Any())
{
editor.InsertBefore(namespaceDeclaration, newNamespaceDeclaration);
var nodeToCleanup = itemsAfter.First();
editor.ReplaceNode(nodeToCleanup, WithElasticTrivia(nodeToCleanup, trailing: false));
}
else
{
throw new Exception("WTF Happened");
}
return new ApplyChangesOperation(editor.GetChangedDocument().Project.Solution);
}
private SyntaxNode WithElasticTrivia(SyntaxNode syntaxNode, bool leading = true, bool trailing = true)
{
if (leading && syntaxNode.HasLeadingTrivia)
{
syntaxNode = syntaxNode.WithLeadingTrivia(syntaxNode.GetLeadingTrivia().Select(AsElasticTrivia));
}
if (trailing && syntaxNode.HasTrailingTrivia)
{
syntaxNode = syntaxNode.WithTrailingTrivia(syntaxNode.GetTrailingTrivia().Select(AsElasticTrivia));
}
return syntaxNode.WithAdditionalAnnotations(Formatter.Annotation);
}
private IEnumerable<SyntaxNode> WithElasticTrivia(IEnumerable<SyntaxNode> syntaxNodes)
{
if (syntaxNodes.Any())
{
var firstNode = syntaxNodes.FirstOrDefault();
var lastNode = syntaxNodes.LastOrDefault();
if (firstNode == lastNode)
{
yield return WithElasticTrivia(firstNode);
}
else
{
yield return WithElasticTrivia(firstNode, trailing: false);
foreach (var node in syntaxNodes.Skip(1))
{
if (node != lastNode)
{
yield return node;
}
else
{
yield return WithElasticTrivia(node, leading: false);
}
}
}
}
}
private SyntaxTrivia AsElasticTrivia(SyntaxTrivia trivia)
{
return trivia.WithAdditionalAnnotations(SyntaxAnnotation.ElasticAnnotation);
}
}
}
}
...@@ -24,40 +24,70 @@ internal abstract partial class AbstractMoveTypeService<TService, TTypeDeclarati ...@@ -24,40 +24,70 @@ internal abstract partial class AbstractMoveTypeService<TService, TTypeDeclarati
where TMemberDeclarationSyntax : SyntaxNode where TMemberDeclarationSyntax : SyntaxNode
where TCompilationUnitSyntax : SyntaxNode where TCompilationUnitSyntax : SyntaxNode
{ {
private enum OperationKind
{
MoveType,
RenameType,
RenameFile
}
public async Task<ImmutableArray<CodeAction>> GetRefactoringAsync( public async Task<ImmutableArray<CodeAction>> GetRefactoringAsync(
Document document, TextSpan textSpan, CancellationToken cancellationToken) Document document, TextSpan textSpan, CancellationToken cancellationToken)
{ {
if (textSpan.IsEmpty) var state = await CreateStateAsync(document, textSpan, cancellationToken).ConfigureAwait(false);
if (state == null)
{ {
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); return ImmutableArray<CodeAction>.Empty;
var nodeToAnalyze = root.FindToken(textSpan.Start).GetAncestor<TTypeDeclarationSyntax>(); }
if (nodeToAnalyze != null)
var actions = CreateActions(state, cancellationToken);
Debug.Assert(actions.Count() != 0, "No code actions found for MoveType Refactoring");
return actions;
}
public async Task<ImmutableArray<CodeAction>> GetRefactoringAsync(Document document, TextSpan textSpan, MoveTypeOperationKind operationKind, CancellationToken cancellationToken)
{ {
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>(); var state = await CreateStateAsync(document, textSpan, cancellationToken).ConfigureAwait(false);
if (syntaxFacts.IsOnTypeHeader(root, textSpan.Start))
if (state == null)
{ {
var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); return ImmutableArray<CodeAction>.Empty;
var state = State.Generate( }
semanticDocument, textSpan, nodeToAnalyze, cancellationToken);
if (state != null) ImmutableArray<CodeAction> actions;
switch (operationKind)
{ {
var actions = CreateActions(state, cancellationToken); case MoveTypeOperationKind.MoveTypeScope:
actions = ImmutableArray.Create(GetCodeAction(state, state.SemanticDocument.Document.Name, operationKind: operationKind));
break;
default:
actions = CreateActions(state, cancellationToken);
break;
}
Debug.Assert(actions.Count() != 0, "No code actions found for MoveType Refactoring"); Debug.Assert(actions.Count() != 0, "No code actions found for MoveType Refactoring");
return actions; return actions;
} }
private async Task<State> CreateStateAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken)
{
if (!textSpan.IsEmpty)
{
return null;
} }
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var nodeToAnalyze = root.FindToken(textSpan.Start).GetAncestor<TTypeDeclarationSyntax>();
if (nodeToAnalyze == null)
{
return null;
} }
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
if (!syntaxFacts.IsOnTypeHeader(root, textSpan.Start))
{
return null;
} }
return ImmutableArray<CodeAction>.Empty; var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);
return State.Generate(semanticDocument, textSpan, nodeToAnalyze, cancellationToken);
} }
private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken cancellationToken) private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken cancellationToken)
...@@ -83,7 +113,7 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken ...@@ -83,7 +113,7 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
{ {
foreach (var fileName in suggestedFileNames) foreach (var fileName in suggestedFileNames)
{ {
actions.Add(GetCodeAction(state, fileName, operationKind: OperationKind.MoveType)); actions.Add(GetCodeAction(state, fileName, operationKind: MoveTypeOperationKind.MoveType));
} }
} }
...@@ -93,7 +123,7 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken ...@@ -93,7 +123,7 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
{ {
foreach (var fileName in suggestedFileNames) foreach (var fileName in suggestedFileNames)
{ {
actions.Add(GetCodeAction(state, fileName, operationKind: OperationKind.RenameFile)); actions.Add(GetCodeAction(state, fileName, operationKind: MoveTypeOperationKind.RenameFile));
} }
// only if the document name can be legal identifier in the language, // only if the document name can be legal identifier in the language,
...@@ -102,14 +132,14 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken ...@@ -102,14 +132,14 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
{ {
actions.Add(GetCodeAction( actions.Add(GetCodeAction(
state, fileName: state.DocumentNameWithoutExtension, state, fileName: state.DocumentNameWithoutExtension,
operationKind: OperationKind.RenameType)); operationKind: MoveTypeOperationKind.RenameType));
} }
} }
return actions.ToImmutableArray(); return actions.ToImmutableArray();
} }
private CodeAction GetCodeAction(State state, string fileName, OperationKind operationKind) => private CodeAction GetCodeAction(State state, string fileName, MoveTypeOperationKind operationKind) =>
new MoveTypeCodeAction((TService)this, state, operationKind, fileName); new MoveTypeCodeAction((TService)this, state, operationKind, fileName);
private bool IsNestedType(TTypeDeclarationSyntax typeNode) => private bool IsNestedType(TTypeDeclarationSyntax typeNode) =>
......
...@@ -12,5 +12,6 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType ...@@ -12,5 +12,6 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType
internal interface IMoveTypeService : ILanguageService internal interface IMoveTypeService : ILanguageService
{ {
Task<ImmutableArray<CodeAction>> GetRefactoringAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); Task<ImmutableArray<CodeAction>> GetRefactoringAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken);
Task<ImmutableArray<CodeAction>> GetRefactoringAsync(Document document, TextSpan textSpan, MoveTypeOperationKind operationKind, CancellationToken cancellationToken);
} }
} }
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType
{
internal enum MoveTypeOperationKind
{
MoveType,
MoveTypeScope,
RenameType,
RenameFile
}
}
...@@ -1049,6 +1049,9 @@ public List<SyntaxNode> GetMethodLevelMembers(SyntaxNode root) ...@@ -1049,6 +1049,9 @@ public List<SyntaxNode> GetMethodLevelMembers(SyntaxNode root)
public SyntaxList<SyntaxNode> GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration) public SyntaxList<SyntaxNode> GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration)
=> ((TypeDeclarationSyntax)typeDeclaration).Members; => ((TypeDeclarationSyntax)typeDeclaration).Members;
public SyntaxList<SyntaxNode> GetMembersOfNamespaceDeclaration(SyntaxNode namespaceDeclaration)
=> ((NamespaceDeclarationSyntax)namespaceDeclaration).Members;
private void AppendMethodLevelMembers(SyntaxNode node, List<SyntaxNode> list) private void AppendMethodLevelMembers(SyntaxNode node, List<SyntaxNode> list)
{ {
foreach (var member in node.GetMembers()) foreach (var member in node.GetMembers())
......
...@@ -369,6 +369,7 @@ internal interface ISyntaxFactsService : ILanguageService ...@@ -369,6 +369,7 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxToken ToIdentifierToken(string name); SyntaxToken ToIdentifierToken(string name);
List<SyntaxNode> GetMethodLevelMembers(SyntaxNode root); List<SyntaxNode> GetMethodLevelMembers(SyntaxNode root);
SyntaxList<SyntaxNode> GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration); SyntaxList<SyntaxNode> GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration);
SyntaxList<SyntaxNode> GetMembersOfNamespaceDeclaration(SyntaxNode namespaceDeclaration);
bool ContainsInMemberBody(SyntaxNode node, TextSpan span); bool ContainsInMemberBody(SyntaxNode node, TextSpan span);
int GetMethodLevelMemberId(SyntaxNode root, SyntaxNode node); int GetMethodLevelMemberId(SyntaxNode root, SyntaxNode node);
......
...@@ -986,6 +986,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ...@@ -986,6 +986,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return DirectCast(typeDeclaration, TypeBlockSyntax).Members Return DirectCast(typeDeclaration, TypeBlockSyntax).Members
End Function End Function
Public Function GetMembersOfNamespaceDeclaration(namespaceDeclaration As SyntaxNode) As SyntaxList(Of SyntaxNode) Implements ISyntaxFactsService.GetMembersOfNamespaceDeclaration
Return DirectCast(namespaceDeclaration, NamespaceBlockSyntax).Members
End Function
Public Function IsTopLevelNodeWithMembers(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsTopLevelNodeWithMembers Public Function IsTopLevelNodeWithMembers(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsTopLevelNodeWithMembers
Return TypeOf node Is NamespaceBlockSyntax OrElse Return TypeOf node Is NamespaceBlockSyntax OrElse
TypeOf node Is TypeBlockSyntax OrElse TypeOf node Is TypeBlockSyntax OrElse
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册