File: Microsoft.NetCore.Analyzers\Performance\BasicUseStartsWithInsteadOfIndexOfComparisonWithZero.Fixer.vb
Web Access
Project: 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.Editing
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.NetCore.Analyzers.Performance

Namespace Microsoft.NetCore.VisualBasic.Analyzers.Performance

    <ExportCodeFixProvider(LanguageNames.VisualBasic), [Shared]>
    Public NotInheritable Class BasicUseStartsWithInsteadOfIndexOfComparisonWithZeroCodeFix
        Inherits UseStartsWithInsteadOfIndexOfComparisonWithZeroCodeFix

        Protected Overrides Function GetIndexOfInvocation(comparison As SyntaxNode) As SyntaxNode
            Dim binaryExpression = TryCast(comparison, BinaryExpressionSyntax)
            If binaryExpression Is Nothing Then
                Return Nothing
            End If

            Dim invocation = If(TryCast(binaryExpression.Left, InvocationExpressionSyntax), TryCast(binaryExpression.Right, InvocationExpressionSyntax))
            If invocation Is Nothing Then
                Return Nothing
            End If

            ' Every overload the fix handles is called with simple arguments; anything else is declined.
            For Each argument In invocation.ArgumentList.Arguments
                If TryCast(argument, SimpleArgumentSyntax) Is Nothing Then
                    Return Nothing
                End If
            Next

            Return invocation
        End Function

        Protected Overrides Function GetInstance(invocation As SyntaxNode) As SyntaxNode
            Return DirectCast(DirectCast(invocation, InvocationExpressionSyntax).Expression, MemberAccessExpressionSyntax).Expression
        End Function

        Protected Overrides Function GetArguments(invocation As SyntaxNode) As SyntaxNode()
            Return DirectCast(invocation, InvocationExpressionSyntax).ArgumentList.Arguments.ToArray()
        End Function

        Protected Overrides Function GetArgumentExpression(argument As SyntaxNode) As SyntaxNode
            Return DirectCast(argument, SimpleArgumentSyntax).Expression
        End Function

        Protected Overrides Function AppendElasticMarker(replacement As SyntaxNode) As SyntaxNode
            Return replacement.WithTrailingTrivia(SyntaxFactory.ElasticMarker)
        End Function

        Protected Overrides Function HandleCharStringComparisonOverload(generator As SyntaxGenerator, instance As SyntaxNode, arguments As SyntaxNode(), shouldNegate As Boolean) As SyntaxNode
            Dim index = GetCharacterArgumentIndex(arguments)
            Dim charArgumentSyntax = DirectCast(arguments(index), SimpleArgumentSyntax)
            If charArgumentSyntax.Expression.IsKind(SyntaxKind.CharacterLiteralExpression) Then
                ' For 'x.IndexOf(hardCodedConstantChar, stringComparison) == 0', switch to x.StartsWith(hardCodedString, stringComparison)
                Dim charValueAsString = DirectCast(charArgumentSyntax.Expression, LiteralExpressionSyntax).Token.Value.ToString()
                arguments(index) = charArgumentSyntax.WithExpression(DirectCast(generator.LiteralExpression(charValueAsString), ExpressionSyntax))
            Else
                ' The character isn't a hard-coded constant, it's some expression. We call `.ToString()` on it.
                arguments(index) = charArgumentSyntax.WithExpression(DirectCast(generator.InvocationExpression(generator.MemberAccessExpression(charArgumentSyntax.Expression, "ToString")), ExpressionSyntax))
            End If

            Return CreateStartsWithInvocationFromArguments(generator, instance, arguments, shouldNegate)
        End Function

        Private Shared Function GetCharacterArgumentIndex(arguments As SyntaxNode()) As Integer
            Dim firstArgument = DirectCast(arguments(0), SimpleArgumentSyntax)
            If firstArgument.NameColonEquals Is Nothing OrElse firstArgument.NameColonEquals.Name.Identifier.ValueText = "value" Then
                Return 0
            End If

            Return 1
        End Function
    End Class
End Namespace