File: FindSymbols\VisualBasicDeclaredSymbolInfoFactoryService.vb
Web Access
Project: src\src\Workspaces\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj (Microsoft.CodeAnalysis.VisualBasic.Workspaces)
' 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.Text
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.FindSymbols
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.LanguageService
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.FindSymbols
    <ExportLanguageService(GetType(IDeclaredSymbolInfoFactoryService), LanguageNames.VisualBasic), [Shared]>
    Friend Class VisualBasicDeclaredSymbolInfoFactoryService
        Inherits AbstractDeclaredSymbolInfoFactoryService(Of
            CompilationUnitSyntax,
            ImportsStatementSyntax,
            NamespaceBlockSyntax,
            TypeBlockSyntax,
            EnumBlockSyntax,
            DeclarationStatementSyntax,
            StatementSyntax,
            NameSyntax,
            QualifiedNameSyntax,
            IdentifierNameSyntax)
 
        Private Const ExtensionName As String = "Extension"
        Private Const ExtensionAttributeName As String = "ExtensionAttribute"
 
        <ImportingConstructor>
        <Obsolete(MefConstruction.ImportingConstructorMessage, True)>
        Public Sub New()
        End Sub
 
        Private Shared Function GetInheritanceNames(stringTable As StringTable, typeBlock As TypeBlockSyntax) As ImmutableArray(Of String)
            Dim builder = ArrayBuilder(Of String).GetInstance()
 
            Dim aliasMap = GetAliasMap(typeBlock)
            Try
                For Each inheritsStatement In typeBlock.Inherits
                    AddInheritanceNames(builder, inheritsStatement.Types, aliasMap)
                Next
 
                For Each implementsStatement In typeBlock.Implements
                    AddInheritanceNames(builder, implementsStatement.Types, aliasMap)
                Next
 
                Intern(stringTable, builder)
                Return builder.ToImmutableAndFree()
            Finally
                FreeAliasMap(aliasMap)
            End Try
        End Function
 
        Private Shared Function GetAliasMap(typeBlock As TypeBlockSyntax) As Dictionary(Of String, String)
            Dim compilationUnit = typeBlock.SyntaxTree.GetCompilationUnitRoot()
 
            Dim aliasMap As Dictionary(Of String, String) = Nothing
            For Each import In compilationUnit.Imports
                For Each clause In import.ImportsClauses
                    If clause.IsKind(SyntaxKind.SimpleImportsClause) Then
                        Dim simpleImport = DirectCast(clause, SimpleImportsClauseSyntax)
                        If simpleImport.Alias IsNot Nothing Then
                            Dim mappedName = GetTypeName(simpleImport.Name)
                            If mappedName IsNot Nothing Then
                                aliasMap = If(aliasMap, AllocateAliasMap())
                                aliasMap(simpleImport.Alias.Identifier.ValueText) = mappedName
                            End If
                        End If
                    End If
                Next
            Next
 
            Return aliasMap
        End Function
 
        Private Shared Sub AddInheritanceNames(
                builder As ArrayBuilder(Of String),
                types As SeparatedSyntaxList(Of TypeSyntax),
                aliasMap As Dictionary(Of String, String))
 
            For Each typeSyntax In types
                AddInheritanceName(builder, typeSyntax, aliasMap)
            Next
        End Sub
 
        Private Shared Sub AddInheritanceName(
                builder As ArrayBuilder(Of String),
                typeSyntax As TypeSyntax,
                aliasMap As Dictionary(Of String, String))
            Dim name = GetTypeName(typeSyntax)
            If name IsNot Nothing Then
                builder.Add(name)
 
                Dim mappedName As String = Nothing
                If aliasMap?.TryGetValue(name, mappedName) = True Then
                    ' Looks Like this could be an alias.  Also include the name the alias points to
                    builder.Add(mappedName)
                End If
            End If
        End Sub
 
        Private Shared Function GetTypeName(typeSyntax As TypeSyntax) As String
            If TypeOf typeSyntax Is SimpleNameSyntax Then
                Return GetSimpleName(DirectCast(typeSyntax, SimpleNameSyntax))
            ElseIf TypeOf typeSyntax Is QualifiedNameSyntax Then
                Return GetSimpleName(DirectCast(typeSyntax, QualifiedNameSyntax).Right)
            End If
 
            Return Nothing
        End Function
 
        Private Shared Function GetSimpleName(simpleName As SimpleNameSyntax) As String
            Return simpleName.Identifier.ValueText
        End Function
 
        Protected Overrides Function GetContainerDisplayName(node As StatementSyntax) As String
            Return VisualBasicSyntaxFacts.Instance.GetDisplayName(node, DisplayNameOptions.IncludeTypeParameters)
        End Function
 
        Protected Overrides Function GetFullyQualifiedContainerName(node As StatementSyntax, rootNamespace As String) As String
            Return VisualBasicSyntaxFacts.Instance.GetDisplayName(node, DisplayNameOptions.IncludeNamespaces, rootNamespace)
        End Function
 
        Protected Overrides Sub AddLocalFunctionInfos(node As StatementSyntax, stringTable As StringTable, declaredSymbolInfos As ArrayBuilder(Of DeclaredSymbolInfo), containerDisplayName As String, fullyQualifiedContainerName As String, cancellationToken As CancellationToken)
            ' VB doesn't have local functions.
        End Sub
 
        Protected Overrides Sub AddSynthesizedDeclaredSymbolInfos(container As SyntaxNode, memberDeclaration As StatementSyntax, stringTable As StringTable, declaredSymbolInfos As ArrayBuilder(Of DeclaredSymbolInfo), containerDisplayName As String, fullyQualifiedContainerName As String, cancellationToken As CancellationToken)
            ' Nothing to do in VB.
        End Sub
 
        Protected Overrides Function GetTypeDeclarationInfo(
                container As SyntaxNode,
                typeDeclaration As TypeBlockSyntax,
                stringTable As StringTable,
                containerDisplayName As String,
                fullyQualifiedContainerName As String) As DeclaredSymbolInfo?
 
            Dim blockStatement = typeDeclaration.BlockStatement
 
            ' If this Is a part of partial type that only contains nested types, then we don't make an info type for it.
            ' That's because we effectively think of this as just being a virtual container just to hold the nested
            ' types, And Not something someone would want to explicitly navigate to itself.  Similar to how we think of
            ' namespaces.
            If blockStatement.Modifiers.Any(SyntaxKind.PartialKeyword) AndAlso
               typeDeclaration.Members.Any() AndAlso
