提交 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
{
private readonly State _state;
private readonly TService _service;
private readonly OperationKind _operationKind;
private readonly MoveTypeOperationKind _operationKind;
private readonly string _title;
private readonly string _fileName;
public MoveTypeCodeAction(
TService service,
State state,
OperationKind operationKind,
MoveTypeOperationKind operationKind,
string fileName)
{
_state = state;
......@@ -36,12 +36,14 @@ private string CreateDisplayText()
{
switch (_operationKind)
{
case OperationKind.MoveType:
case MoveTypeOperationKind.MoveType:
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);
case OperationKind.RenameFile:
case MoveTypeOperationKind.RenameFile:
return string.Format(FeaturesResources.Rename_file_to_0, _fileName);
case MoveTypeOperationKind.MoveTypeScope:
return string.Empty;
default:
throw ExceptionUtilities.UnexpectedValue(_operationKind);
}
......@@ -59,12 +61,14 @@ private Editor GetEditor(CancellationToken cancellationToken)
{
switch (_operationKind)
{
case OperationKind.MoveType:
case MoveTypeOperationKind.MoveType:
return new MoveTypeEditor(_service, _state, _fileName, cancellationToken);
case OperationKind.RenameType:
case MoveTypeOperationKind.RenameType:
return new RenameTypeEditor(_service, _state, _fileName, cancellationToken);
case OperationKind.RenameFile:
case MoveTypeOperationKind.RenameFile:
return new RenameFileEditor(_service, _state, _fileName, cancellationToken);
case MoveTypeOperationKind.MoveTypeScope:
return new MoveTypeScopeEditor(_service, _state, _fileName, cancellationToken);
default:
throw ExceptionUtilities.UnexpectedValue(_operationKind);
}
......@@ -76,8 +80,10 @@ internal override bool IsApplicable(Workspace workspace)
{
switch (_operationKind)
{
case OperationKind.RenameFile:
case MoveTypeOperationKind.RenameFile:
return workspace.CanRenameFilesDuringCodeActions(_state.SemanticDocument.Document.Project);
case MoveTypeOperationKind.MoveTypeScope:
return _state.TypeNode.Parent is TNamespaceDeclarationSyntax;
}
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
where TMemberDeclarationSyntax : SyntaxNode
where TCompilationUnitSyntax : SyntaxNode
{
private enum OperationKind
{
MoveType,
RenameType,
RenameFile
}
public async Task<ImmutableArray<CodeAction>> GetRefactoringAsync(
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);
var nodeToAnalyze = root.FindToken(textSpan.Start).GetAncestor<TTypeDeclarationSyntax>();
if (nodeToAnalyze != null)
return ImmutableArray<CodeAction>.Empty;
}
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>();
if (syntaxFacts.IsOnTypeHeader(root, textSpan.Start))
var state = await CreateStateAsync(document, textSpan, cancellationToken).ConfigureAwait(false);
if (state == null)
{
var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false);
var state = State.Generate(
semanticDocument, textSpan, nodeToAnalyze, cancellationToken);
if (state != null)
return ImmutableArray<CodeAction>.Empty;
}
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");
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)
......@@ -83,7 +113,7 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
{
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
{
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,
......@@ -102,14 +132,14 @@ private ImmutableArray<CodeAction> CreateActions(State state, CancellationToken
{
actions.Add(GetCodeAction(
state, fileName: state.DocumentNameWithoutExtension,
operationKind: OperationKind.RenameType));
operationKind: MoveTypeOperationKind.RenameType));
}
}
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);
private bool IsNestedType(TTypeDeclarationSyntax typeNode) =>
......
......@@ -12,5 +12,6 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType
internal interface IMoveTypeService : ILanguageService
{
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)
public SyntaxList<SyntaxNode> GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration)
=> ((TypeDeclarationSyntax)typeDeclaration).Members;
public SyntaxList<SyntaxNode> GetMembersOfNamespaceDeclaration(SyntaxNode namespaceDeclaration)
=> ((NamespaceDeclarationSyntax)namespaceDeclaration).Members;
private void AppendMethodLevelMembers(SyntaxNode node, List<SyntaxNode> list)
{
foreach (var member in node.GetMembers())
......
......@@ -369,6 +369,7 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxToken ToIdentifierToken(string name);
List<SyntaxNode> GetMethodLevelMembers(SyntaxNode root);
SyntaxList<SyntaxNode> GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration);
SyntaxList<SyntaxNode> GetMembersOfNamespaceDeclaration(SyntaxNode namespaceDeclaration);
bool ContainsInMemberBody(SyntaxNode node, TextSpan span);
int GetMethodLevelMemberId(SyntaxNode root, SyntaxNode node);
......
......@@ -986,6 +986,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return DirectCast(typeDeclaration, TypeBlockSyntax).Members
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
Return TypeOf node Is NamespaceBlockSyntax OrElse
TypeOf node Is TypeBlockSyntax OrElse
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册