File: Microsoft.NetCore.Analyzers\Performance\BasicDoNotUseCountWhenAnyCanBeUsedFixer.vb
Web Access
Project: src\src\sdk\src\Microsoft.CodeAnalysis.NetAnalyzers\src\Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers\Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers.vbproj (Microsoft.CodeAnalysis.VisualBasic.NetAnalyzers)
' Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the MIT license.  See License.txt in the project root for license information.

Imports System.Composition
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.NetCore.Analyzers.Performance

Namespace Microsoft.NetCore.VisualBasic.Analyzers.Performance
    ''' <summary>
    ''' CA1827: Do not use Count()/LongCount() when Any() can be used.
    ''' CA1828: Do not use CountAsync()/LongCountAsync() when AnyAsync() can be used.
    ''' </summary>
    <ExportCodeFixProvider(LanguageNames.VisualBasic), [Shared]>
    Public NotInheritable Class BasicDoNotUseCountWhenAnyCanBeUsedFixer
        Inherits DoNotUseCountWhenAnyCanBeUsedFixer

        ''' <summary>
        ''' Tries to get a fixer for the specified <paramref name="node" />.
        ''' </summary>
        ''' <param name="node">The node to get a fixer for.</param>
        ''' <param name="operation">The operation to get the fixer from.</param>
        ''' <param name="isAsync"><see langword="true" /> if it's an asynchronous method <see langword="false" /> otherwise.</param>
        ''' <param name="expression">If this method returns <see langword="true" />, contains the expression to be used to invoke <c>Any</c>.</param>
        ''' <param name="arguments">If this method returns <see langword="true" />, contains the arguments from <c>Any</c> to be used on <c>Count</c>.</param>
        ''' <returns><see langword="true" /> if a fixer was found., <see langword="false" /> otherwise.</returns>
        Protected Overrides Function TryGetFixer(node As SyntaxNode, operation As String, isAsync As Boolean, ByRef expression As SyntaxNode, ByRef arguments As IEnumerable(Of SyntaxNode)) As Boolean

            Select Case operation

                Case UseCountProperlyAnalyzer.OperationEqualsInstance

                    Dim invocation = TryCast(node, InvocationExpressionSyntax)

                    If invocation IsNot Nothing Then

                        Dim member = TryCast(invocation.Expression, MemberAccessExpressionSyntax)

                        If member IsNot Nothing Then

                            Return TryGetExpressionAndInvocationArguments(
                                sourceExpression:=member.Expression,
                                isAsync:=isAsync,
                                expression:=expression,
                                arguments:=arguments)

                        End If

                    End If

                Case UseCountProperlyAnalyzer.OperationEqualsArgument

                    Dim invocation = TryCast(node, InvocationExpressionSyntax)

                    If invocation IsNot Nothing AndAlso invocation.ArgumentList.Arguments.Count = 1 Then

                        Return TryGetExpressionAndInvocationArguments(
                            sourceExpression:=invocation.ArgumentList.Arguments(0).GetExpression(),
                            isAsync:=isAsync,
                            expression:=expression,
                            arguments:=arguments)

                    End If

                Case UseCountProperlyAnalyzer.OperationBinaryLeft

                    Dim binary = TryCast(node, BinaryExpressionSyntax)

                    If binary IsNot Nothing Then

                        Return TryGetExpressionAndInvocationArguments(
                            sourceExpression:=binary.Left,
                            isAsync:=isAsync,
                            expression:=expression,
                            arguments:=arguments)
                    End If

                Case UseCountProperlyAnalyzer.OperationBinaryRight

                    Dim binary = TryCast(node, BinaryExpressionSyntax)

                    If binary IsNot Nothing Then

                        Return TryGetExpressionAndInvocationArguments(
                            sourceExpression:=binary.Right,
                            isAsync:=isAsync,
                            expression:=expression,
                            arguments:=arguments)

                    End If

            End Select

            Return False

        End Function

        Private Shared Function TryGetExpressionAndInvocationArguments(sourceExpression As ExpressionSyntax, isAsync As Boolean, ByRef expression As SyntaxNode, ByRef arguments As IEnumerable(Of SyntaxNode)) As Boolean

            Dim parenthesizedExpression = TryCast(sourceExpression, ParenthesizedExpressionSyntax)

            While parenthesizedExpression IsNot Nothing

                sourceExpression = parenthesizedExpression.Expression
                parenthesizedExpression = TryCast(sourceExpression, ParenthesizedExpressionSyntax)

            End While

            If isAsync Then

                Dim awaitExpressionSyntax = TryCast(sourceExpression, AwaitExpressionSyntax)

                If awaitExpressionSyntax IsNot Nothing Then

                    sourceExpression = awaitExpressionSyntax.Expression

                End If

            End If

            Dim invocationExpression As InvocationExpressionSyntax = TryCast(sourceExpression, InvocationExpressionSyntax)

            If invocationExpression IsNot Nothing Then

                expression = DirectCast(invocationExpression.Expression, MemberAccessExpressionSyntax).Expression
                arguments = invocationExpression.ArgumentList.ChildNodes()
                Return True

            End If

            '  Try to get source expression as MemberAccessExpression which is only legal on VB.
            Dim memberAccessExpression = TryCast(sourceExpression, MemberAccessExpressionSyntax)

            ' This case happens for something like: x = GetData().Count where Count method is called without parentheses.
            If memberAccessExpression IsNot Nothing Then
                expression = memberAccessExpression.Expression
                arguments = Enumerable.Empty(Of SyntaxNode)()
                Return True
            End If

            expression = Nothing
            arguments = Nothing
            Return False
        End Function

    End Class

End Namespace