File: Completion\KeywordRecommenders\Declarations\ParameterModifiersKeywordRecommender.vb
Web Access
Project: src\src\Features\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.Features.vbproj (Microsoft.CodeAnalysis.VisualBasic.Features)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
 
Imports System.Collections.Immutable
Imports System.Threading
Imports Microsoft.CodeAnalysis.Completion.Providers
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.KeywordRecommenders.Declarations
    ''' <summary>
    ''' Recommends the ByVal, ByRef, etc keywords.
    ''' </summary>
    Friend Class ParameterModifiersKeywordRecommender
        Inherits AbstractKeywordRecommender
 
        Protected Overrides Function RecommendKeywords(context As VisualBasicSyntaxContext, cancellationToken As CancellationToken) As ImmutableArray(Of RecommendedKeyword)
            If context.FollowsEndOfStatement Then
                Return ImmutableArray(Of RecommendedKeyword).Empty
            End If
 
            Dim targetToken = context.TargetToken
 
            Dim methodDeclaration = targetToken.GetAncestor(Of MethodBaseSyntax)()
            If methodDeclaration Is Nothing OrElse methodDeclaration.ParameterList Is Nothing Then
                Return ImmutableArray(Of RecommendedKeyword).Empty
            End If
 
            Dim parameterAlreadyHasByValOrByRef = False
            If targetToken.GetAncestor(Of ParameterSyntax)() IsNot Nothing Then
                parameterAlreadyHasByValOrByRef = targetToken.GetAncestor(Of ParameterSyntax)().Modifiers.Any(Function(m) m.IsKind(SyntaxKind.ByValKeyword, SyntaxKind.ByRefKeyword))
            End If
 
            ' Compute some basic properties of what is allowed at all in this context
            Dim byRefAllowed = Not TypeOf methodDeclaration Is AccessorStatementSyntax AndAlso
                               methodDeclaration.Kind <> SyntaxKind.PropertyStatement AndAlso
                               methodDeclaration.Kind <> SyntaxKind.OperatorStatement
 
            Dim optionalAndParamArrayAllowed = Not TypeOf methodDeclaration Is DelegateStatementSyntax AndAlso
                                               Not TypeOf methodDeclaration Is LambdaHeaderSyntax AndAlso
                                               Not TypeOf methodDeclaration Is AccessorStatementSyntax AndAlso
                                               methodDeclaration.Kind <> SyntaxKind.EventStatement AndAlso
                                               methodDeclaration.Kind <> SyntaxKind.OperatorStatement
 
            ' Compute a simple list of the "standard" recommendations assuming nothing special is going on
            Dim defaultRecommendations As New List(Of RecommendedKeyword)
            defaultRecommendations.Add(New RecommendedKeyword("ByVal", VBFeaturesResources.Specifies_that_an_argument_is_passed_in_such_a_way_that_the_called_procedure_or_property_cannot_change_the_underlying_value_of_the_argument_in_the_calling_code))
 
            If byRefAllowed Then
                defaultRecommendations.Add(New RecommendedKeyword("ByRef", VBFeaturesResources.Specifies_that_an_argument_is_passed_in_such_a_way_that_the_called_procedure_can_change_the_underlying_value_of_the_argument_in_the_calling_code))
            End If
 
            If optionalAndParamArrayAllowed Then
                defaultRecommendations.Add(New RecommendedKeyword("Optional", VBFeaturesResources.Specifies_that_a_procedure_argument_can_be_omitted_when_the_procedure_is_called))
                defaultRecommendations.Add(New RecommendedKeyword("ParamArray", VBFeaturesResources.Specifies_that_a_procedure_parameter_takes_an_optional_array_of_elements_of_the_specified_type))
            End If
 
            If methodDeclaration.ParameterList.OpenParenToken = targetToken Then
                Return defaultRecommendations.ToImmutableArray()
            ElseIf targetToken.Kind = SyntaxKind.CommaToken AndAlso targetToken.Parent.Kind = SyntaxKind.ParameterList Then
                ' Now we get to look at previous declarations and see what might still be valid
                For Each parameter In methodDeclaration.ParameterList.Parameters.Where(Function(p) p.FullSpan.End < context.Position)
                    ' If a previous one had a ParamArray, then nothing is valid anymore, since the ParamArray must
                    ' always be the last parameter
                    If parameter.Modifiers.Any(Function(modifier) modifier.Kind = SyntaxKind.ParamArrayKeyword) Then
                        Return ImmutableArray(Of RecommendedKeyword).Empty
                    End If
 
                    ' If a previous one had an Optional, then all following must be optional. Following Dev10 behavior,
                    ' we recommend just Optional as a first recommendation
                    If parameter.Modifiers.Any(Function(modifier) modifier.Kind = SyntaxKind.OptionalKeyword) AndAlso optionalAndParamArrayAllowed Then
                        Return defaultRecommendations.Where(Function(k) k.Keyword = "Optional").ToImmutableArray()
                    End If
                Next
 
                ' We had no special requirements, so return the default set
                Return defaultRecommendations.ToImmutableArray()
            ElseIf targetToken.Kind = SyntaxKind.OptionalKeyword AndAlso Not parameterAlreadyHasByValOrByRef Then
                Return defaultRecommendations.Where(Function(k) k.Keyword.StartsWith("By", StringComparison.Ordinal)).ToImmutableArray()
            ElseIf targetToken.Kind = SyntaxKind.ParamArrayKeyword AndAlso Not parameterAlreadyHasByValOrByRef Then
                Return defaultRecommendations.Where(Function(k) k.Keyword = "ByVal").ToImmutableArray()
            End If
 
            Return ImmutableArray(Of RecommendedKeyword).Empty
        End Function
    End Class
End Namespace