File: Completion\CompletionProviders\HandlesClauseCompletionProvider.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.Composition
Imports System.Runtime.CompilerServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.Completion
Imports Microsoft.CodeAnalysis.Completion.Providers
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
    <ExportCompletionProvider(NameOf(HandlesClauseCompletionProvider), LanguageNames.VisualBasic)>
    <ExtensionOrder(After:=NameOf(ImplementsClauseCompletionProvider))>
    <[Shared]>
    Partial Friend Class HandlesClauseCompletionProvider
        Inherits AbstractSymbolCompletionProvider(Of VisualBasicSyntaxContext)
 
        <ImportingConstructor>
        <Obsolete(MefConstruction.ImportingConstructorMessage, True)>
        Public Sub New()
        End Sub
 
        Friend Overrides ReadOnly Property Language As String
            Get
                Return LanguageNames.VisualBasic
            End Get
        End Property
 
        Protected Overrides Async Function GetSymbolsAsync(
                completionContext As CompletionContext,
                syntaxContext As VisualBasicSyntaxContext,
                position As Integer,
                options As CompletionOptions,
                cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of SymbolAndSelectionInfo))
 
            Dim symbols = Await GetSymbolsAsync(syntaxContext, position, cancellationToken).ConfigureAwait(False)
            Return symbols.SelectAsArray(Function(s) New SymbolAndSelectionInfo(s, Preselect:=False))
        End Function
 
        Private Overloads Shared Function GetSymbolsAsync(context As VisualBasicSyntaxContext, position As Integer, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of ISymbol))
            If context.SyntaxTree.IsInNonUserCode(position, cancellationToken) OrElse
                context.SyntaxTree.IsInSkippedText(position, cancellationToken) Then
                Return SpecializedTasks.EmptyImmutableArray(Of ISymbol)()
            End If
 
            If context.TargetToken.Kind = SyntaxKind.None Then
                Return SpecializedTasks.EmptyImmutableArray(Of ISymbol)()
            End If
 
            ' Handles or a comma
            If context.TargetToken.IsChildToken(Of HandlesClauseSyntax)(Function(hc) hc.HandlesKeyword) OrElse
                context.TargetToken.IsChildSeparatorToken(Function(hc As HandlesClauseSyntax) hc.Events) Then
                Return Task.FromResult(GetTopLevelIdentifiers(context, cancellationToken))
            End If
 
            ' Handles x. or , x.
            If context.TargetToken.IsChildToken(Of HandlesClauseItemSyntax)(Function(hc) hc.DotToken) Then
                Return Task.FromResult(LookUpEvents(context, context.TargetToken, cancellationToken))
            End If
 
            Return SpecializedTasks.EmptyImmutableArray(Of ISymbol)()
        End Function
 
        Public Overrides Function IsInsertionTrigger(text As SourceText, characterPosition As Integer, options As CompletionOptions) As Boolean
            Return CompletionUtilities.IsDefaultTriggerCharacter(text, characterPosition, options)
        End Function
 
        Public Overrides ReadOnly Property TriggerCharacters As ImmutableHashSet(Of Char) = CompletionUtilities.CommonTriggerChars
 
        Private Shared Function GetTopLevelIdentifiers(
            context As VisualBasicSyntaxContext,
            cancellationToken As CancellationToken
        ) As ImmutableArray(Of ISymbol)
 
            Dim containingSymbol = context.SemanticModel.GetEnclosingSymbol(context.Position, cancellationToken)
            Dim containingType = TryCast(containingSymbol, ITypeSymbol)
            If containingType Is Nothing Then
                ' We got the containing method as our enclosing type.
                containingType = containingSymbol.ContainingType
            End If
 
            If containingType Is Nothing Then
                ' We've somehow failed to find a containing type.
                Return ImmutableArray(Of ISymbol).Empty
            End If
 
            ' Instance or shared variables declared WithEvents
            Dim symbols = context.SemanticModel.LookupSymbols(context.Position, DirectCast(containingType, INamespaceOrTypeSymbol), includeReducedExtensionMethods:=True)
            Return symbols.WhereAsArray(Function(s) IsWithEvents(s))
        End Function
 
        Private Shared Function LookUpEvents(
            context As VisualBasicSyntaxContext,
            token As SyntaxToken,
            cancellationToken As CancellationToken
        ) As ImmutableArray(Of ISymbol)
 
            ' We came up on a dot, so the previous token will tell us in which object we should find events.
            Dim containingSymbol = context.SemanticModel.GetEnclosingSymbol(context.Position, cancellationToken)
            Dim containingType = TryCast(containingSymbol, ITypeSymbol)
            If containingType Is Nothing Then
                ' We got the containing method as our enclosing type.
                containingType = containingSymbol.ContainingType
            End If
 
            If containingType Is Nothing Then
                ' We've somehow failed to find a containing type.
                Return ImmutableArray(Of ISymbol).Empty
            End If
 
            Dim result = ImmutableArray(Of IEventSymbol).Empty
 
            Dim previousToken = token.GetPreviousToken()
            Select Case previousToken.Kind
                Case SyntaxKind.MeKeyword, SyntaxKind.MyClassKeyword
                    result = context.SemanticModel.LookupSymbols(context.Position, containingType).
                        OfType(Of IEventSymbol)().
                        ToImmutableArray()
                Case SyntaxKind.MyBaseKeyword
                    result = context.SemanticModel.LookupSymbols(context.Position, containingType.BaseType).
                        OfType(Of IEventSymbol)().
                        ToImmutableArray()
                Case SyntaxKind.IdentifierToken
                    ' We must be looking at a WithEvents property.
                    Dim symbolInfo = context.SemanticModel.GetSymbolInfo(previousToken, cancellationToken)
                    If symbolInfo.Symbol IsNot Nothing Then
                        Dim type = TryCast(symbolInfo.Symbol, IPropertySymbol)?.Type
                        If type IsNot Nothing Then
                            result = context.SemanticModel.LookupSymbols(token.SpanStart, type).
                                OfType(Of IEventSymbol)().
                                ToImmutableArray()
                        End If
                    End If
            End Select
 
            Return ImmutableArray(Of ISymbol).CastUp(result)
        End Function
 
        Private Shared Function IsWithEvents(s As ISymbol) As Boolean
            Dim [property] = TryCast(s, IPropertySymbol)
            If [property] IsNot Nothing Then
                Return [property].IsWithEvents
            End If
 
            Return False
        End Function
 
        Protected Overrides Function GetDisplayAndSuffixAndInsertionText(
                symbol As ISymbol, context As VisualBasicSyntaxContext) As (displayText As String, suffix As String, insertionText As String)
 
            Return CompletionUtilities.GetDisplayAndSuffixAndInsertionText(symbol, context)
        End Function
 
        Protected Overrides Function GetInsertionText(item As CompletionItem, ch As Char) As String
            Return CompletionUtilities.GetInsertionTextAtInsertionTime(item, ch)
        End Function
 
        Protected Overrides Function CreateItem(completionContext As CompletionContext, displayText As String, displayTextSuffix As String, insertionText As String, symbols As ImmutableArray(Of SymbolAndSelectionInfo), context As VisualBasicSyntaxContext, supportedPlatformData As SupportedPlatformData) As CompletionItem
            Return CreateItemDefault(displayText, displayTextSuffix, insertionText, symbols, context, supportedPlatformData)
        End Function
    End Class
End Namespace