typeDeclaration.Members.All(Function(m) TypeOf m Is TypeBlockSyntax) Then
 
                Return Nothing
            End If
 
            Return DeclaredSymbolInfo.Create(
                stringTable,
                blockStatement.Identifier.ValueText,
                GetTypeParameterSuffix(blockStatement.TypeParameterList),
                containerDisplayName,
                fullyQualifiedContainerName,
                blockStatement.Modifiers.Any(SyntaxKind.PartialKeyword),
                blockStatement.AttributeLists.Any(),
                If(typeDeclaration.Kind() = SyntaxKind.ClassBlock, DeclaredSymbolInfoKind.Class,
                   If(typeDeclaration.Kind() = SyntaxKind.InterfaceBlock, DeclaredSymbolInfoKind.Interface,
                      If(typeDeclaration.Kind() = SyntaxKind.ModuleBlock, DeclaredSymbolInfoKind.Module, DeclaredSymbolInfoKind.Struct))),
                GetAccessibility(container, typeDeclaration, blockStatement.Modifiers),
                blockStatement.Identifier.Span,
                GetInheritanceNames(stringTable, typeDeclaration),
                IsNestedType(typeDeclaration),
                typeParameterCount:=If(blockStatement.TypeParameterList?.Parameters.Count, 0))
        End Function
 
        Protected Overrides Function GetEnumDeclarationInfo(
                container As SyntaxNode,
                enumDeclaration As EnumBlockSyntax,
                stringTable As StringTable,
                containerDisplayName As String,
                fullyQualifiedContainerName As String) As DeclaredSymbolInfo
 
            Dim enumStatement = enumDeclaration.EnumStatement
 
            Return DeclaredSymbolInfo.Create(
                stringTable,
                enumStatement.Identifier.ValueText, Nothing,
                containerDisplayName,
                fullyQualifiedContainerName,
                enumStatement.Modifiers.Any(SyntaxKind.PartialKeyword),
                enumStatement.AttributeLists.Any(),
                DeclaredSymbolInfoKind.Enum,
                GetAccessibility(container, enumDeclaration, enumStatement.Modifiers),
                enumStatement.Identifier.Span,
                ImmutableArray(Of String).Empty,
                IsNestedType(enumDeclaration))
        End Function
 
        Protected Overrides Sub AddMemberDeclarationInfos(
                container As SyntaxNode,
                node As StatementSyntax,
                stringTable As StringTable,
                declaredSymbolInfos As ArrayBuilder(Of DeclaredSymbolInfo),
                containerDisplayName As String,
                fullyQualifiedContainerName As String)
 
            If node.Kind() = SyntaxKind.PropertyBlock Then
                node = DirectCast(node, PropertyBlockSyntax).PropertyStatement
            ElseIf node.Kind() = SyntaxKind.EventBlock Then
                node = DirectCast(node, EventBlockSyntax).EventStatement
            ElseIf TypeOf node Is MethodBlockBaseSyntax Then
                node = DirectCast(node, MethodBlockBaseSyntax).BlockStatement
            End If
 
            Dim kind = node.Kind()
            Select Case kind
                Case SyntaxKind.SubNewStatement
                    Dim constructor = DirectCast(node, SubNewStatementSyntax)
                    Dim typeBlock = TryCast(container, TypeBlockSyntax)
                    If typeBlock IsNot Nothing Then
                        declaredSymbolInfos.Add(DeclaredSymbolInfo.Create(
                            stringTable,
                            typeBlock.BlockStatement.Identifier.ValueText,
                            GetConstructorSuffix(constructor),
                            containerDisplayName,
                            fullyQualifiedContainerName,
                            constructor.Modifiers.Any(SyntaxKind.PartialKeyword),
                            constructor.AttributeLists.Any(),
                            DeclaredSymbolInfoKind.Constructor,
                            GetAccessibility(container, constructor, constructor.Modifiers),
                            constructor.NewKeyword.Span,
                            ImmutableArray(Of String).Empty,
                            parameterCount:=If(constructor.ParameterList?.Parameters.Count, 0)))
 
                        Return
                    End If
                Case SyntaxKind.DelegateFunctionStatement, SyntaxKind.DelegateSubStatement
                    Dim delegateDecl = DirectCast(node, DelegateStatementSyntax)
                    declaredSymbolInfos.Add(DeclaredSymbolInfo.Create(
                        stringTable,
                        delegateDecl.Identifier.ValueText,
                        GetTypeParameterSuffix(delegateDecl.TypeParameterList),
                        containerDisplayName,
                        fullyQualifiedContainerName,
                        delegateDecl.Modifiers.Any(SyntaxKind.PartialKeyword),
                        delegateDecl.AttributeLists.Any(),
                        DeclaredSymbolInfoKind.Delegate,
                        GetAccessibility(container, delegateDecl, delegateDecl.Modifiers),
                        delegateDecl.Identifier.Span,
                        ImmutableArray(Of String).Empty))
                    Return
                Case SyntaxKind.EnumMemberDeclaration
                    Dim enumMember = DirectCast(node, EnumMemberDeclarationSyntax)
                    declaredSymbolInfos.Add(DeclaredSymbolInfo.Create(
                        stringTable,
                        enumMember.Identifier.ValueText, Nothing,
                        containerDisplayName,
                        fullyQualifiedContainerName,
                        isPartial:=False,
                        enumMember.AttributeLists.Any(),
                        DeclaredSymbolInfoKind.EnumMember,
                        Accessibility.Public,
                        enumMember.Identifier.Span,
                        ImmutableArray(Of String).Empty))
                    Return
                Case SyntaxKind.EventStatement
                    Dim eventDecl = DirectCast(node, EventStatementSyntax)
                    declaredSymbolInfos.Add(DeclaredSymbolInfo.Create(
                        stringTable,
                        eventDecl.Identifier.ValueText, Nothing,
                        containerDisplayName,
                        fullyQualifiedContainerName,
                        eventDecl.Modifiers.Any(SyntaxKind.PartialKeyword),
                        eventDecl.AttributeLists.Any(),
                        DeclaredSymbolInfoKind.Event,
                        GetAccessibility(container, eventDecl, eventDecl.Modifiers),
                        eventDecl.Identifier.Span,
                        ImmutableArray(Of String).Empty))
                    Return
                Case SyntaxKind.FunctionStatement, SyntaxKind.SubStatement
                    Dim funcDecl = DirectCast(node, MethodStatementSyntax)
                    Dim isExtension = IsExtensionMethod(funcDecl)
                    declaredSymbolInfos.Add(DeclaredSymbolInfo.Create(
                        stringTable,
                        funcDecl.Identifier.ValueText,
                        GetMethodSuffix(funcDecl),
                        containerDisplayName,
                        fullyQualifiedContainerName,
                        funcDecl.Modifiers.Any(SyntaxKind.PartialKeyword),
                        funcDecl.AttributeLists.Any(),
                        If(isExtension, DeclaredSymbolInfoKind.ExtensionMethod, DeclaredSymbolInfoKind.Method),
                        GetAccessibility(container, funcDecl, funcDecl.Modifiers),
                        funcDecl.Identifier.Span,
                        ImmutableArray(Of String).Empty,
                        parameterCount:=If(funcDecl.ParameterList?.Parameters.Count, 0),
                        typeParameterCount:=If(funcDecl.TypeParameterList?.Parameters.Count, 0)))
 
                    Return
                Case SyntaxKind.PropertyStatement
                    Dim propertyDecl = DirectCast(node, PropertyStatementSyntax)
                    declaredSymbolInfos.Add(DeclaredSymbolInfo.Create(
                        stringTable,
                        propertyDecl.Identifier.ValueText,
                        GetPropertySuffix(propertyDecl),
                        containerDisplayName,
                        fullyQualifiedContainerName,
                        propertyDecl.Modifiers.Any(SyntaxKind.PartialKeyword),
                        propertyDecl.AttributeLists.Any(),
                        DeclaredSymbolInfoKind.Property,
                        GetAccessibility(container, propertyDecl, propertyDecl.Modifiers),
                        propertyDecl.Identifier.Span,
                        ImmutableArray(Of String).Empty))
                    Return
                Case SyntaxKind.FieldDeclaration
                    Dim fieldDecl = DirectCast(node, FieldDeclarationSyntax)
                    For Each variableDeclarator In fieldDecl.Declarators
                        For Each modifiedIdentifier In variableDeclarator.Names
                            declaredSymbolInfos.Add(DeclaredSymbolInfo.Create(
                                stringTable,
                                modifiedIdentifier.Identifier.ValueText, Nothing,
                                containerDisplayName,
                                fullyQualifiedContainerName,
                                fieldDecl.Modifiers.Any(SyntaxKind.PartialKeyword),
                                fieldDecl.AttributeLists.Any(),
                                If(fieldDecl.Modifiers.Any(Function(m) m.Kind() = SyntaxKind.ConstKeyword),
                                    DeclaredSymbolInfoKind.Constant,
                                    DeclaredSymbolInfoKind.Field),
                                GetAccessibility(container, fieldDecl, fieldDecl.Modifiers),
                                modifiedIdentifier.Identifier.Span,
                                ImmutableArray(Of String).Empty))
                        Next
                    Next
            End Select
        End Sub
 
        Protected Overrides Function GetChildren(node As CompilationUnitSyntax) As SyntaxList(Of StatementSyntax)
            Return node.Members
        End Function
 
        Protected Overrides Function GetChildren(node As NamespaceBlockSyntax) As SyntaxList(Of StatementSyntax)
            Return node.Members
        End Function
 
        Protected Overrides Function GetChildren(node As TypeBlockSyntax) As SyntaxList(Of StatementSyntax)
            Return node.Members
        End Function
 
        Protected Overrides Function GetChildren(node As EnumBlockSyntax) As IEnumerable(Of StatementSyntax)
            Return node.Members
        End Function
 
        Protected Overrides Function GetUsingAliases(node As CompilationUnitSyntax) As SyntaxList(Of ImportsStatementSyntax)
            Return node.Imports
        End Function
 
        Protected Overrides Function GetUsingAliases(node As NamespaceBlockSyntax) As SyntaxList(Of ImportsStatementSyntax)
            Return Nothing
        End Function
 
        Protected Overrides Function GetName(node As NamespaceBlockSyntax) As NameSyntax
            Return node.NamespaceStatement.Name
        End Function
 
        Protected Overrides Function GetLeft(node As QualifiedNameSyntax) As NameSyntax
            Return node.Left
        End Function
 
        Protected Overrides Function GetRight(node As QualifiedNameSyntax) As NameSyntax
            Return node.Right
        End Function
 
        Protected Overrides Function GetIdentifier(node As IdentifierNameSyntax) As SyntaxToken
            Return node.Identifier
        End Function
 
        Private Shared Function IsExtensionMethod(node As MethodStatementSyntax) As Boolean
            Dim parameterCount = node.ParameterList?.Parameters.Count
 
            ' Extension method must have at least one parameter and declared inside a module
            If Not parameterCount.HasValue OrElse parameterCount.Value = 0 OrElse TypeOf node.Parent?.Parent IsNot ModuleBlockSyntax Then
                Return False
            End If
 
            For Each attributeList In node.AttributeLists
                For Each attribute In attributeList.Attributes
                    ' ExtensionAttribute takes no argument.
                    If attribute.ArgumentList?.Arguments.Count > 0 Then
                        Continue For
                    End If
 
                    Dim name = attribute.Name.GetRightmostName()?.ToString()
                    If String.Equals(name, ExtensionName, StringComparison.OrdinalIgnoreCase) OrElse String.Equals(name, ExtensionAttributeName, StringComparison.OrdinalIgnoreCase) Then
                        Return True
                    End If
                Next
            Next
 
            Return False
        End Function
 
        Private Shared Function IsNestedType(node As DeclarationStatementSyntax) As Boolean
            Return TypeOf node.Parent Is TypeBlockSyntax
        End Function
 
        Private Shared Function GetAccessibility(container As SyntaxNode, node As StatementSyntax, modifiers As SyntaxTokenList) As Accessibility
            Dim sawFriend = False
 
            For Each modifier In modifiers
                Select Case modifier.Kind()
                    Case SyntaxKind.PublicKeyword : Return Accessibility.Public
                    Case SyntaxKind.PrivateKeyword : Return Accessibility.Private
                    Case SyntaxKind.ProtectedKeyword : Return Accessibility.Protected
                    Case SyntaxKind.FriendKeyword
                        sawFriend = True
                        Continue For
                End Select
            Next
 
            If sawFriend Then
                Return Accessibility.Internal
            End If
 
            ' No accessibility modifiers
            Select Case container.Kind()
                Case SyntaxKind.ClassBlock
                    ' In a class, fields and shared-constructors are private by default,
                    ' everything Else Is Public
                    If node.Kind() = SyntaxKind.FieldDeclaration Then
                        Return Accessibility.Private
                    End If
 
                    If node.Kind() = SyntaxKind.SubNewStatement AndAlso
                       DirectCast(node, SubNewStatementSyntax).Modifiers.Any(SyntaxKind.SharedKeyword) Then
                        Return Accessibility.Private
                    End If
 
                    Return Accessibility.Public
                Case SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ModuleBlock
                    ' Everything in a struct/interface/module is public
                    Return Accessibility.Public
            End Select
 
            ' Otherwise, it's internal
            Return Accessibility.Internal
        End Function
 
        Private Shared Function GetMethodSuffix(method As MethodStatementSyntax) As String
            Return GetTypeParameterSuffix(method.TypeParameterList) & GetSuffix(method.ParameterList)
        End Function
 
        Private Shared Function GetConstructorSuffix(method As SubNewStatementSyntax) As String
            Return ".New" & GetSuffix(method.ParameterList)
        End Function
 
        Private Shared Function GetPropertySuffix([property] As PropertyStatementSyntax) As String
            If [property].ParameterList Is Nothing Then
                Return Nothing
            End If
 
            Return GetSuffix([property].ParameterList)
        End Function
 
        Private Shared Function GetTypeParameterSuffix(typeParameterList As TypeParameterListSyntax) As String
            If typeParameterList Is Nothing Then
                Return Nothing
            End If
 
            Dim pooledBuilder = PooledStringBuilder.GetInstance()
 
            Dim builder = pooledBuilder.Builder
            builder.Append("(Of ")
 
            Dim First = True
            For Each parameter In typeParameterList.Parameters
                If Not First Then
                    builder.Append(", ")
                End If
 
                builder.Append(parameter.Identifier.Text)
                First = False
            Next
 
            builder.Append(")"c)
 
            Return pooledBuilder.ToStringAndFree()
        End Function
 
        ''' <summary>
        ''' Builds up the suffix to show for something with parameters in navigate-to.
        ''' While it would be nice to just use the compiler SymbolDisplay API for this,
        ''' it would be too expensive as it requires going back to Symbols (which requires
        ''' creating compilations, etc.) in a perf sensitive area.
        ''' 
        ''' So, instead, we just build a reasonable suffix using the pure syntax that a 
        ''' user provided.  That means that if they wrote "Method(System.Int32 i)" we'll 
        ''' show that as "Method(System.Int32)" Not "Method(Integer)".  Given that this Is
        ''' actually what the user wrote, And it saves us from ever having to go back to
        ''' symbols/compilations, this Is well worth it, even if it does mean we have to
        ''' create our own 'symbol display' logic here.
        ''' </summary>
        Private Shared Function GetSuffix(parameterList As ParameterListSyntax) As String
            If parameterList Is Nothing OrElse parameterList.Parameters.Count = 0 Then
                Return "()"
            End If
 
            Dim pooledBuilder = PooledStringBuilder.GetInstance()
 
            Dim builder = pooledBuilder.Builder
            builder.Append("("c)
            If parameterList IsNot Nothing Then
                AppendParameters(parameterList.Parameters, builder)
            End If
 
            builder.Append(")"c)
 
            Return pooledBuilder.ToStringAndFree()
        End Function
 
        Private Shared Sub AppendParameters(parameters As SeparatedSyntaxList(Of ParameterSyntax), builder As StringBuilder)
            Dim First = True
            For Each parameter In parameters
                If Not First Then
                    builder.Append(", ")
                End If
 
                For Each modifier In parameter.Modifiers
                    If modifier.Kind() <> SyntaxKind.ByValKeyword Then
                        builder.Append(modifier.Text)
                        builder.Append(" "c)
                    End If
                Next
 
                If parameter.AsClause?.Type IsNot Nothing Then
                    builder.Append(parameter.AsClause.Type.ConvertToSingleLine().ToString())
                End If
 
                First = False
            Next
        End Sub
 
        Protected Overrides Function GetReceiverTypeName(node As DeclarationStatementSyntax) As String
            node = If(TryCast(node, MethodBlockBaseSyntax)?.BlockStatement, node)
 
            Dim funcDecl = DirectCast(node, MethodStatementSyntax)
            Debug.Assert(IsExtensionMethod(funcDecl))
 
            Dim typeParameterNames = funcDecl.TypeParameterList?.Parameters.SelectAsArray(Function(p) p.Identifier.Text)
            Dim targetTypeName As String = Nothing
            Dim isArray As Boolean = False
 
            TryGetSimpleTypeNameWorker(funcDecl.ParameterList.Parameters(0).AsClause?.Type, typeParameterNames, targetTypeName, isArray)
            Return CreateReceiverTypeString(targetTypeName, isArray)
        End Function
 
        Protected Overrides Function TryGetAliasesFromUsingDirective(importStatement As ImportsStatementSyntax, ByRef aliases As ImmutableArray(Of (aliasName As String, name As String))) As Boolean
            Dim builder = ArrayBuilder(Of (String, String)).GetInstance()
 
            If importStatement IsNot Nothing Then
                For Each importsClause In importStatement.ImportsClauses
 
                    If importsClause.Kind = SyntaxKind.SimpleImportsClause Then
                        Dim simpleImportsClause = DirectCast(importsClause, SimpleImportsClauseSyntax)
                        Dim aliasName, name As String
 
#Disable Warning BC42030 ' Variable is passed by reference before it has been assigned a value
                        If simpleImportsClause.Alias IsNot Nothing AndAlso
                            TryGetSimpleTypeNameWorker(simpleImportsClause.Alias, Nothing, aliasName, Nothing) AndAlso
                            TryGetSimpleTypeNameWorker(simpleImportsClause, Nothing, name, Nothing) Then
#Enable Warning BC42030 ' Variable is passed by reference before it has been assigned a value
 
                            builder.Add((aliasName, name))
                        End If
                    End If
                Next
 
                aliases = builder.ToImmutableAndFree()
                Return True
            End If
 
            aliases = Nothing
            Return False
        End Function
 
        Private Shared Function TryGetSimpleTypeNameWorker(node As SyntaxNode, typeParameterNames As ImmutableArray(Of String)?, ByRef simpleTypeName As String, ByRef isArray As Boolean) As Boolean
 
            isArray = False
 
            If TypeOf node Is IdentifierNameSyntax Then
                Dim identifierName = DirectCast(node, IdentifierNameSyntax)
                Dim text = identifierName.Identifier.Text
                simpleTypeName = If(typeParameterNames?.Contains(text), Nothing, text)
                Return simpleTypeName IsNot Nothing
 
            ElseIf TypeOf node Is ArrayTypeSyntax Then
                isArray = True
                Dim arrayType = DirectCast(node, ArrayTypeSyntax)
                Return TryGetSimpleTypeNameWorker(arrayType.ElementType, typeParameterNames, simpleTypeName, Nothing)
 
            ElseIf TypeOf node Is GenericNameSyntax Then
                Dim genericName = DirectCast(node, GenericNameSyntax)
                Dim name = genericName.Identifier.Text
                Dim arity = genericName.Arity
                simpleTypeName = If(arity = 0, name, name + ArityUtilities.GetMetadataAritySuffix(arity))
                Return True
 
            ElseIf TypeOf node Is QualifiedNameSyntax Then
                ' For an identifier to the right of a '.', it can't be a type parameter,
                ' so we don't need to check for it further.
                Dim qualifiedName = DirectCast(node, QualifiedNameSyntax)
                Return TryGetSimpleTypeNameWorker(qualifiedName.Right, Nothing, simpleTypeName, Nothing)
 
            ElseIf TypeOf node Is NullableTypeSyntax Then
                Return TryGetSimpleTypeNameWorker(DirectCast(node, NullableTypeSyntax).ElementType, typeParameterNames, simpleTypeName, isArray)
 
            ElseIf TypeOf node Is PredefinedTypeSyntax Then
                simpleTypeName = GetSpecialTypeName(DirectCast(node, PredefinedTypeSyntax))
                Return simpleTypeName IsNot Nothing
 
            ElseIf TypeOf node Is TupleTypeSyntax Then
                Dim tupleArity = DirectCast(node, TupleTypeSyntax).Elements.Count
                simpleTypeName = CreateValueTupleTypeString(tupleArity)
                Return True
            End If
 
            simpleTypeName = Nothing
            Return False
        End Function
 
        Private Shared Function GetSpecialTypeName(predefinedTypeNode As PredefinedTypeSyntax) As String
            Select Case predefinedTypeNode.Keyword.Kind()
                Case SyntaxKind.BooleanKeyword
                    Return "Boolean"
                Case SyntaxKind.ByteKeyword
                    Return "Byte"
                Case SyntaxKind.CharKeyword
                    Return "Char"
                Case SyntaxKind.DateKeyword
                    Return "DateTime"
                Case SyntaxKind.DecimalKeyword
                    Return "Decimal"
                Case SyntaxKind.DoubleKeyword
                    Return "Double"
                Case SyntaxKind.IntegerKeyword
                    Return "Int32"
                Case SyntaxKind.LongKeyword
                    Return "Int64"
                Case SyntaxKind.ObjectKeyword
                    Return "Object"
                Case SyntaxKind.SByteKeyword
                    Return "SByte"
                Case SyntaxKind.ShortKeyword
                    Return "Int16"
                Case SyntaxKind.SingleKeyword
                    Return "Single"
                Case SyntaxKind.StringKeyword
                    Return "String"
                Case SyntaxKind.UIntegerKeyword
                    Return "UInt32"
                Case SyntaxKind.ULongKeyword
                    Return "UInt64"
                Case SyntaxKind.UShortKeyword
                    Return "UInt16"
                Case Else
                    Return Nothing
            End Select
        End Function
 
        Protected Overrides Function GetRootNamespace(compilationOptions As CompilationOptions) As String
            Return DirectCast(compilationOptions, VisualBasicCompilationOptions).RootNamespace
        End Function
    End Class
End Namespace