' 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 Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports System.Runtime.InteropServices
Imports System.Threading

Namespace Microsoft.CodeAnalysis.VisualBasic

    ''' <summary>
    ''' Binder used for interiors of documentation comment for binding 'cref' attribute value
    ''' </summary>
    Partial Friend NotInheritable Class DocumentationCommentCrefBinder
        Inherits DocumentationCommentBinder

        Public Sub New(containingBinder As Binder, commentedSymbol As Symbol)
            MyBase.New(containingBinder, commentedSymbol)
        End Sub

        Private _typeParameterBinder As TypeParametersBinder

        Private Function GetOrCreateTypeParametersAwareBinder(typeParameters As Dictionary(Of String, CrefTypeParameterSymbol)) As Binder
            If Me._typeParameterBinder Is Nothing Then
                Interlocked.CompareExchange(Me._typeParameterBinder, New TypeParametersBinder(Me, typeParameters), Nothing)
            End If

#If DEBUG Then
            ' Make sure the type parameter symbols are the same
            Debug.Assert(typeParameters.Count = Me._typeParameterBinder._typeParameters.Count)
            For Each kvp In typeParameters
                Debug.Assert(kvp.Value.Equals(Me._typeParameterBinder._typeParameters(kvp.Key)))
            Next
#End If

            Return Me._typeParameterBinder
        End Function

        Private Shared Function HasTrailingSkippedTokensAndShouldReportError(reference As CrefReferenceSyntax) As Boolean
            Dim triviaList As SyntaxTriviaList = reference.GetTrailingTrivia()
            For Each trivia In triviaList
                If trivia.Kind = SyntaxKind.SkippedTokensTrivia Then
                    ' ignore those, representing VB intrinsic types
                    Dim name As TypeSyntax = reference.Name
                    If name.Kind = SyntaxKind.IdentifierName Then
                        Dim identifier As SyntaxToken = DirectCast(name, IdentifierNameSyntax).Identifier
                        If Not identifier.IsBracketed AndAlso IsIntrinsicTypeForDocumentationComment(SyntaxFacts.GetKeywordKind(identifier.ValueText)) Then
                            ' special case to be ignored, also see description 
                            ' in ParseXml.vb::TryParseXmlCrefAttributeValue(...)
                            Continue For
                        End If

                    ElseIf name.Kind = SyntaxKind.PredefinedType Then
                        Continue For
                    End If

                    ' Otherwise report an error
                    Return True
                End If
            Next

            Return False
        End Function

        Friend Overrides Function BindInsideCrefAttributeValue(reference As CrefReferenceSyntax, preserveAliases As Boolean, diagnosticBag As DiagnosticBag, <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo)) As ImmutableArray(Of Symbol)
            ' If the node has trailing syntax nodes, it should report error, unless the name 
            ' is a VB intrinsic type (which ensures compatibility with Dev11)
            If HasTrailingSkippedTokensAndShouldReportError(reference) Then
                Return ImmutableArray(Of Symbol).Empty
            End If

            If reference.Signature Is Nothing Then
                Return BindNameInsideCrefReferenceInLegacyMode(reference.Name, preserveAliases, useSiteDiagnostics)
            End If

            ' Extended 'cref' attribute syntax should not contain complex generic arguments 
            ' such as in [cref="List(Of Action(Of A))"], because these generic arguments actually 
            ' define type parameters to be used in signature part and return value
            If NameSyntaxHasComplexGenericArguments(reference.Name) Then
                Return ImmutableArray(Of Symbol).Empty
            End If

            Dim symbols = ArrayBuilder(Of Symbol).GetInstance

            ' Bind the name part and collect type parameters
            Dim typeParameters As New Dictionary(Of String, CrefTypeParameterSymbol)(CaseInsensitiveComparison.Comparer)
            CollectCrefNameSymbolsStrict(reference.Name, reference.Signature.ArgumentTypes.Count, typeParameters, symbols, preserveAliases, useSiteDiagnostics)
            If symbols.Count = 0 Then
                symbols.Free()
                Return ImmutableArray(Of Symbol).Empty
            End If

            RemoveOverriddenMethodsAndProperties(symbols)

            ' Bind signature and return type if present
            Dim signatureTypes As ArrayBuilder(Of SignatureElement) = Nothing
            Dim returnType As TypeSymbol = Nothing
            BindSignatureAndReturnValue(reference, typeParameters, signatureTypes, returnType, diagnosticBag)

            ' Create only if needed
            Debug.Assert(signatureTypes Is Nothing OrElse signatureTypes.Count > 0)
            Dim signatureParameterCount As Integer = If(signatureTypes Is Nothing, 0, signatureTypes.Count)

            '  Choose between symbols those with matching signatures
            Dim candidatePointer As Integer = 0
            Dim goodPointer As Integer = 0

            While candidatePointer < symbols.Count
                Dim candidateSymbol As Symbol = symbols(candidatePointer)

                ' NOTE: we do a very simple signature check and 
                '       avoid using signature comparer

                Select Case candidateSymbol.Kind
                    Case SymbolKind.Method
                        Dim candidateMethod = DirectCast(candidateSymbol, MethodSymbol)

                        If candidateMethod.ParameterCount <> signatureParameterCount Then
                            ' Signature does not match
                            Exit Select
                        End If

                        Dim parameters As ImmutableArray(Of ParameterSymbol) = candidateMethod.Parameters
                        For i = 0 To signatureParameterCount - 1
                            Dim parameter As ParameterSymbol = parameters(i)
                            If parameter.IsByRef <> signatureTypes(i).IsByRef OrElse
                                    Not parameter.Type.IsSameTypeIgnoringAll(signatureTypes(i).Type) Then

                                ' Signature does not match
                                Exit Select
                            End If
                        Next

                        If returnType IsNot Nothing Then
                            If candidateMethod.IsSub OrElse Not candidateMethod.ReturnType.IsSameTypeIgnoringAll(returnType) Then
                                ' Return type does not match
                                Exit Select
                            End If
                        End If

                        ' Good candidate
                        symbols(goodPointer) = candidateSymbol
                        goodPointer += 1
                        candidatePointer += 1
                        Continue While

                    Case SymbolKind.Property
                        Dim candidateProperty = DirectCast(candidateSymbol, PropertySymbol)
                        Dim parameters As ImmutableArray(Of ParameterSymbol) = candidateProperty.Parameters

                        If parameters.Length <> signatureParameterCount Then
                            ' Signature does not match
                            Exit Select
                        End If

                        For i = 0 To signatureParameterCount - 1
                            Dim parameter As ParameterSymbol = parameters(i)
                            If parameter.IsByRef <> signatureTypes(i).IsByRef OrElse
                                    Not parameter.Type.IsSameTypeIgnoringAll(signatureTypes(i).Type) Then

                                ' Signature does not match
                                Exit Select
                            End If
                        Next

                        Debug.Assert(returnType Is Nothing,
                                     "Return type is only allowed for Operator CType, why we found a property here?")

                        ' Good candidate
                        symbols(goodPointer) = candidateSymbol
                        goodPointer += 1
                        candidatePointer += 1
                        Continue While

                    Case Else
                        ' All other symbols are ignored
                End Select

                ' Ignore symbol
                candidatePointer += 1
            End While

            If signatureTypes IsNot Nothing Then
                signatureTypes.Free()
            End If

            If goodPointer < candidatePointer Then
                symbols.Clip(goodPointer)
            End If

            Return symbols.ToImmutableAndFree()
        End Function

        Friend Overrides Function BindInsideCrefAttributeValue(name As TypeSyntax, preserveAliases As Boolean, diagnosticBag As DiagnosticBag, <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo)) As ImmutableArray(Of Symbol)
            Dim isPartOfSignatureOrReturnType As Boolean = False
            Dim crefReference As CrefReferenceSyntax = GetEnclosingCrefReference(name, isPartOfSignatureOrReturnType)

            If crefReference Is Nothing Then
                Debug.Assert(False, "Speculative binding??")
                Return ImmutableArray(Of Symbol).Empty
            End If

            If crefReference.Signature Is Nothing Then
                Debug.Assert(Not isPartOfSignatureOrReturnType)
                Return BindNameInsideCrefReferenceInLegacyMode(name, preserveAliases, useSiteDiagnostics)
            End If

            If isPartOfSignatureOrReturnType Then
                Return BindInsideCrefSignatureOrReturnType(crefReference, name, preserveAliases, diagnosticBag)
            Else
                Return BindInsideCrefReferenceName(name, crefReference.Signature.ArgumentTypes.Count, preserveAliases, useSiteDiagnostics)
            End If
        End Function

        Private Function BindInsideCrefSignatureOrReturnType(crefReference As CrefReferenceSyntax, name As TypeSyntax, preserveAliases As Boolean, diagnosticBag As DiagnosticBag) As ImmutableArray(Of Symbol)
            Dim typeParameterAwareBinder As Binder = Me.GetOrCreateTypeParametersAwareBinder(crefReference)

            Dim result As Symbol
            If (diagnosticBag Is Nothing) Then
                Dim diagnostics = DiagnosticBag.GetInstance
                result = typeParameterAwareBinder.BindNamespaceOrTypeOrAliasSyntax(name, diagnostics)
                diagnostics.Free()
            Else
                result = typeParameterAwareBinder.BindNamespaceOrTypeOrAliasSyntax(name, diagnosticBag)
            End If

            If result IsNot Nothing AndAlso result.Kind = SymbolKind.Alias AndAlso Not preserveAliases Then
                result = DirectCast(result, AliasSymbol).Target
            End If

            Return If(result Is Nothing,
                      ImmutableArray(Of Symbol).Empty,
                      ImmutableArray.Create(Of Symbol)(result))
        End Function

        Private Function GetOrCreateTypeParametersAwareBinder(crefReference As CrefReferenceSyntax) As Binder
            ' To create type-param-aware binder we need to have type parameters, 
            ' but we don't want to do so if the binder is already created
            If Me._typeParameterBinder IsNot Nothing Then
                Return Me._typeParameterBinder
            End If

            Dim typeParameters As New Dictionary(Of String, CrefTypeParameterSymbol)(IdentifierComparison.Comparer)

            Dim crefName As TypeSyntax = crefReference.Name
            Dim genericName As GenericNameSyntax = Nothing

            While crefName IsNot Nothing

                Select Case crefName.Kind
                    Case SyntaxKind.GenericName
                        genericName = DirectCast(crefName, GenericNameSyntax)
                        crefName = Nothing

                    Case SyntaxKind.QualifiedName
                        Dim qName = DirectCast(crefName, QualifiedNameSyntax)
                        crefName = qName.Left

                        If qName.Right.Kind = SyntaxKind.GenericName Then
                            genericName = DirectCast(qName.Right, GenericNameSyntax)
                        End If

                    Case SyntaxKind.IdentifierName,
                         SyntaxKind.CrefOperatorReference,
                         SyntaxKind.GlobalName,
                         SyntaxKind.PredefinedType
                        Exit While

                    Case SyntaxKind.QualifiedCrefOperatorReference
                        crefName = DirectCast(crefName, QualifiedCrefOperatorReferenceSyntax).Left

                    Case Else
                        Throw ExceptionUtilities.UnexpectedValue(crefName.Kind)
                End Select

                ' Fall back to the next name part, if we need to collect type 
                ' parameters genericName is supposed to be not Nothing
                If genericName IsNot Nothing Then
                    Dim arguments As SeparatedSyntaxList(Of TypeSyntax) = genericName.TypeArgumentList.Arguments

                    For i = 0 To arguments.Count - 1
                        Dim typeSyntax As TypeSyntax = arguments(i)

                        Select Case typeSyntax.Kind
                            Case SyntaxKind.IdentifierName
                                Dim identifier = DirectCast(typeSyntax, IdentifierNameSyntax)
                                Dim typeParameterName As String = identifier.Identifier.ValueText

                                ' As we go 'left-to-right' don't override right-most parameters with the same name
                                If Not typeParameters.ContainsKey(typeParameterName) Then
                                    typeParameters(typeParameterName) = New CrefTypeParameterSymbol(i, typeParameterName, identifier)
                                End If

                            Case Else
                                ' An error case
                        End Select
                    Next
                End If

            End While

            Return GetOrCreateTypeParametersAwareBinder(typeParameters)
        End Function

        Private Function BindInsideCrefReferenceName(name As TypeSyntax, argCount As Integer, preserveAliases As Boolean, <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo)) As ImmutableArray(Of Symbol)
            ' NOTE: in code here and below 'parent' may be Nothing in 
            '       case of speculative binding (which is NYI)
            Dim parent As VisualBasicSyntaxNode = name.Parent

            ' Type parameter
            If parent IsNot Nothing AndAlso parent.Kind = SyntaxKind.TypeArgumentList Then
                Dim ordinal As Integer = DirectCast(parent, TypeArgumentListSyntax).Arguments.IndexOf(name)

                If name.Kind = SyntaxKind.IdentifierName Then
                    Dim identifier = DirectCast(name, IdentifierNameSyntax)
                    Return ImmutableArray.Create(Of Symbol)(New CrefTypeParameterSymbol(ordinal, identifier.Identifier.ValueText, identifier))
                End If

                ' An error case
                Return ImmutableArray.Create(Of Symbol)(New CrefTypeParameterSymbol(ordinal, StringConstants.NamedSymbolErrorName, name))
            End If

            ' Names considered to be checked for color-color case are Identifier or Generic names which 
            ' are the left part of the qualified name parent 
            Dim checkForColorColor As Boolean = False
            Dim nameText As String = Nothing
            Dim arity As Integer = -1

lAgain:
            Select Case name.Kind
                Case SyntaxKind.IdentifierName,
                     SyntaxKind.GenericName

                    If parent IsNot Nothing AndAlso parent.Kind = SyntaxKind.QualifiedName Then
                        Dim qualified = DirectCast(parent, QualifiedNameSyntax)
                        If qualified.Right Is name Then
                            name = qualified
                            parent = name.Parent
                            GoTo lAgain
                        End If
                    End If

                    ' color-color info
                    checkForColorColor = True
                    If name.Kind = SyntaxKind.IdentifierName Then
                        nameText = DirectCast(name, IdentifierNameSyntax).Identifier.ValueText
                        arity = 0

                    Else
                        Dim generic = DirectCast(name, GenericNameSyntax)
                        nameText = generic.Identifier.ValueText
                        arity = generic.TypeArgumentList.Arguments.Count
                    End If

                ' Fall through

                Case SyntaxKind.CrefOperatorReference
                    If parent IsNot Nothing AndAlso parent.Kind = SyntaxKind.QualifiedCrefOperatorReference Then
                        name = DirectCast(parent, QualifiedCrefOperatorReferenceSyntax)
                        parent = name.Parent
                        GoTo lAgain
                    End If
                ' Fall through

                Case SyntaxKind.QualifiedName,
                     SyntaxKind.QualifiedCrefOperatorReference
                    ' Fall through

                Case SyntaxKind.GlobalName
                    Return ImmutableArray.Create(Of Symbol)(Me.Compilation.GlobalNamespace)

                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(name.Kind)
            End Select

            Dim symbols = ArrayBuilder(Of Symbol).GetInstance
            CollectCrefNameSymbolsStrict(name, argCount, New Dictionary(Of String, CrefTypeParameterSymbol)(IdentifierComparison.Comparer), symbols, preserveAliases, useSiteDiagnostics)

            RemoveOverriddenMethodsAndProperties(symbols)

            If symbols.Count = 1 AndAlso checkForColorColor Then
                Dim symbol As Symbol = symbols(0)
                Dim type As TypeSymbol = Nothing

                Select Case symbol.Kind
                    Case SymbolKind.Field
                        type = DirectCast(symbol, FieldSymbol).Type

                    Case SymbolKind.Method
                        type = DirectCast(symbol, MethodSymbol).ReturnType

                    Case SymbolKind.Property
                        type = DirectCast(symbol, PropertySymbol).Type
                End Select

                Dim replaceWithType As Boolean = False
                If type IsNot Nothing Then
                    If IdentifierComparison.Equals(type.Name, nameText) Then
                        Dim namedType = TryCast(type, NamedTypeSymbol)

                        If namedType IsNot Nothing Then
                            replaceWithType = namedType.Arity = arity
                        Else
                            replaceWithType = arity = 0
                        End If
                    End If
                End If

                If replaceWithType Then
                    symbols(0) = type
                End If
            End If

            Return symbols.ToImmutableAndFree()
        End Function

        Private Shared Function GetEnclosingCrefReference(nameFromCref As TypeSyntax, <Out> ByRef partOfSignatureOrReturnType As Boolean) As CrefReferenceSyntax
            partOfSignatureOrReturnType = False

            Dim node As VisualBasicSyntaxNode = nameFromCref
            While node IsNot Nothing

                Select Case node.Kind
                    Case SyntaxKind.CrefReference
                        Exit While

                    Case SyntaxKind.SimpleAsClause
                        partOfSignatureOrReturnType = True

                    Case SyntaxKind.CrefSignature
                        partOfSignatureOrReturnType = True
                End Select

                node = node.Parent
            End While

            Return DirectCast(node, CrefReferenceSyntax)
        End Function

        Private Structure SignatureElement
            Public ReadOnly Type As TypeSymbol
            Public ReadOnly IsByRef As Boolean

            Public Sub New(type As TypeSymbol, isByRef As Boolean)
                Me.Type = type
                Me.IsByRef = isByRef
            End Sub
        End Structure

        Private Sub BindSignatureAndReturnValue(reference As CrefReferenceSyntax,
                                                typeParameters As Dictionary(Of String, CrefTypeParameterSymbol),
                                                <Out> ByRef signatureTypes As ArrayBuilder(Of SignatureElement),
                                                <Out> ByRef returnType As TypeSymbol,
                                                diagnosticBag As DiagnosticBag)

            signatureTypes = Nothing
            returnType = Nothing

            Dim typeParameterAwareBinder As Binder = Me.GetOrCreateTypeParametersAwareBinder(typeParameters)
            Dim diagnostic = If(diagnosticBag, DiagnosticBag.GetInstance())

            Dim signature As CrefSignatureSyntax = reference.Signature
            Debug.Assert(signature IsNot Nothing)

            If signature.ArgumentTypes.Count > 0 Then
                signatureTypes = ArrayBuilder(Of SignatureElement).GetInstance

                For Each part In signature.ArgumentTypes
                    signatureTypes.Add(
                        New SignatureElement(
                            typeParameterAwareBinder.BindTypeSyntax(part.Type, diagnostic),
                            part.Modifier.Kind = SyntaxKind.ByRefKeyword))
                Next
            End If

            If reference.AsClause IsNot Nothing Then
                returnType = typeParameterAwareBinder.BindTypeSyntax(reference.AsClause.Type, diagnostic)
            End If

            If diagnosticBag Is Nothing Then diagnostic.Free()
        End Sub

        Private Sub CollectCrefNameSymbolsStrict(nameFromCref As TypeSyntax,
                                                 argsCount As Integer,
                                                 typeParameters As Dictionary(Of String, CrefTypeParameterSymbol),
                                                 symbols As ArrayBuilder(Of Symbol),
                                                 preserveAlias As Boolean,
                                                 <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo))

            ' This binding mode is used for extended cref-reference syntax with mandatory
            ' signature specified, we enforce more strict rules in this case

            Select Case nameFromCref.Kind
                Case SyntaxKind.QualifiedCrefOperatorReference
                    ' 'A.B.Operator+' or 'C(Of T).Operator CType'
                    CollectQualifiedOperatorReferenceSymbolsStrict(
                        DirectCast(nameFromCref, QualifiedCrefOperatorReferenceSyntax), argsCount, typeParameters, symbols, useSiteDiagnostics)

                Case SyntaxKind.CrefOperatorReference
                    ' 'Operator+' or 'Operator CType'
                    CollectTopLevelOperatorReferenceStrict(
                        DirectCast(nameFromCref, CrefOperatorReferenceSyntax), argsCount, symbols, useSiteDiagnostics)

                Case SyntaxKind.IdentifierName,
                     SyntaxKind.GenericName
                    ' 'New', 'A', or 'B(Of T)'
                    CollectSimpleNameSymbolsStrict(
                        DirectCast(nameFromCref, SimpleNameSyntax), typeParameters, symbols, preserveAlias, useSiteDiagnostics, False)

                Case SyntaxKind.QualifiedName
                    ' 'A(Of T).B.M(Of E)'
                    CollectQualifiedNameSymbolsStrict(
                        DirectCast(nameFromCref, QualifiedNameSyntax), typeParameters, symbols, preserveAlias, useSiteDiagnostics)

                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(nameFromCref.Kind)
            End Select
        End Sub

        Private Sub CollectTopLevelOperatorReferenceStrict(reference As CrefOperatorReferenceSyntax, argCount As Integer, symbols As ArrayBuilder(Of Symbol), <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo))
            CollectOperatorsAndConversionsInType(reference, argCount, Me.ContainingType, symbols, useSiteDiagnostics)
        End Sub

        Private Sub CollectSimpleNameSymbolsStrict(node As SimpleNameSyntax,
                                                   typeParameters As Dictionary(Of String, CrefTypeParameterSymbol),
                                                   symbols As ArrayBuilder(Of Symbol),
                                                   preserveAlias As Boolean,
                                                   <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo),
                                                   typeOrNamespaceOnly As Boolean)

            ' Name syntax of Cref should not have diagnostics
            If node.ContainsDiagnostics Then
                Return
            End If

            If node.Kind = SyntaxKind.GenericName Then
                ' Generic name
                Dim genericName = DirectCast(node, GenericNameSyntax)

                ' Search exact arity only
                CollectSimpleNameSymbolsStrict(genericName.Identifier.ValueText,
                                               genericName.TypeArgumentList.Arguments.Count,
                                               symbols,
                                               preserveAlias,
                                               useSiteDiagnostics,
                                               typeOrNamespaceOnly)

                CreateTypeParameterSymbolsAndConstructSymbols(genericName, symbols, typeParameters)

            Else
                ' Simple identifier name
                Debug.Assert(node.Kind = SyntaxKind.IdentifierName)

                Dim identifier = DirectCast(node, IdentifierNameSyntax)
                Dim token As SyntaxToken = identifier.Identifier

                If IdentifierComparison.Equals(identifier.Identifier.ValueText, SyntaxFacts.GetText(SyntaxKind.NewKeyword)) AndAlso Not token.IsBracketed Then
                    CollectConstructorsSymbolsStrict(symbols)

                Else
                    ' Search 0-arity only
                    CollectSimpleNameSymbolsStrict(identifier.Identifier.ValueText, 0, symbols, preserveAlias, useSiteDiagnostics, typeOrNamespaceOnly)
                End If
            End If
        End Sub

        Private Sub CollectQualifiedNameSymbolsStrict(node As QualifiedNameSyntax,
                                                      typeParameters As Dictionary(Of String, CrefTypeParameterSymbol),
                                                      symbols As ArrayBuilder(Of Symbol),
                                                      preserveAlias As Boolean,
                                                      <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo))

            ' Name syntax of Cref should not have diagnostics
            If node.ContainsDiagnostics Then
                Return
            End If

            Dim allowColorColor As Boolean = True

            Dim left As NameSyntax = node.Left
            Select Case left.Kind
                Case SyntaxKind.IdentifierName
                    CollectSimpleNameSymbolsStrict(DirectCast(left, SimpleNameSyntax), typeParameters, symbols, preserveAlias:=False, useSiteDiagnostics:=useSiteDiagnostics, typeOrNamespaceOnly:=True)

                Case SyntaxKind.GenericName
                    CollectSimpleNameSymbolsStrict(DirectCast(left, SimpleNameSyntax), typeParameters, symbols, preserveAlias:=False, useSiteDiagnostics:=useSiteDiagnostics, typeOrNamespaceOnly:=True)

                Case SyntaxKind.QualifiedName
                    CollectQualifiedNameSymbolsStrict(DirectCast(left, QualifiedNameSyntax), typeParameters, symbols, preserveAlias:=False, useSiteDiagnostics:=useSiteDiagnostics)
                    allowColorColor = False

                Case SyntaxKind.GlobalName
                    symbols.Add(Me.Compilation.GlobalNamespace)

                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(left.Kind)
            End Select

            If symbols.Count <> 1 Then
                ' Stop resolving
                typeParameters.Clear()
                symbols.Clear()
                Return
            End If

            Dim singleSymbol As Symbol = symbols(0)
            symbols.Clear()

            ' We found one single symbol, we need to search for the 'right' 
            ' name in the context of this symbol
            Dim right As SimpleNameSyntax = node.Right

            If right.Kind = SyntaxKind.GenericName Then
                ' Generic name
                Dim genericName = DirectCast(right, GenericNameSyntax)

                ' Search exact arity only
                CollectSimpleNameSymbolsStrict(singleSymbol,
                                               allowColorColor,
                                               genericName.Identifier.ValueText,
                                               genericName.TypeArgumentList.Arguments.Count,
                                               symbols,
                                               preserveAlias,
                                               useSiteDiagnostics)

                CreateTypeParameterSymbolsAndConstructSymbols(genericName, symbols, typeParameters)

            Else
                ' Simple identifier name
                Debug.Assert(right.Kind = SyntaxKind.IdentifierName)

                Dim identifier = DirectCast(right, IdentifierNameSyntax)
                Dim token As SyntaxToken = identifier.Identifier

                If IdentifierComparison.Equals(identifier.Identifier.ValueText, SyntaxFacts.GetText(SyntaxKind.NewKeyword)) AndAlso Not token.IsBracketed Then
                    CollectConstructorsSymbolsStrict(singleSymbol, symbols)

                Else
                    ' Search 0-arity only
                    CollectSimpleNameSymbolsStrict(singleSymbol, allowColorColor, identifier.Identifier.ValueText, 0, symbols, preserveAlias, useSiteDiagnostics)
                End If
            End If
        End Sub

        Private Sub CollectQualifiedOperatorReferenceSymbolsStrict(node As QualifiedCrefOperatorReferenceSyntax,
                                                                   argCount As Integer,
                                                                   typeParameters As Dictionary(Of String, CrefTypeParameterSymbol),
                                                                   symbols As ArrayBuilder(Of Symbol),
                                                                   <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo))

            ' Name syntax of Cref should not have diagnostics
            If node.ContainsDiagnostics Then
                Return
            End If

            Dim allowColorColor As Boolean = True

            Dim left As NameSyntax = node.Left
            Select Case left.Kind
                Case SyntaxKind.IdentifierName
                    CollectSimpleNameSymbolsStrict(DirectCast(left, SimpleNameSyntax), typeParameters, symbols, preserveAlias:=False, useSiteDiagnostics:=useSiteDiagnostics, typeOrNamespaceOnly:=True)

                Case SyntaxKind.GenericName
                    CollectSimpleNameSymbolsStrict(DirectCast(left, SimpleNameSyntax), typeParameters, symbols, preserveAlias:=False, useSiteDiagnostics:=useSiteDiagnostics, typeOrNamespaceOnly:=True)

                Case SyntaxKind.QualifiedName
                    CollectQualifiedNameSymbolsStrict(DirectCast(left, QualifiedNameSyntax), typeParameters, symbols, preserveAlias:=False, useSiteDiagnostics:=useSiteDiagnostics)
                    allowColorColor = False

                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(left.Kind)
            End Select

            If symbols.Count <> 1 Then
                ' Stop resolving
                typeParameters.Clear()
                symbols.Clear()
                Return
            End If

            Dim singleSymbol As Symbol = symbols(0)
            symbols.Clear()

            If singleSymbol.Kind = SymbolKind.Alias Then
                singleSymbol = DirectCast(singleSymbol, AliasSymbol).Target
            End If

            CollectOperatorsAndConversionsInType(node.Right, argCount, TryCast(singleSymbol, TypeSymbol), symbols, useSiteDiagnostics)
        End Sub

        Private Sub CollectConstructorsSymbolsStrict(symbols As ArrayBuilder(Of Symbol))
            Dim containingSymbol As Symbol = Me.ContainingMember
            If containingSymbol Is Nothing Then
                Return
            End If

            If containingSymbol.Kind <> SymbolKind.NamedType Then
                containingSymbol = containingSymbol.ContainingType
            End If

            Dim type = DirectCast(containingSymbol, NamedTypeSymbol)
            If type IsNot Nothing Then
                symbols.AddRange(type.InstanceConstructors)
            End If
            Return
        End Sub

        Private Shared Sub CollectConstructorsSymbolsStrict(containingSymbol As Symbol, symbols As ArrayBuilder(Of Symbol))
            Debug.Assert(symbols.Count = 0)
            If containingSymbol.Kind = SymbolKind.NamedType Then
                symbols.AddRange(DirectCast(containingSymbol, NamedTypeSymbol).InstanceConstructors)
            End If
        End Sub

        Private Sub CollectSimpleNameSymbolsStrict(name As String,
                                                   arity As Integer,
                                                   symbols As ArrayBuilder(Of Symbol),
                                                   preserveAlias As Boolean,
                                                   <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo),
                                                   typeOrNamespaceOnly As Boolean)

            Debug.Assert(Not String.IsNullOrEmpty(name))
            Debug.Assert(arity >= 0)

            Const options As LookupOptions =
                                LookupOptions.UseBaseReferenceAccessibility Or
                                LookupOptions.MustNotBeReturnValueVariable Or
                                LookupOptions.IgnoreExtensionMethods Or
                                LookupOptions.MustNotBeLocalOrParameter Or
                                LookupOptions.NoSystemObjectLookupForInterfaces

            Dim result As LookupResult = LookupResult.GetInstance()

            Me.Lookup(result, name, arity, If(typeOrNamespaceOnly, options Or LookupOptions.NamespacesOrTypesOnly, options), useSiteDiagnostics)

            If Not result.IsGoodOrAmbiguous OrElse Not result.HasSymbol Then
                result.Free()
                Return
            End If

            CollectGoodOrAmbiguousFromLookupResult(result, symbols, preserveAlias)
            result.Free()
        End Sub

        Private Sub CollectSimpleNameSymbolsStrict(containingSymbol As Symbol,
                                                   allowColorColor As Boolean,
                                                   name As String,
                                                   arity As Integer,
                                                   symbols As ArrayBuilder(Of Symbol),
                                                   preserveAlias As Boolean,
                                                   <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo))

            Debug.Assert(Not String.IsNullOrEmpty(name))
            Debug.Assert(arity >= 0)

            Dim lookupResult As LookupResult = lookupResult.GetInstance()

            Dim options As LookupOptions = LookupOptions.UseBaseReferenceAccessibility Or
                                           LookupOptions.MustNotBeReturnValueVariable Or
                                           LookupOptions.IgnoreExtensionMethods Or
                                           LookupOptions.MustNotBeLocalOrParameter Or
                                           LookupOptions.NoSystemObjectLookupForInterfaces
lAgain:
            Select Case containingSymbol.Kind
                Case SymbolKind.Namespace
                    LookupMember(lookupResult, DirectCast(containingSymbol, NamespaceSymbol), name, arity, options, useSiteDiagnostics)

                Case SymbolKind.Alias
                    containingSymbol = DirectCast(containingSymbol, AliasSymbol).Target
                    GoTo lAgain

                Case SymbolKind.NamedType, SymbolKind.ArrayType
                    LookupMember(lookupResult, DirectCast(containingSymbol, TypeSymbol), name, arity, options, useSiteDiagnostics)

                Case SymbolKind.Property
                    If allowColorColor Then
                        ' Check for Color Color case
                        Dim [property] = DirectCast(containingSymbol, PropertySymbol)
                        Dim propertyType As TypeSymbol = [property].Type
                        If IdentifierComparison.Equals([property].Name, propertyType.Name) Then
                            containingSymbol = propertyType
                            GoTo lAgain
                        End If
                    End If

                Case SymbolKind.Field
                    If allowColorColor Then
                        ' Check for Color Color case
                        Dim field = DirectCast(containingSymbol, FieldSymbol)
                        Dim fieldType As TypeSymbol = field.Type
                        If IdentifierComparison.Equals(field.Name, fieldType.Name) Then
                            containingSymbol = fieldType
                            GoTo lAgain
                        End If
                    End If

                Case SymbolKind.Method
                    ' Check for Color Color case
                    If allowColorColor Then
                        Dim method = DirectCast(containingSymbol, MethodSymbol)
                        If Not method.IsSub Then
                            Dim returnType As TypeSymbol = method.ReturnType
                            If IdentifierComparison.Equals(method.Name, returnType.Name) Then
                                containingSymbol = returnType
                                GoTo lAgain
                            End If
                        End If
                    End If

                Case Else
                    ' Nothing can be found in context of these symbols

            End Select

            If Not lookupResult.IsGoodOrAmbiguous OrElse Not lookupResult.HasSymbol Then
                lookupResult.Free()
                Return
            End If

            CollectGoodOrAmbiguousFromLookupResult(lookupResult, symbols, preserveAlias)
            lookupResult.Free()
        End Sub

        Private Shared Sub CreateTypeParameterSymbolsAndConstructSymbols(genericName As GenericNameSyntax,
                                                                  symbols As ArrayBuilder(Of Symbol),
                                                                  typeParameters As Dictionary(Of String, CrefTypeParameterSymbol))

            Dim arguments As SeparatedSyntaxList(Of TypeSyntax) = genericName.TypeArgumentList.Arguments
            Dim typeParameterSymbols(arguments.Count - 1) As TypeSymbol

            For i = 0 To arguments.Count - 1
                Dim typeSyntax As TypeSyntax = arguments(i)
                Dim created As CrefTypeParameterSymbol = Nothing

                Select Case typeSyntax.Kind
                    Case SyntaxKind.IdentifierName
                        Dim identifier = DirectCast(typeSyntax, IdentifierNameSyntax)
                        created = New CrefTypeParameterSymbol(i, identifier.Identifier.ValueText, identifier)
                        typeParameterSymbols(i) = created

                    Case Else
                        ' An error case
                        created = New CrefTypeParameterSymbol(i, StringConstants.NamedSymbolErrorName, typeSyntax)
                        typeParameterSymbols(i) = created
                End Select

                typeParameters(created.Name) = created
            Next

            For i = 0 To symbols.Count - 1
                Dim symbol As Symbol = symbols(i)
lAgain:
                Select Case symbol.Kind
                    Case SymbolKind.Method
                        Dim method = DirectCast(symbol, MethodSymbol)
                        Debug.Assert(method.Arity = genericName.TypeArgumentList.Arguments.Count)
                        symbols(i) = method.Construct(typeParameterSymbols.AsImmutableOrNull.As(Of TypeSymbol))

                    Case SymbolKind.NamedType, SymbolKind.ErrorType
                        Dim type = DirectCast(symbol, NamedTypeSymbol)
                        Debug.Assert(type.Arity = genericName.TypeArgumentList.Arguments.Count)
                        symbols(i) = type.Construct(typeParameterSymbols.AsImmutableOrNull.As(Of TypeSymbol))

                    Case SymbolKind.Alias
                        symbol = DirectCast(symbol, AliasSymbol).Target
                        GoTo lAgain
                End Select
            Next
        End Sub

        Private Shared Sub CollectGoodOrAmbiguousFromLookupResult(lookupResult As LookupResult, symbols As ArrayBuilder(Of Symbol), preserveAlias As Boolean)
            Dim di As DiagnosticInfo = lookupResult.Diagnostic

            If TypeOf di Is AmbiguousSymbolDiagnostic Then
                ' Several ambiguous symbols wrapped in 'AmbiguousSymbolDiagnostic', return 
                ' unwrapped symbols in 'ambiguousSymbols' and return Nothing as a result
                Debug.Assert(lookupResult.Kind = LookupResultKind.Ambiguous)

                Dim ambiguousSymbols As ImmutableArray(Of Symbol) = DirectCast(di, AmbiguousSymbolDiagnostic).AmbiguousSymbols
                Debug.Assert(ambiguousSymbols.Length > 1)

                For Each sym In ambiguousSymbols
                    symbols.Add(If(preserveAlias, sym, UnwrapAlias(sym)))
                Next

            Else
                ' Return result as a single good symbol
                For Each sym In lookupResult.Symbols
                    symbols.Add(If(preserveAlias, sym, UnwrapAlias(sym)))
                Next
            End If
        End Sub

        Private Shared Sub CollectOperatorsAndConversionsInType(crefOperator As CrefOperatorReferenceSyntax, argCount As Integer, type As TypeSymbol, symbols As ArrayBuilder(Of Symbol),
                                                         <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo))
            If type Is Nothing Then
                Return
            End If

            If argCount > 2 OrElse argCount < 1 Then
                Return
            End If

            Select Case crefOperator.OperatorToken.Kind
                Case SyntaxKind.IsTrueKeyword
                    If argCount = 1 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(UnaryOperatorKind.IsTrue)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.TrueOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.IsFalseKeyword
                    If argCount = 1 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(UnaryOperatorKind.IsFalse)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.FalseOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.NotKeyword
                    If argCount = 1 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(UnaryOperatorKind.Not)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator,
                                                             WellKnownMemberNames.OnesComplementOperatorName, opInfo,
                                                             useSiteDiagnostics,
                                                             WellKnownMemberNames.LogicalNotOperatorName, opInfo)
                    End If

                Case SyntaxKind.PlusToken
                    If argCount = 1 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(UnaryOperatorKind.Plus)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.UnaryPlusOperatorName, opInfo, useSiteDiagnostics)
                    Else
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Add)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.AdditionOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.MinusToken
                    If argCount = 1 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(UnaryOperatorKind.Minus)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.UnaryNegationOperatorName, opInfo, useSiteDiagnostics)
                    Else
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Subtract)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.SubtractionOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.AsteriskToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Multiply)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.MultiplyOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.SlashToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Divide)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.DivisionOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.BackslashToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.IntegerDivide)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.IntegerDivisionOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.ModKeyword
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Modulo)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.ModulusOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.CaretToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Power)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.ExponentOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.EqualsToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Equals)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.EqualityOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.LessThanGreaterThanToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.NotEquals)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.InequalityOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.LessThanToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.LessThan)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.LessThanOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.GreaterThanToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.GreaterThan)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.GreaterThanOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.LessThanEqualsToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.LessThanOrEqual)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.LessThanOrEqualOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.GreaterThanEqualsToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.GreaterThanOrEqual)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.GreaterThanOrEqualOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.LikeKeyword
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Like)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.LikeOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.AmpersandToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Concatenate)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.ConcatenateOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.AndKeyword
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.And)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator,
                                                             WellKnownMemberNames.BitwiseAndOperatorName, opInfo,
                                                             useSiteDiagnostics,
                                                             WellKnownMemberNames.LogicalAndOperatorName, opInfo)
                    End If

                Case SyntaxKind.OrKeyword
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Or)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator,
                                                             WellKnownMemberNames.BitwiseOrOperatorName, opInfo,
                                                             useSiteDiagnostics,
                                                             WellKnownMemberNames.LogicalOrOperatorName, opInfo)
                    End If

                Case SyntaxKind.XorKeyword
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.Xor)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator, WellKnownMemberNames.ExclusiveOrOperatorName, opInfo, useSiteDiagnostics)
                    End If

                Case SyntaxKind.LessThanLessThanToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.LeftShift)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator,
                                                             WellKnownMemberNames.LeftShiftOperatorName, opInfo,
                                                             useSiteDiagnostics,
                                                             WellKnownMemberNames.UnsignedLeftShiftOperatorName, opInfo)
                    End If

                Case SyntaxKind.GreaterThanGreaterThanToken
                    If argCount = 2 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.RightShift)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.UserDefinedOperator,
                                                             WellKnownMemberNames.RightShiftOperatorName, opInfo,
                                                             useSiteDiagnostics,
                                                             WellKnownMemberNames.UnsignedRightShiftOperatorName, opInfo)
                    End If

                Case SyntaxKind.CTypeKeyword
                    If argCount = 1 Then
                        Dim opInfo As New OverloadResolution.OperatorInfo(BinaryOperatorKind.RightShift)
                        CollectOperatorsAndConversionsInType(type, symbols, MethodKind.Conversion,
                                                             WellKnownMemberNames.ImplicitConversionName, New OverloadResolution.OperatorInfo(UnaryOperatorKind.Implicit),
                                                             useSiteDiagnostics,
                                                             WellKnownMemberNames.ExplicitConversionName, New OverloadResolution.OperatorInfo(UnaryOperatorKind.Explicit))
                    End If

                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(crefOperator.OperatorToken.Kind)
            End Select
        End Sub

        Private Shared Sub CollectOperatorsAndConversionsInType(type As TypeSymbol,
                                                         symbols As ArrayBuilder(Of Symbol),
                                                         kind As MethodKind,
                                                         name1 As String,
                                                         info1 As OverloadResolution.OperatorInfo,
                                                         <[In], Out> ByRef useSiteDiagnostics As HashSet(Of DiagnosticInfo),
                                                         Optional name2 As String = Nothing,
                                                         Optional info2 As OverloadResolution.OperatorInfo = Nothing)

            Dim methods = ArrayBuilder(Of MethodSymbol).GetInstance()
            OverloadResolution.CollectUserDefinedOperators(type, Nothing, kind, name1, info1, name2, info2, methods, useSiteDiagnostics)
            symbols.AddRange(methods)
            methods.Free()
        End Sub

        Private Shared Function NameSyntaxHasComplexGenericArguments(name As TypeSyntax) As Boolean
            Select Case name.Kind
                Case SyntaxKind.IdentifierName,
                     SyntaxKind.CrefOperatorReference,
                     SyntaxKind.GlobalName,
                     SyntaxKind.PredefinedType
                    Return False

                Case SyntaxKind.QualifiedCrefOperatorReference
                    Return NameSyntaxHasComplexGenericArguments(DirectCast(name, QualifiedCrefOperatorReferenceSyntax).Left)

                Case SyntaxKind.QualifiedName
                    Dim qualified = DirectCast(name, QualifiedNameSyntax)
                    Return NameSyntaxHasComplexGenericArguments(qualified.Left) OrElse
                           NameSyntaxHasComplexGenericArguments(qualified.Right)

                Case SyntaxKind.GenericName
                    Dim genericArguments = DirectCast(name, GenericNameSyntax).TypeArgumentList.Arguments
                    For i = 0 To genericArguments.Count - 1
                        If genericArguments(i).Kind <> SyntaxKind.IdentifierName Then
                            Return True
                        End If
                    Next
                    Return False

                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(name.Kind)
            End Select
        End Function

    End Class

End Namespace

