File: SymbolDisplay\SymbolDisplay.vb
Web Access
Project: src\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic)
' 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.Collections
Imports Microsoft.CodeAnalysis.PooledObjects
 
Namespace Microsoft.CodeAnalysis.VisualBasic
#Disable Warning CA1200 ' Avoid using cref tags with a prefix
    ''' <summary>
    ''' Displays a symbol in the VisualBasic style.
    ''' </summary>
    ''' <seealso cref="T:Microsoft.CodeAnalysis.CSharp.SymbolDisplay"/>
#Enable Warning CA1200 ' Avoid using cref tags with a prefix
    Public Module SymbolDisplay
        ''' <summary>
        ''' Displays a symbol in the Visual Basic style, based on a <see cref="SymbolDisplayFormat"/>.
        ''' </summary>
        ''' <param name="symbol">The symbol to be displayed.</param>
        ''' <param name="format">The formatting options to apply.  If Nothing is passed, <see cref="SymbolDisplayFormat.VisualBasicErrorMessageFormat"/> will be used.</param>
        ''' <returns>A formatted string that can be displayed to the user.</returns>
        ''' <remarks>
        ''' The return value is not expected to be syntactically valid Visual Basic.
        ''' </remarks>
        Public Function ToDisplayString(symbol As ISymbol, Optional format As SymbolDisplayFormat = Nothing) As String
            format = If(format, SymbolDisplayFormat.VisualBasicErrorMessageFormat)
            Return ToDisplayString(symbol, semanticModel:=Nothing, position:=-1, format, minimal:=False)
        End Function
 
        ''' <summary>
        ''' Displays a symbol in the Visual Basic style, based on a <see cref="SymbolDisplayFormat"/>.
        ''' Based on the context, qualify type And member names as little as possible without
        ''' introducing ambiguities.
        ''' </summary>
        ''' <param name="symbol">The symbol to be displayed.</param>
        ''' <param name="semanticModel">Semantic information about the context in which the symbol is being displayed.</param>
        ''' <param name="position">A position within the <see cref="SyntaxTree"/> Or <paramref name="semanticModel"/>.</param>
        ''' <param name="format">The formatting options to apply.  If null is passed, <see cref="SymbolDisplayFormat.CSharpErrorMessageFormat"/> will be used.</param>
        ''' <returns>A formatted string that can be displayed to the user.</returns>
        ''' <remarks>
        ''' The return value is not expected to be syntactically valid Visual Basic.
        ''' </remarks>
        Public Function ToMinimalDisplayString(symbol As ISymbol,
                                               semanticModel As SemanticModel,
                                               position As Integer,
                                               Optional format As SymbolDisplayFormat = Nothing) As String
            format = If(format, SymbolDisplayFormat.MinimallyQualifiedFormat)
            Return ToDisplayString(symbol, semanticModel, position, format, minimal:=True)
        End Function
 
        Private Function ToDisplayString(symbol As ISymbol,
                                         semanticModel As SemanticModel,
                                         position As Integer,
                                         format As SymbolDisplayFormat,
                                         minimal As Boolean) As String
            Dim builder = ArrayBuilder(Of SymbolDisplayPart).GetInstance()
 
            PopulateDisplayParts(builder, symbol, semanticModel, position, format, minimal)
 
            Dim result = builder.ToDisplayString()
            builder.Free()
 
            Return result
        End Function
 
        ''' <summary>
        ''' Convert a symbol to an array of string parts, each of which has a kind. Useful for
        ''' colorizing the display string.
        ''' </summary>
        ''' <param name="symbol">The symbol to be displayed.</param>
        ''' <param name="format">The formatting options to apply.  If Nothing Is passed, <see cref="SymbolDisplayFormat.VisualBasicErrorMessageFormat"/> will be used.</param>
        ''' <returns>A list of display parts.</returns>
        ''' <remarks>
        ''' Parts are not localized until they are converted to strings.
        ''' </remarks>
        Public Function ToDisplayParts(symbol As ISymbol,
                                       Optional format As SymbolDisplayFormat = Nothing) As ImmutableArray(Of SymbolDisplayPart)
            format = If(format, SymbolDisplayFormat.VisualBasicErrorMessageFormat)
            Return ToDisplayParts(symbol, semanticModelOpt:=Nothing, positionOpt:=-1, format:=format, minimal:=False)
        End Function
 
        ''' <summary>
        ''' Convert a symbol to an array of string parts, each of which has a kind. Useful for
        ''' colorizing the display string.
        ''' </summary>
        ''' <param name="symbol">The symbol to be displayed.</param>
        ''' <param name="semanticModel">Semantic information about the context in which the symbol is being displayed.</param>
        ''' <param name="position">A position within the <see cref="SyntaxTree"/> or <paramref name="semanticModel"/>.</param>
        ''' <param name="format">The formatting options to apply.  If null is passed, <see cref="SymbolDisplayFormat.CSharpErrorMessageFormat"/> will be used.</param>
        ''' <returns>A list of display parts.</returns>
        ''' <remarks>
        ''' Parts are not localized until they are converted to strings.
        ''' </remarks>
        Public Function ToMinimalDisplayParts(symbol As ISymbol,
                                              semanticModel As SemanticModel,
                                              position As Integer,
                                              Optional format As SymbolDisplayFormat = Nothing) As ImmutableArray(Of SymbolDisplayPart)
            format = If(format, SymbolDisplayFormat.MinimallyQualifiedFormat)
            Return ToDisplayParts(symbol, semanticModel, position, format, minimal:=True)
        End Function
 
        Private Function ToDisplayParts(symbol As ISymbol,
                                       semanticModelOpt As SemanticModel,
                                       positionOpt As Integer,
                                       format As SymbolDisplayFormat,
                                       minimal As Boolean) As ImmutableArray(Of SymbolDisplayPart)
            Dim builder = ArrayBuilder(Of SymbolDisplayPart).GetInstance()
 
            PopulateDisplayParts(builder, symbol, semanticModelOpt, positionOpt, format, minimal)
 
            Return builder.ToImmutableAndFree()
        End Function
 
        Private Sub PopulateDisplayParts(builder As ArrayBuilder(Of SymbolDisplayPart),
                                         symbol As ISymbol,
                                         semanticModelOpt As SemanticModel,
                                         positionOpt As Integer,
                                         format As SymbolDisplayFormat,
                                         minimal As Boolean)
            If symbol Is Nothing Then
                Throw New ArgumentNullException(NameOf(symbol))
            End If
 
            If minimal Then
                If semanticModelOpt Is Nothing Then
                    Throw New ArgumentException(VBResources.SemanticModelMustBeProvided)
                ElseIf positionOpt < 0 OrElse positionOpt > semanticModelOpt.SyntaxTree.Length Then 'Note: not >= since EOF is allowed.
                    Throw New ArgumentOutOfRangeException(VBResources.PositionNotWithinTree)
                End If
            Else
                Debug.Assert(semanticModelOpt Is Nothing)
                Debug.Assert(positionOpt < 0)
            End If
 
            Dim visitor = SymbolDisplayVisitor.GetInstance(builder, format, semanticModelOpt, positionOpt)
            symbol.Accept(visitor)
            visitor.Free()
        End Sub
 
        ''' <summary>
        ''' Returns a string representation of an object of primitive type.
        ''' </summary>
        ''' <param name="obj">A value to display as a string.</param>
        ''' <param name="quoteStrings">Whether or not to quote string literals.</param>
        ''' <param name="useHexadecimalNumbers">Whether or not to display integral literals in hexadecimal.</param>
        ''' <returns>A string representation of an object of primitive type (or null if the type is not supported).</returns>
        ''' <remarks>
        ''' Handles <see cref="Boolean"/>, <see cref="String"/>, <see cref="Char"/>, <see cref="SByte"/>
        ''' <see cref="Byte"/>, <see cref="Short"/>, <see cref="UShort"/>, <see cref="Integer"/>, <see cref="UInteger"/>,
        ''' <see cref="Long"/>, <see cref="ULong"/>, <see cref="Double"/>, <see cref="Single"/>, <see cref="Decimal"/>,
        ''' <see cref="Date"/>, and <c>Nothing</c>.
        ''' </remarks>
        Public Function FormatPrimitive(obj As Object, quoteStrings As Boolean, useHexadecimalNumbers As Boolean) As String
            Dim options = ObjectDisplayOptions.None
            If quoteStrings Then
                options = options Or ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableCharacters
            End If
            If useHexadecimalNumbers Then
                options = options Or ObjectDisplayOptions.UseHexadecimalNumbers
            End If
            Return ObjectDisplay.FormatPrimitive(obj, options)
        End Function
 
        Friend Sub AddSymbolDisplayParts(parts As ArrayBuilder(Of SymbolDisplayPart), str As String)
            Dim pooledBuilder = PooledStringBuilder.GetInstance()
            Dim sb = pooledBuilder.Builder
 
            Dim lastKind = -1
            For Each token As Integer In ObjectDisplay.TokenizeString(str, ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.UseHexadecimalNumbers Or ObjectDisplayOptions.EscapeNonPrintableCharacters)
                Dim kind = token >> 16
 
                ' merge contiguous tokens of the same kind into a single part
                If lastKind >= 0 AndAlso lastKind <> kind Then
                    parts.Add(New SymbolDisplayPart(DirectCast(lastKind, SymbolDisplayPartKind), Nothing, sb.ToString()))
                    sb.Clear()
                End If
 
                lastKind = kind
                sb.Append(ChrW(token And &HFFFF)) ' lower 16 bits of token contains the Unicode char value
            Next
 
            If lastKind >= 0 Then
                parts.Add(New SymbolDisplayPart(DirectCast(lastKind, SymbolDisplayPartKind), Nothing, sb.ToString()))
            End If
 
            pooledBuilder.Free()
        End Sub
 
        Friend Sub AddSymbolDisplayParts(parts As ArrayBuilder(Of SymbolDisplayPart), c As Char)
            Dim wellKnown = ObjectDisplay.GetWellKnownCharacterName(c)
            If wellKnown IsNot Nothing Then
                parts.Add(New SymbolDisplayPart(SymbolDisplayPartKind.FieldName, Nothing, wellKnown))
                Return
            End If
 
            If ObjectDisplay.IsPrintable(c) Then
                parts.Add(New SymbolDisplayPart(SymbolDisplayPartKind.StringLiteral, Nothing, """" & c & """c"))
                Return
            End If
 
            ' non-printable, add "ChrW(codepoint)"
            Dim codepoint = AscW(c)
            parts.Add(New SymbolDisplayPart(SymbolDisplayPartKind.MethodName, Nothing, "ChrW"))
            parts.Add(New SymbolDisplayPart(SymbolDisplayPartKind.Punctuation, Nothing, "("))
            parts.Add(New SymbolDisplayPart(SymbolDisplayPartKind.NumericLiteral, Nothing, "&H" & codepoint.ToString("X")))
            parts.Add(New SymbolDisplayPart(SymbolDisplayPartKind.Punctuation, Nothing, ")"))
        End Sub
    End Module
End Namespace