提交 ac8d467e 编写于 作者: P Petr Houska

Reworked IsInXXHeader usage (now position based), docs.

上级 a3291cd7
......@@ -23,6 +23,7 @@ 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;[||]")]
......@@ -170,7 +171,6 @@ 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(
......
......@@ -20,6 +20,7 @@ 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[||]")>
......@@ -118,7 +119,6 @@ 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)
......
......@@ -23,35 +23,11 @@ internal abstract class AbstractRefactoringHelpersService : IRefactoringHelpersS
cancellationToken).ConfigureAwait(false);
}
//TODO: Rework comment
/// <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>
/// The <paramref name="extractNodes"/> enables testing with <paramref name="predicate"/> and potentially returning Nodes
/// that are under/above those that might be selected / considered (as described above). It should iterate over all candidate
/// nodes.
/// </para>
/// <para>
/// Note: this function trims all whitespace from both the beginning and the end of given <paramref name="selectionRaw"/>.
/// 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 async Task<SyntaxNode> TryGetSelectedNodeAsync(
Document document, TextSpan selectionRaw,
Func<SyntaxNode, bool> predicate,
Func<SyntaxNode, ISyntaxFactsService, IEnumerable<SyntaxNode>> extractNodes,
Func<SyntaxToken, ISyntaxFactsService, IEnumerable<SyntaxNode>> extracNodestIfInHeader,
Func<SyntaxNode, int, ISyntaxFactsService, IEnumerable<SyntaxNode>> extracNodestIfInHeader,
CancellationToken cancellationToken)
{
// Given selection is trimmed first to enable over-selection that spans multiple lines. Since trailing whitespace ends
......@@ -73,20 +49,16 @@ internal abstract class AbstractRefactoringHelpersService : IRefactoringHelpersS
return null;
}
// Every time a Node is considered by following algorithm (and tested with predicate) and the predicate fails
// extractNode is called on the node and the results are tested with predicate again. If any of those succeed
// a respective Node gets returned.
// Every time a Node is considered by an extractNodes method is called to check & potentially return nodes around the original one
// that should also be considered.
//
// That enables us to e.g. return node `b` when Node `var a = b;` is being considered without a complex (and potentially
// lang. & situation dependent) into Children descending code here. We can't just try extracted Node because we might
// want the whole node `var a = b;`
//
// While we want to do most extractions for both selections and just caret location (empty selection), extractions based
// on type's header node (caret is anywhere in a header of wanted type e.g. `in[||]t A { get; set; }) are limited to
// empty selections. Otherwise `[|int|] A { get; set; }) would trigger all refactorings for Property Decl.
// Thus: selection -> extractParentsOfHeader: false; location -> extractParentsOfHeader
//
// See local function TryGetAcceptedNodeOrExtracted DefaultNodeExtractor for more info.
// In addition to per-node extractions we also check if current location (if selection is empty) is in a header of higher level
// desired node once. We do that only for locations because otherwise `[|int|] A { get; set; }) would trigger all refactorings for
// Property Decl.
// Handle selections:
// - The smallest node whose FullSpan includes the whole (trimmed) selection
......@@ -159,10 +131,10 @@ internal abstract class AbstractRefactoringHelpersService : IRefactoringHelpersS
? tokenOnLocation
: default;
// A token can be to the left only when there's either no tokenDirectlyToRightOrIn or there's one
// directly starting at current location. Otherwise (otherwise tokenToRightOrIn is also left from location, e.g: `tok[||]enToRightOrIn`)
// A token can be to the left only when there's either no tokenDirectlyToRightOrIn or there's one directly starting at current location.
// Otherwise (otherwise tokenToRightOrIn is also left from location, e.g: `tok[||]enToRightOrIn`)
var tokenToLeft = default(SyntaxToken);
if (tokenToRightOrIn == default || tokenToRightOrIn.Span.Start == location)
if (tokenToRightOrIn == default || tokenToRightOrIn.FullSpan.Start == location)
{
var tokenPreLocation = (tokenOnLocation.Span.End == location)
? tokenOnLocation
......@@ -206,13 +178,18 @@ internal abstract class AbstractRefactoringHelpersService : IRefactoringHelpersS
}
}
// First check if we're in a header of some higher-level node what would pass predicate & if we are -> return it
// We can't check any sooner because the code above (that figures out tokenToLeft, ...) can change current
// `location`.
var acceptedHeaderNode = extracNodestIfInHeader(root, location, syntaxFacts).FirstOrDefault(predicate);
if (acceptedHeaderNode != null)
{
return acceptedHeaderNode;
}
if (tokenToRightOrIn != default)
{
var acceptedHeaderNode = extracNodestIfInHeader(tokenToRightOrIn, syntaxFacts).FirstOrDefault(predicate);
if (acceptedHeaderNode != null)
{
return acceptedHeaderNode;
}
var rightNode = tokenOnLocation.Parent;
do
......@@ -253,12 +230,6 @@ internal abstract class AbstractRefactoringHelpersService : IRefactoringHelpersS
if (tokenToLeft != default)
{
var acceptedHeaderNode = extracNodestIfInHeader(tokenToLeft, syntaxFacts).FirstOrDefault(predicate);
if (acceptedHeaderNode != null)
{
return acceptedHeaderNode;
}
var leftNode = tokenToLeft.Parent;
do
{
......@@ -323,6 +294,20 @@ 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>
///
/// <summary>
/// Extractor function that retrieves all nodes that should be considered for <see cref="TryGetSelectedNodeAsync(Document, TextSpan, Func{SyntaxNode, bool}, Func{SyntaxNode, ISyntaxFactsService, IEnumerable{SyntaxNode}}, Func{SyntaxNode, int, ISyntaxFactsService, IEnumerable{SyntaxNode}}, CancellationToken)"/>
/// given current node.
/// <para>
/// The rationale is that when user selects e.g. entire local declaration statement [|var a = b;|] it is reasonable
/// to provide refactoring for `b` node. Similarly for other types of refactorings.
/// </para>
/// </summary>
/// <remark>
/// Should also return given node.
/// </remark>
protected virtual IEnumerable<SyntaxNode> ExtractNodesSimple(SyntaxNode node, ISyntaxFactsService syntaxFacts)
{
if (node == null)
......@@ -391,34 +376,37 @@ protected virtual IEnumerable<SyntaxNode> ExtractNodesSimple(SyntaxNode node, IS
}
}
protected virtual IEnumerable<SyntaxNode> ExtractNodesIfInHeader(SyntaxToken token, ISyntaxFactsService syntaxFacts)
/// <summary>
/// Extractor function that checks and retrieves all nodes current location is in a header of <see cref="TryGetSelectedNodeAsync(Document, TextSpan, Func{SyntaxNode, bool}, Func{SyntaxNode, ISyntaxFactsService, IEnumerable{SyntaxNode}}, Func{SyntaxNode, int, ISyntaxFactsService, IEnumerable{SyntaxNode}}, CancellationToken)"/>.
/// </summary>
protected virtual IEnumerable<SyntaxNode> ExtractNodesIfInHeader(SyntaxNode root, int location, ISyntaxFactsService syntaxFacts)
{
// Header: [Test] `public int a` { get; set; }
if (syntaxFacts.IsInPropertyDeclarationHeader(token, out var propertyDeclaration))
if (syntaxFacts.IsOnPropertyDeclarationHeader(root, location, out var propertyDeclaration))
{
yield return propertyDeclaration;
}
// Header: public C([Test]`int a = 42`) {}
if (syntaxFacts.IsInParameterHeader(token, out var parameter))
if (syntaxFacts.IsOnParameterHeader(root, location, out var parameter))
{
yield return parameter;
}
// Header: `public I.C([Test]int a = 42)` {}
if (syntaxFacts.IsInMethodHeader(token, out var method))
if (syntaxFacts.IsOnMethodHeader(root, location, out var method))
{
yield return method;
}
// Header: `static C([Test]int a = 42)` {}
if (syntaxFacts.IsInLocalFunctionHeader(token, out var localFunction))
if (syntaxFacts.IsOnLocalFunctionHeader(root, location, out var localFunction))
{
yield return localFunction;
}
// Header: `var a = `3,` b = `5,` c = `7 + 3``;
if (syntaxFacts.IsInLocalDeclarationHeader(token, out var localDeclaration))
if (syntaxFacts.IsOnLocalDeclarationHeader(root, location, out var localDeclaration))
{
yield return localDeclaration;
}
......
......@@ -17,7 +17,9 @@ internal interface IRefactoringHelpersService : ILanguageService
/// <para>
/// A <typeparamref name="TSyntaxNode"/> instance is returned if:
/// - Selection is zero-width and inside/touching a Token with direct parent of type <typeparamref name="TSyntaxNode"/>.
/// - Selection is zero-width and touching a Token whose ancestor ends/starts precisely on current selection .
/// - Selection is zero-width and touching a Token whose ancestor of type <typeparamref name="TSyntaxNode"/> ends/starts precisely on current selection.
/// - Selection is zero-width and in whitespace that corresponds to a Token whose direct ancestor is of type of type <typeparamref name="TSyntaxNode"/>.
/// - Selection is zero-width and in a header (defined by ISyntaxFacts helpers) of an node of type of type <typeparamref name="TSyntaxNode"/>.
/// - Token whose direct parent of type <typeparamref name="TSyntaxNode"/> is selected.
/// - Whole node of a type <typeparamref name="TSyntaxNode"/> is selected.
/// </para>
......
......@@ -1784,64 +1784,61 @@ public bool IsOnTypeHeader(SyntaxNode root, int position)
return false;
}
var start = GetStartOfNodeExcludingAttributes(typeDecl);
var end = typeDecl.GetTypeParameterList()?.GetLastToken().FullSpan.End ??
typeDecl.Identifier.FullSpan.End;
return position >= start && position <= end;
return IsOnHeader(position, typeDecl, typeDecl.Identifier);
}
public bool IsInPropertyDeclarationHeader(SyntaxToken token, out SyntaxNode propertyDeclaration)
public bool IsOnPropertyDeclarationHeader(SyntaxNode root, int position, out SyntaxNode propertyDeclaration)
{
var node = token.GetAncestor<PropertyDeclarationSyntax>();
var node = TryGetAncestorForLocation<PropertyDeclarationSyntax>(position, root);
propertyDeclaration = node;
if (propertyDeclaration == null)
{
return false;
}
return IsInHeader(token, node, node.Identifier);
return IsOnHeader(position, node, node.Identifier);
}
public bool IsInParameterHeader(SyntaxToken token, out SyntaxNode parameter)
public bool IsOnParameterHeader(SyntaxNode root, int position, out SyntaxNode parameter)
{
var node = token.GetAncestor<ParameterSyntax>();
var node = TryGetAncestorForLocation<ParameterSyntax>(position, root);
parameter = node;
if (parameter == null)
{
return false;
}
return IsInHeader(token, node, node);
return IsOnHeader(position, node, node);
}
public bool IsInMethodHeader(SyntaxToken token, out SyntaxNode method)
public bool IsOnMethodHeader(SyntaxNode root, int position, out SyntaxNode method)
{
var node = token.GetAncestor<MethodDeclarationSyntax>();
var node = TryGetAncestorForLocation<MethodDeclarationSyntax>(position, root);
method = node;
if (method == null)
{
return false;
}
return IsInHeader(token, node, node.ParameterList);
return IsOnHeader(position, node, node.ParameterList);
}
public bool IsInLocalFunctionHeader(SyntaxToken token, out SyntaxNode localFunction)
public bool IsOnLocalFunctionHeader(SyntaxNode root, int position, out SyntaxNode localFunction)
{
var node = token.GetAncestor<LocalFunctionStatementSyntax>();
var node = TryGetAncestorForLocation<LocalFunctionStatementSyntax>(position, root);
localFunction = node;
if (localFunction == null)
{
return false;
}
return IsInHeader(token, node, node.ParameterList);
return IsOnHeader(position, node, node.ParameterList);
}
public bool IsInLocalDeclarationHeader(SyntaxToken token, out SyntaxNode localDeclaration)
public bool IsOnLocalDeclarationHeader(SyntaxNode root, int position, out SyntaxNode localDeclaration)
{
var node = token.GetAncestor<LocalDeclarationStatementSyntax>();
var node = TryGetAncestorForLocation<LocalDeclarationStatementSyntax>(position, root);
localDeclaration = node;
if (localDeclaration == null)
{
......@@ -1851,7 +1848,7 @@ public bool IsInLocalDeclarationHeader(SyntaxToken token, out SyntaxNode localDe
var initializersExpressions = node.Declaration.Variables
.Where(v => v.Initializer != null)
.Select(initializedV => initializedV.Initializer.Value).ToImmutableArray<SyntaxNode>();
return IsInHeader(token, node, node, initializersExpressions);
return IsInHeader(position, node, node, initializersExpressions);
}
public bool IsBetweenTypeMembers(SourceText sourceText, SyntaxNode root, int position)
......
......@@ -488,23 +488,25 @@ public bool SpansPreprocessorDirective(IEnumerable<SyntaxToken> tokens)
private bool SpansPreprocessorDirective(SyntaxTriviaList list)
=> list.Any(t => IsPreprocessorDirective(t));
public bool IsInHeader(SyntaxNodeOrToken nodeOrToken, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader)
public bool IsOnHeader(int position, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader)
{
var start = GetStartOfNodeExcludingAttributes(ownerOfHeader);
var end = lastTokenOrNodeOfHeader.FullSpan.End;
return nodeOrToken.Span.Start >= start && nodeOrToken.Span.End <= end;
return start <= position && position <= end;
}
public bool IsInHeader(SyntaxNodeOrToken nodeOrToken, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader, ImmutableArray<SyntaxNode> holes)
public bool IsInHeader(int position, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader, ImmutableArray<SyntaxNode> holes)
{
var inHeader = IsInHeader(nodeOrToken, ownerOfHeader, lastTokenOrNodeOfHeader);
var inHeader = IsOnHeader(position, ownerOfHeader, lastTokenOrNodeOfHeader);
if (!inHeader)
{
return false;
}
if (holes.Any(h => h.Span.IntersectsWith(nodeOrToken.Span)))
// Holes are exclusive: to return false it needs to be _inside_ a hole not only on the edge
// -> to be consistent with other 'being on the edge' of Tokens/Nodes.
if (holes.Any(h => (h.Span.Start < position && position < h.Span.End)))
{
return false;
}
......@@ -512,6 +514,23 @@ public bool IsInHeader(SyntaxNodeOrToken nodeOrToken, SyntaxNode ownerOfHeader,
return true;
}
/// <summary>
/// Tries to get an ancestor of a Token on current position or of Token directly to left:
/// e.g.: tokenWithWantedAncestor[||]tokenWithoutWantedAncestor
/// </summary>
protected static TNode TryGetAncestorForLocation<TNode>(int position, SyntaxNode root) where TNode : SyntaxNode
{
var token = root.FindToken(position);
var node = token.GetAncestor<TNode>();
if (node == null && token.FullSpan.Start == position)
{
token = token.GetPreviousToken();
node = token.GetAncestor<TNode>();
}
return node;
}
protected int GetStartOfNodeExcludingAttributes(SyntaxNode node)
{
var attributeLists = GetAttributeLists(node);
......@@ -522,5 +541,6 @@ protected int GetStartOfNodeExcludingAttributes(SyntaxNode node)
}
public abstract SyntaxList<SyntaxNode> GetAttributeLists(SyntaxNode node);
}
}
......@@ -412,12 +412,12 @@ internal interface ISyntaxFactsService : ILanguageService
ImmutableArray<SyntaxNode> GetSelectedFieldsAndProperties(SyntaxNode root, TextSpan textSpan, bool allowPartialSelection);
bool IsOnTypeHeader(SyntaxNode root, int position);
bool IsInHeader(SyntaxNodeOrToken nodeOrToken, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader);
bool IsInPropertyDeclarationHeader(SyntaxToken token, out SyntaxNode propertyDeclaration);
bool IsInParameterHeader(SyntaxToken token, out SyntaxNode parameter);
bool IsInMethodHeader(SyntaxToken token, out SyntaxNode method);
bool IsInLocalFunctionHeader(SyntaxToken token, out SyntaxNode localFunction);
bool IsInLocalDeclarationHeader(SyntaxToken token, out SyntaxNode localDeclaration);
bool IsOnHeader(int position, SyntaxNode ownerOfHeader, SyntaxNodeOrToken lastTokenOrNodeOfHeader);
bool IsOnPropertyDeclarationHeader(SyntaxNode root, int position, out SyntaxNode propertyDeclaration);
bool IsOnParameterHeader(SyntaxNode root, int position, out SyntaxNode parameter);
bool IsOnMethodHeader(SyntaxNode root, int position, out SyntaxNode method);
bool IsOnLocalFunctionHeader(SyntaxNode root, int position, out SyntaxNode localFunction);
bool IsOnLocalDeclarationHeader(SyntaxNode root, int position, out SyntaxNode localDeclaration);
bool IsBetweenTypeMembers(SourceText sourceText, SyntaxNode root, int position);
// Walks the tree, starting from contextNode, looking for the first construct
......
' 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.Collections.Immutable
Imports System.Composition
Imports System.Text
Imports System.Threading
Imports Microsoft.CodeAnalysis
......@@ -1735,12 +1734,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return position >= start AndAlso position <= _end
End Function
Private Function ISyntaxFactsService_IsInHeader(nodeOrToken As SyntaxNodeOrToken, ownerOfHeader As SyntaxNode, lastTokenOrNodeOfHeader As SyntaxNodeOrToken) As Boolean Implements ISyntaxFactsService.IsInHeader
Return IsInHeader(nodeOrToken, ownerOfHeader, lastTokenOrNodeOfHeader)
Private Function ISyntaxFactsService_IsInHeader(position As Integer, ownerOfHeader As SyntaxNode, lastTokenOrNodeOfHeader As SyntaxNodeOrToken) As Boolean Implements ISyntaxFactsService.IsOnHeader
Return IsOnHeader(position, ownerOfHeader, lastTokenOrNodeOfHeader)
End Function
Public Function IsInPropertyDeclarationHeader(token As SyntaxToken, ByRef propertyDeclaration As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInPropertyDeclarationHeader
Dim node = token.GetAncestor(Of PropertyStatementSyntax)()
Public Function IsOnPropertyDeclarationHeader(root As SyntaxNode, position As Integer, ByRef propertyDeclaration As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsOnPropertyDeclarationHeader
Dim node = TryGetAncestorForLocation(Of PropertyStatementSyntax)(position, root)
propertyDeclaration = node
If propertyDeclaration Is Nothing Then
......@@ -1748,25 +1747,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
If node.AsClause IsNot Nothing Then
Return IsInHeader(token, node, node.AsClause)
Return IsOnHeader(position, node, node.AsClause)
End If
Return IsInHeader(token, node, node.Identifier)
Return IsOnHeader(position, node, node.Identifier)
End Function
Public Function IsInParameterHeader(token As SyntaxToken, ByRef parameter As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInParameterHeader
Dim node = token.GetAncestor(Of ParameterSyntax)()
Public Function IsOnParameterHeader(root As SyntaxNode, position As Integer, ByRef parameter As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsOnParameterHeader
Dim node = TryGetAncestorForLocation(Of ParameterSyntax)(position, root)
parameter = node
If parameter Is Nothing Then
Return False
End If
Return IsInHeader(token, node, node)
Return IsOnHeader(position, node, node)
End Function
Public Function IsInMethodHeader(token As SyntaxToken, ByRef method As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInMethodHeader
Dim node = token.GetAncestor(Of MethodStatementSyntax)()
Public Function IsOnMethodHeader(root As SyntaxNode, position As Integer, ByRef method As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsOnMethodHeader
Dim node = TryGetAncestorForLocation(Of MethodStatementSyntax)(position, root)
method = node
If method Is Nothing Then
......@@ -1774,23 +1773,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
If node.HasReturnType() Then
Return IsInHeader(token, method, node.GetReturnType())
Return IsOnHeader(position, method, node.GetReturnType())
End If
If node.ParameterList IsNot Nothing Then
Return IsInHeader(token, method, node.ParameterList)
Return IsOnHeader(position, method, node.ParameterList)
End If
Return IsInHeader(token, node, node)
Return IsOnHeader(position, node, node)
End Function
Public Function IsInLocalFunctionHeader(token As SyntaxToken, ByRef localFunction As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInLocalFunctionHeader
Public Function IsOnLocalFunctionHeader(root As SyntaxNode, position As Integer, ByRef localFunction As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsOnLocalFunctionHeader
' No local functions in VisualBasic
Return False
End Function
Public Function IsInLocalDeclarationHeader(token As SyntaxToken, ByRef localDeclaration As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInLocalDeclarationHeader
Dim node = token.GetAncestor(Of LocalDeclarationStatementSyntax)()
Public Function IsOnLocalDeclarationHeader(root As SyntaxNode, position As Integer, ByRef localDeclaration As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsOnLocalDeclarationHeader
Dim node = TryGetAncestorForLocation(Of LocalDeclarationStatementSyntax)(position, root)
localDeclaration = node
If localDeclaration Is Nothing Then
......@@ -1798,7 +1797,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
Dim initializersExpressions = node.Declarators.Where(Function(d) d.Initializer IsNot Nothing).[Select](Function(initializedd) initializedd.Initializer.Value).Cast(Of SyntaxNode).ToImmutableArray()
Return IsInHeader(token, node, node, initializersExpressions)
Return IsInHeader(position, node, node, initializersExpressions)
End Function
Public Function IsBetweenTypeMembers(sourceText As SourceText, root As SyntaxNode, position As Integer) As Boolean Implements ISyntaxFactsService.IsBetweenTypeMembers
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册