提交 98a6065e 编写于 作者: P Petr Houska

Move IntroduceUsingStatement to helpers.

上级 6dda1023
......@@ -23,7 +23,6 @@ protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspa
[InlineData("var name[||] = disposable;")]
[InlineData("var name [||]= disposable;")]
[InlineData("var name =[||] disposable;")]
[InlineData("var name = [||]disposable;")]
[InlineData("[|var name = disposable;|]")]
[InlineData("var name = disposable[||];")]
[InlineData("var name = disposable;[||]")]
......@@ -171,6 +170,7 @@ void M(System.IDisposable disposable)
[InlineData("var name = d[||]isposable;")]
[InlineData("var name = disposabl[||]e;")]
[InlineData("var name=[|disposable|];")]
[InlineData("var name = [||]disposable;")]
public async Task RefactoringIsNotAvailableForSelection(string declaration)
{
await TestMissingInRegularAndScriptAsync(
......
......@@ -811,16 +811,16 @@ class TestAttribute : Attribute { }
#region Test arguments
[Fact]
[WorkItem(35525, "https://github.com/dotnet/roslyn/issues/35525")]
public async Task TestMissingArgumentsExtractionsInInitializer()
public async Task TestArgumentsExtractionsInInitializer()
{
var testText = @"
using System;
class C
{
class TestAttribute : Attribute { }
public C([Test]int a = [||]42, int b = 41) {}
public C({|result:[Test]int a = [||]42|}, int b = 41) {}
}";
await TestMissingAsync<ParameterSyntax>(testText);
await TestAsync<ParameterSyntax>(testText);
}
[Fact]
......
......@@ -20,7 +20,6 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.IntroduceUsingStat
<InlineData("Dim name[||] = disposable")>
<InlineData("Dim name [||]= disposable")>
<InlineData("Dim name =[||] disposable")>
<InlineData("Dim name = [||]disposable")>
<InlineData("[|Dim name = disposable|]")>
<InlineData("Dim name = disposable[||]")>
<InlineData("Dim name = disposable[||]")>
......@@ -119,6 +118,7 @@ End Class")
<InlineData("Dim name = d[||]isposable")>
<InlineData("Dim name = disposabl[||]e")>
<InlineData("Dim name=[|disposable|]")>
<InlineData("Dim name = [||]disposable")>
Public Async Function RefactoringIsNotAvailableForSelection(ByVal declaration As String) As Task
Await TestMissingInRegularAndScriptAsync("Class C
Sub M(disposable As System.IDisposable)
......
......@@ -21,34 +21,14 @@ internal abstract class AbstractRefactoringHelpersService<TPropertyDeclaration,
public async Task<TSyntaxNode> TryGetSelectedNodeAsync<TSyntaxNode>(
Document document, TextSpan selection, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode
{
return (TSyntaxNode)await TryGetSelectedNodeAsync(document, selection, n => n is TSyntaxNode, cancellationToken).ConfigureAwait(false);
return (TSyntaxNode)await TryGetSelectedNodeAsync(
document,
selection, n => n is TSyntaxNode,
ExtractNodesSimple, ExtractNodesIfInHeader,
cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// <para>
/// Returns a Node for refactoring given specified selection that passes <paramref name="predicate"/>
/// or null if no such instance exists.
/// </para>
/// <para>
/// A node instance is return if:
/// - Selection is zero-width and inside/touching a Token with direct parent passing <paramref name="predicate"/>.
/// - Selection is zero-width and touching a Token whose ancestor Node passing <paramref name="predicate"/> ends/starts precisely on current selection.
/// - Token whose direct parent passing <paramref name="predicate"/> is selected.
/// - Whole node passing <paramref name="predicate"/> is selected.
/// </para>
/// <para>
/// Attempts extracting (and testing with <paramref name="predicate"/> a Node for each Node it considers (see above).
/// By default extracts initializer expressions from declarations and assignments.
/// </para>
/// <para>
/// Note: this function trims all whitespace from both the beginning and the end of given <paramref name="selection"/>.
/// The trimmed version is then used to determine relevant <see cref="SyntaxNode"/>. It also handles incomplete selections
/// of tokens gracefully. Over-selection containing leading comments is also handled correctly.
/// </para>
/// </summary>
protected Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, TextSpan selection, Func<SyntaxNode, bool> predicate, CancellationToken cancellationToken)
=> TryGetSelectedNodeAsync(document, selection, predicate, DefaultNodesExtractor, cancellationToken);
//TODO: Rework comment
/// <summary>
/// <para>
/// Returns a Node for refactoring given specified selection that passes <paramref name="predicate"/>
......@@ -72,7 +52,12 @@ protected Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, TextSpan s
/// of tokens gracefully. Over-selection containing leading comments is also handled correctly.
/// </para>
/// </summary>
protected async Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, TextSpan selectionRaw, Func<SyntaxNode, bool> predicate, Func<SyntaxNode, ISyntaxFactsService, bool, IEnumerable<SyntaxNode>> extractNodes, CancellationToken cancellationToken)
protected async Task<SyntaxNode> TryGetSelectedNodeAsync(
Document document, TextSpan selectionRaw,
Func<SyntaxNode, bool> predicate,
Func<SyntaxNode, ISyntaxFactsService, IEnumerable<SyntaxNode>> extractNodes,
Func<SyntaxToken, ISyntaxFactsService, IEnumerable<SyntaxNode>> extracNodestIfInHeader,
CancellationToken cancellationToken)
{
// Given selection is trimmed first to enable over-selection that spans multiple lines. Since trailing whitespace ends
// at newline boundary over-selection to e.g. a line after LocalFunctionStatement would cause FindNode to find enclosing
......@@ -119,21 +104,21 @@ protected async Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, Text
var prevNode = selectionNode;
do
{
var wantedNode = TryGetAcceptedNodeOrExtracted(selectionNode, predicate, extractNodes, syntaxFacts, extractParentsOfHeader: false);
if (wantedNode != null)
var acceptedNode = extractNodes(selectionNode, syntaxFacts).FirstOrDefault(predicate);
if (acceptedNode != null)
{
// For selections we need to handle an edge case where only AttributeLists are within selection (e.g. `Func([|[in][out]|] arg1);`).
// In that case the smallest encompassing node is still the whole argument node but it's hard to justify showing refactorings for it
// if user selected only its attributes.
// Selection contains only AttributeLists -> don't consider current Node
var spanWithoutAttributes = GetSpanWithoutAttributes(wantedNode, root, syntaxFacts);
var spanWithoutAttributes = GetSpanWithoutAttributes(acceptedNode, root, syntaxFacts);
if (!selectionTrimmed.IntersectsWith(spanWithoutAttributes))
{
break;
}
return wantedNode;
return acceptedNode;
}
prevNode = selectionNode;
......@@ -228,16 +213,22 @@ protected async Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, Text
if (tokenToRightOrIn != default)
{
var acceptedHeaderNode = extracNodestIfInHeader(tokenToRightOrIn, syntaxFacts).FirstOrDefault(predicate);
if (acceptedHeaderNode != null)
{
return acceptedHeaderNode;
}
var rightNode = tokenOnLocation.Parent;
do
{
// Consider either a Node that is:
// - Parent of touched Token (location can be within)
// - Ancestor Node of such Token as long as their span starts on location (it's still on the edge)
var wantedNode = TryGetAcceptedNodeOrExtracted(rightNode, predicate, extractNodes, syntaxFacts, extractParentsOfHeader: true);
if (wantedNode != null)
var acceptedNode = extractNodes(rightNode, syntaxFacts).FirstOrDefault(predicate);
if (acceptedNode != null)
{
return wantedNode;
return acceptedNode;
}
rightNode = rightNode.Parent;
......@@ -267,15 +258,21 @@ protected async Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, Text
if (tokenToLeft != default)
{
var acceptedHeaderNode = extracNodestIfInHeader(tokenToLeft, syntaxFacts).FirstOrDefault(predicate);
if (acceptedHeaderNode != null)
{
return acceptedHeaderNode;
}
var leftNode = tokenToLeft.Parent;
do
{
// Consider either a Node that is:
// - Ancestor Node of such Token as long as their span ends on location (it's still on the edge)
var wantedNode = TryGetAcceptedNodeOrExtracted(leftNode, predicate, extractNodes, syntaxFacts, extractParentsOfHeader: true);
if (wantedNode != null)
var acceptedNode = extractNodes(leftNode, syntaxFacts).FirstOrDefault(predicate);
if (acceptedNode != null)
{
return wantedNode;
return acceptedNode;
}
leftNode = leftNode.Parent;
......@@ -290,21 +287,6 @@ protected async Task<SyntaxNode> TryGetSelectedNodeAsync(Document document, Text
// nothing found -> return null
return null;
static SyntaxNode TryGetAcceptedNodeOrExtracted(SyntaxNode node, Func<SyntaxNode, bool> predicate, Func<SyntaxNode, ISyntaxFactsService, bool, IEnumerable<SyntaxNode>> extractNodes, ISyntaxFactsService syntaxFacts, bool extractParentsOfHeader)
{
if (node == null)
{
return null;
}
if (predicate(node))
{
return node;
}
return extractNodes(node, syntaxFacts, extractParentsOfHeader).FirstOrDefault(predicate);
}
}
private static TextSpan GetSpanWithoutAttributes(SyntaxNode node, SyntaxNode root, ISyntaxFactsService syntaxFacts)
......@@ -329,9 +311,10 @@ private static TextSpan GetSpanWithoutAttributes(SyntaxNode node, SyntaxNode roo
return node.Span;
}
// TODO: Rework comment
/// <summary>
/// <para>
/// Extractor function for <see cref="TryGetSelectedNodeAsync(Document, TextSpan, Func{SyntaxNode, bool}, Func{SyntaxNode, ISyntaxFactsService, bool, IEnumerable{SyntaxNode}}, CancellationToken)"/> method
/// Extractor function for method
/// that retrieves nodes that should also be considered as refactoring targets given <paramref name="node"/> is considered.
/// Can extract both nodes above and under given <paramref name="node"/>.
/// </para>
......@@ -345,29 +328,21 @@ private static TextSpan GetSpanWithoutAttributes(SyntaxNode node, SyntaxNode roo
/// with that and only that node. On the other hand placing cursor anywhere in header should still count as selecting the node it's header of.
/// </para>
/// </summary>
protected virtual IEnumerable<SyntaxNode> DefaultNodesExtractor(SyntaxNode node, ISyntaxFactsService syntaxFacts, bool extractParentsOfHeader)
protected virtual IEnumerable<SyntaxNode> ExtractNodesSimple(SyntaxNode node, ISyntaxFactsService syntaxFacts)
{
if (node == null)
{
yield break;
}
// First return the node itself so that it is considered
yield return node;
// REMARKS:
// The set of currently attempted extractions is in no way exhaustive and covers only cases
// that were found to be relevant for refactorings that were moved to `TryGetSelectedNodeAsync`.
// Feel free to extend it / refine current heuristics.
foreach (var extractedNode in ExtractNodesSimple(node, syntaxFacts))
{
yield return extractedNode;
}
if (extractParentsOfHeader)
{
foreach (var headerNode in ExtractNodesOfHeader(node, syntaxFacts))
{
yield return headerNode;
}
}
}
protected virtual IEnumerable<SyntaxNode> ExtractNodesSimple(SyntaxNode node, ISyntaxFactsService syntaxFacts)
{
// `var a = b`;
if (syntaxFacts.IsLocalDeclarationStatement(node))
{
......@@ -421,30 +396,36 @@ protected virtual IEnumerable<SyntaxNode> ExtractNodesSimple(SyntaxNode node, IS
}
}
protected virtual IEnumerable<SyntaxNode> ExtractNodesOfHeader(SyntaxNode node, ISyntaxFactsService syntaxFacts)
protected virtual IEnumerable<SyntaxNode> ExtractNodesIfInHeader(SyntaxToken token, ISyntaxFactsService syntaxFacts)
{
// Header: [Test] `public int a` { get; set; }
if (syntaxFacts.IsInPropertyDeclarationHeader(node))
if (syntaxFacts.IsInPropertyDeclarationHeader(token))
{
yield return node.GetAncestorOrThis<TPropertyDeclaration>();
yield return token.GetAncestor<TPropertyDeclaration>();
}
// Header: public C([Test]`int a` = 42) {}
if (syntaxFacts.IsInParameterHeader(node))
// Header: public C([Test]`int a = 42`) {}
if (syntaxFacts.IsInParameterHeader(token))
{
yield return node.GetAncestorOrThis<TParameter>();
yield return token.GetAncestor<TParameter>();
}
// Header: `public I.C([Test]int a = 42)` {}
if (syntaxFacts.IsInMethodHeader(node))
if (syntaxFacts.IsInMethodHeader(token))
{
yield return node.GetAncestorOrThis<TMethodDeclaration>();
yield return token.GetAncestor<TMethodDeclaration>();
}
// Header: `static C([Test]int a = 42)` {}
if (syntaxFacts.IsInLocalFunctionHeader(node))
if (syntaxFacts.IsInLocalFunctionHeader(token))
{
yield return token.GetAncestor<TLocalFunctionStatementSyntax>();
}
// Header: `var a = `3,` b = `5,` c = `7 + 3``;
if (syntaxFacts.IsInLocalDelcalrationHeader(token))
{
yield return node.GetAncestorOrThis<TLocalFunctionStatementSyntax>();
yield return token.GetAncestor<TLocalDeclaration>();
}
}
}
......
......@@ -47,11 +47,13 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
private async Task<(TLocalDeclarationSyntax, ILocalSymbol)> FindDisposableLocalDeclaration(Document document, TextSpan selection, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var refactoringHelperService = document.GetLanguageService<IRefactoringHelpersService>();
var declarationSyntax = await refactoringHelperService.TryGetSelectedNodeAsync<TLocalDeclarationSyntax>(document, selection, cancellationToken).ConfigureAwait(false);
var declarationSyntax =
root.FindNode(selection)?.GetAncestorOrThis<TLocalDeclarationSyntax>()
?? root.FindTokenOnLeftOfPosition(selection.End).GetAncestor<TLocalDeclarationSyntax>();
if (declarationSyntax == null)
{
return default;
}
if (declarationSyntax is null || !CanRefactorToContainBlockStatements(declarationSyntax.Parent))
{
......@@ -94,20 +96,6 @@ private async Task<(TLocalDeclarationSyntax, ILocalSymbol)> FindDisposableLocalD
return default;
}
// Infer the intent of the selection. Offer the refactoring only if the selection
// appears to be aimed at the declaration statement but not at its initializer expression.
var isValidSelection = await CodeRefactoringHelpers.RefactoringSelectionIsValidAsync(
document,
selection,
node: declarationSyntax,
holes: ImmutableArray.Create(initializer.Syntax),
cancellationToken).ConfigureAwait(false);
if (!isValidSelection)
{
return default;
}
if (!IsLegalUsingStatementType(semanticModel.Compilation, disposableType, localType))
{
return default;
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeActions
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.Editing
......@@ -9,7 +9,6 @@ Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.ReplaceMethodWithProperty
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Text
Imports System.Threading
Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.ReplaceMethodWithProperty
<ExportLanguageService(GetType(IReplaceMethodWithPropertyService), LanguageNames.VisualBasic), [Shared]>
......
......@@ -1791,48 +1791,62 @@ public bool IsOnTypeHeader(SyntaxNode root, int position)
return position >= start && position <= end;
}
public bool IsInPropertyDeclarationHeader(SyntaxNode node)
public bool IsInPropertyDeclarationHeader(SyntaxToken token)
{
var propertyDeclaration = node.GetAncestorOrThis<PropertyDeclarationSyntax>();
var propertyDeclaration = token.GetAncestor<PropertyDeclarationSyntax>();
if (propertyDeclaration == null)
{
return false;
}
return IsInHeader(node, propertyDeclaration, propertyDeclaration.Identifier);
return IsInHeader(token, propertyDeclaration, propertyDeclaration.Identifier);
}
public bool IsInParameterHeader(SyntaxNode node)
public bool IsInParameterHeader(SyntaxToken token)
{
var parameter = node.GetAncestorOrThis<ParameterSyntax>();
var parameter = token.GetAncestor<ParameterSyntax>();
if (parameter == null)
{
return false;
}
return IsInHeader(node, parameter, parameter.Identifier);
return IsInHeader(token, parameter, parameter);
}
public bool IsInMethodHeader(SyntaxNode node)
public bool IsInMethodHeader(SyntaxToken token)
{
var containingMethod = node.GetAncestorOrThis<MethodDeclarationSyntax>();
var containingMethod = token.GetAncestor<MethodDeclarationSyntax>();
if (containingMethod == null)
{
return false;
}
return IsInHeader(node, containingMethod, containingMethod.ParameterList);
return IsInHeader(token, containingMethod, containingMethod.ParameterList);
}
public bool IsInLocalFunctionHeader(SyntaxNode node)
public bool IsInLocalFunctionHeader(SyntaxToken token)
{
var containingLocalFunction = node.GetAncestorOrThis<LocalFunctionStatementSyntax>();
var containingLocalFunction = token.GetAncestor<LocalFunctionStatementSyntax>();
if (containingLocalFunction == null)
{
return false;
}
return IsInHeader(node, containingLocalFunction, containingLocalFunction.ParameterList);
return IsInHeader(token, containingLocalFunction, containingLocalFunction.ParameterList);
}
public bool IsInLocalDelcalrationHeader(SyntaxToken token)
{
var localDeclaration = token.GetAncestor<LocalDeclarationStatementSyntax>();
if (localDeclaration == null)
{
return false;
}
var initializersExpressions = localDeclaration.Declaration.Variables
.Where(v => v.Initializer != null)
.Select(initializedV => initializedV.Initializer.Value).ToImmutableArray<SyntaxNode>();
return IsInHeader(token, localDeclaration, localDeclaration, initializersExpressions);
}
public bool IsBetweenTypeMembers(SourceText sourceText, SyntaxNode root, int position)
......
......@@ -488,12 +488,28 @@ public bool SpansPreprocessorDirective(IEnumerable<SyntaxToken> tokens)
private bool SpansPreprocessorDirective(SyntaxTriviaList list)
=> list.Any(t => IsPreprocessorDirective(t));
public bool IsInHeader(SyntaxNode node, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader)
public bool IsInHeader(SyntaxNodeOrToken nodeOrToken, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader)
{
var start = GetStartOfNodeExcludingAttributes(ownerOfHeader);
var end = lastTokenOrNodeOfHeader.FullSpan.End;
return node.Span.Start >= start && node.Span.End <= end;
return nodeOrToken.Span.Start >= start && nodeOrToken.Span.End <= end;
}
public bool IsInHeader(SyntaxNodeOrToken nodeOrToken, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader, ImmutableArray<SyntaxNode> holes)
{
var inHeader = IsInHeader(nodeOrToken, ownerOfHeader, lastTokenOrNodeOfHeader);
if (!inHeader)
{
return false;
}
if (holes.Any(h => h.Span.IntersectsWith(nodeOrToken.Span)))
{
return false;
}
return true;
}
protected int GetStartOfNodeExcludingAttributes(SyntaxNode node)
......
......@@ -412,11 +412,12 @@ internal interface ISyntaxFactsService : ILanguageService
ImmutableArray<SyntaxNode> GetSelectedFieldsAndProperties(SyntaxNode root, TextSpan textSpan, bool allowPartialSelection);
bool IsOnTypeHeader(SyntaxNode root, int position);
bool IsInHeader(SyntaxNode node, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader);
bool IsInPropertyDeclarationHeader(SyntaxNode node);
bool IsInParameterHeader(SyntaxNode node);
bool IsInMethodHeader(SyntaxNode node);
bool IsInLocalFunctionHeader(SyntaxNode node);
bool IsInHeader(SyntaxNodeOrToken nodeOrToken, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader);
bool IsInPropertyDeclarationHeader(SyntaxToken token);
bool IsInParameterHeader(SyntaxToken token);
bool IsInMethodHeader(SyntaxToken token);
bool IsInLocalFunctionHeader(SyntaxToken token);
bool IsInLocalDelcalrationHeader(SyntaxToken token);
bool IsBetweenTypeMembers(SourceText sourceText, SyntaxNode root, int position);
// Walks the tree, starting from contextNode, looking for the first construct
......
......@@ -1735,57 +1735,64 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return position >= start AndAlso position <= _end
End Function
Private Function ISyntaxFactsService_IsInHeader(node As SyntaxNode, ownerOfHeader As SyntaxNode, lastTokenOrNodeOfHeader As SyntaxNodeOrToken) As Boolean Implements ISyntaxFactsService.IsInHeader
Return IsInHeader(node, ownerOfHeader, lastTokenOrNodeOfHeader)
Private Function ISyntaxFactsService_IsInHeader(nodeOrToken As SyntaxNodeOrToken, ownerOfHeader As SyntaxNode, lastTokenOrNodeOfHeader As SyntaxNodeOrToken) As Boolean Implements ISyntaxFactsService.IsInHeader
Return IsInHeader(nodeOrToken, ownerOfHeader, lastTokenOrNodeOfHeader)
End Function
Public Function IsInPropertyDeclarationHeader(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInPropertyDeclarationHeader
Dim propertyDeclaration = node.GetAncestorOrThis(Of PropertyStatementSyntax)()
Public Function IsInPropertyDeclarationHeader(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsInPropertyDeclarationHeader
Dim propertyDeclaration = token.GetAncestor(Of PropertyStatementSyntax)()
If propertyDeclaration Is Nothing Then
Return False
End If
If propertyDeclaration.AsClause IsNot Nothing Then
Return IsInHeader(node, propertyDeclaration, propertyDeclaration.AsClause)
Return IsInHeader(token, propertyDeclaration, propertyDeclaration.AsClause)
End If
Return IsInHeader(node, propertyDeclaration, propertyDeclaration.Identifier)
Return IsInHeader(token, propertyDeclaration, propertyDeclaration.Identifier)
End Function
Public Function IsInParameterHeader(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInParameterHeader
Dim parameter = node.GetAncestorOrThis(Of ParameterSyntax)()
Public Function IsInParameterHeader(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsInParameterHeader
Dim parameter = token.GetAncestor(Of ParameterSyntax)()
If parameter Is Nothing Then
Return False
End If
If parameter.AsClause IsNot Nothing Then
Return IsInHeader(node, parameter, parameter.AsClause)
End If
Return IsInHeader(node, parameter, parameter.Identifier)
Return IsInHeader(token, parameter, parameter)
End Function
Public Function IsInMethodHeader(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInMethodHeader
Dim method = node.GetAncestorOrThis(Of MethodStatementSyntax)()
Public Function IsInMethodHeader(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsInMethodHeader
Dim method = token.GetAncestor(Of MethodStatementSyntax)()
If method Is Nothing Then
Return False
End If
If method.HasReturnType() Then
Return IsInHeader(node, method, method.GetReturnType())
Return IsInHeader(token, method, method.GetReturnType())
End If
If method.ParameterList IsNot Nothing Then
Return IsInHeader(node, method, method.ParameterList)
Return IsInHeader(token, method, method.ParameterList)
End If
Return IsInHeader(token, method, method)
End Function
Public Function IsInLocalDelcalrationHeader(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsInLocalDelcalrationHeader
Dim localDeclaration = token.GetAncestor(Of LocalDeclarationStatementSyntax)()
If localDeclaration Is Nothing Then
Return False
End If
Return IsInHeader(node, method, method)
Dim initializersExpressions = localDeclaration.Declarators.Where(Function(d) d.Initializer IsNot Nothing).[Select](Function(initializedd) initializedd.Initializer.Value).Cast(Of SyntaxNode).ToImmutableArray()
Return IsInHeader(token, localDeclaration, localDeclaration, initializersExpressions)
End Function
Public Function IsInLocalFunctionHeader(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInLocalFunctionHeader
Public Function IsInLocalFunctionHeader(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsInLocalFunctionHeader
' No local functions in VisualBasic
Return False
End Function
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册