File: CodeModel\MethodXML\MethodXmlBuilder.vb
Web Access
Project: src\src\VisualStudio\VisualBasic\Impl\Microsoft.VisualStudio.LanguageServices.VisualBasic.vbproj (Microsoft.VisualStudio.LanguageServices.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 Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Shared.Extensions
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.MethodXml
 
Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel.MethodXml
    Friend Class MethodXmlBuilder
        Inherits AbstractMethodXmlBuilder
 
        Private Shared ReadOnly s_fullNameFormat As New SymbolDisplayFormat(
            typeQualificationStyle:=SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
            memberOptions:=SymbolDisplayMemberOptions.None)
 
        Private Sub New(symbol As IMethodSymbol, semanticModel As SemanticModel)
            MyBase.New(symbol, semanticModel)
        End Sub
 
        Private Sub GenerateStatementBlock(statementList As SyntaxList(Of StatementSyntax))
            Using BlockTag()
                For Each statement In statementList
                    GenerateStatement(statement)
                Next
            End Using
        End Sub
 
        Private Sub GenerateStatement(statement As StatementSyntax)
            Dim success = False
            Dim mark = GetMark()
 
            Select Case statement.Kind
                Case SyntaxKind.LocalDeclarationStatement
                    success = TryGenerateLocal(DirectCast(statement, LocalDeclarationStatementSyntax))
                Case SyntaxKind.SimpleAssignmentStatement
                    success = TryGenerateAssignment(DirectCast(statement, AssignmentStatementSyntax))
                Case SyntaxKind.CallStatement
                    success = TryGenerateCall(DirectCast(statement, CallStatementSyntax))
                Case SyntaxKind.ExpressionStatement
                    success = TryGenerateExpressionStatement(DirectCast(statement, ExpressionStatementSyntax))
                Case SyntaxKind.AddHandlerStatement,
                     SyntaxKind.RemoveHandlerStatement
                    success = TryGenerateAddOrRemoveHandlerStatement(DirectCast(statement, AddRemoveHandlerStatementSyntax))
            End Select
 
            If Not success Then
                Rewind(mark)
                GenerateUnknown(statement)
            End If
 
            ' Just for readability
            LineBreak()
        End Sub
 
        Private Function TryGenerateLocal(localDeclaration As LocalDeclarationStatementSyntax) As Boolean
            For Each declarator In localDeclaration.Declarators
                Using LocalTag(GetLineNumber(localDeclaration))
                    ' Note: this is a difference from Dev10 where VB always generates
                    ' a full assembly-qualified name. Because this extra information is
                    ' generally wasteful, and C# never generates, we'll just generate
                    ' the non-assembly-qualified name instead.
                    Dim type = declarator.Type(SemanticModel)
                    If type Is Nothing Then
                        Return False
                    End If
 
                    GenerateType(type)
 
                    For Each name In declarator.Names
                        Using NameTag()
                            EncodedText(name.Identifier.ToString())
                        End Using
 
                        Dim initializer = declarator.GetInitializer()
 
                        If type.TypeKind = TypeKind.Array AndAlso
                          (name.ArrayBounds IsNot Nothing OrElse initializer IsNot Nothing) Then
                            Using ExpressionTag()
                                If Not TryGenerateNewArray(name.ArrayBounds, initializer, type) Then
                                    Return False
                                End If
                            End Using
                        ElseIf initializer IsNot Nothing AndAlso Not TryGenerateExpression(initializer) Then
                            Return False
                        End If
                    Next
                End Using
            Next
 
            Return True
        End Function
 
        Private Function TryGenerateAssignment(assignmentStatement As AssignmentStatementSyntax) As Boolean
            Using ExpressionStatementTag(GetLineNumber(assignmentStatement))
                Using ExpressionTag()
                    Using AssignmentTag()
                        Return TryGenerateExpression(assignmentStatement.Left) AndAlso
                               TryGenerateExpression(assignmentStatement.Right)
                    End Using
                End Using
            End Using
        End Function
 
        Private Function TryGenerateCall(callStatement As CallStatementSyntax) As Boolean
            Using ExpressionStatementTag(GetLineNumber(callStatement))
                Return TryGenerateExpression(callStatement.Invocation)
            End Using
        End Function
 
        Private Function TryGenerateExpressionStatement(expressionStatement As ExpressionStatementSyntax) As Boolean
            Using ExpressionStatementTag(GetLineNumber(expressionStatement))
                Return TryGenerateExpression(expressionStatement.Expression)
            End Using
        End Function
 
        Private Function TryGenerateAddOrRemoveHandlerStatement(addHandlerStatement As AddRemoveHandlerStatementSyntax) As Boolean
            ' AddHandler statements are represented as invocations of an event's add_* method.
            ' RemoveHandler statements are represented as invocations of an event's remove_* method.
 
            Dim eventExpression = addHandlerStatement.EventExpression
            Dim eventSymbol = TryCast(SemanticModel.GetSymbolInfo(eventExpression).Symbol, IEventSymbol)
 
            Dim eventAccessor As IMethodSymbol
            If addHandlerStatement.Kind() = SyntaxKind.AddHandlerStatement Then
                eventAccessor = eventSymbol?.AddMethod
            ElseIf addHandlerStatement.Kind() = SyntaxKind.RemoveHandlerStatement
                eventAccessor = eventSymbol?.RemoveMethod
            Else
                eventAccessor = Nothing
            End If
 
            If eventAccessor Is Nothing Then
                Return False
            End If
 
            Using ExpressionStatementTag(GetLineNumber(addHandlerStatement))
                Using ExpressionTag()
                    Using MethodCallTag()
                        If Not TryGenerateExpression(eventExpression, eventAccessor, generateAttributes:=True) Then
                            Return False
                        End If
 
                        GenerateType(eventSymbol.ContainingType, implicit:=True, assemblyQualify:=True)
 
                        Using ArgumentTag()
                            If Not TryGenerateExpression(addHandlerStatement.DelegateExpression, generateAttributes:=True) Then
                                Return False
                            End If
                        End Using
 
                        Return True
                    End Using
                End Using
            End Using
        End Function
 
        Private Function TryGenerateExpression(expression As ExpressionSyntax, Optional symbolOpt As ISymbol = Nothing, Optional generateAttributes As Boolean = False) As Boolean
            Using ExpressionTag()
                Return TryGenerateExpressionSansTag(expression, symbolOpt, generateAttributes)
            End Using
        End Function
 
        Private Function TryGenerateExpressionSansTag(expression As ExpressionSyntax, Optional symbolOpt As ISymbol = Nothing, Optional generateAttributes As Boolean = False) As Boolean
            Select Case expression.Kind
                Case SyntaxKind.CharacterLiteralExpression,
                     SyntaxKind.UnaryMinusExpression,
                     SyntaxKind.NumericLiteralExpression,
                     SyntaxKind.StringLiteralExpression,
                     SyntaxKind.TrueLiteralExpression,
                     SyntaxKind.FalseLiteralExpression
                    Return TryGenerateLiteral(expression)
 
                Case SyntaxKind.NothingLiteralExpression
                    GenerateNullLiteral()
                    Return True
 
                Case SyntaxKind.ParenthesizedExpression
                    Return TryGenerateParenthesizedExpression(DirectCast(expression, ParenthesizedExpressionSyntax))
 
                Case SyntaxKind.AddExpression,
                     SyntaxKind.OrExpression,
                     SyntaxKind.AndExpression,
                     SyntaxKind.ConcatenateExpression
                    Return TryGenerateBinaryOperation(DirectCast(expression, BinaryExpressionSyntax))
 
                Case SyntaxKind.CollectionInitializer
                    Return TryGenerateCollectionInitializer(DirectCast(expression, CollectionInitializerSyntax))
 
                Case SyntaxKind.ArrayCreationExpression
                    Return TryGenerateArrayCreation(DirectCast(expression, ArrayCreationExpressionSyntax))
 
                Case SyntaxKind.ObjectCreationExpression
                    Return TryGenerateNewClass(DirectCast(expression, ObjectCreationExpressionSyntax))
 
                Case SyntaxKind.SimpleMemberAccessExpression
                    Return TryGenerateNameRef(DirectCast(expression, MemberAccessExpressionSyntax), symbolOpt, generateAttributes)
 
                Case SyntaxKind.IdentifierName
                    Return TryGenerateNameRef(DirectCast(expression, IdentifierNameSyntax), symbolOpt, generateAttributes)
 
                Case SyntaxKind.InvocationExpression
                    Return TryGenerateMethodCall(DirectCast(expression, InvocationExpressionSyntax))
 
                Case SyntaxKind.GetTypeExpression
                    Return TryGenerateGetTypeExpression(DirectCast(expression, GetTypeExpressionSyntax))
 
                Case SyntaxKind.CTypeExpression,
                     SyntaxKind.DirectCastExpression,
                     SyntaxKind.TryCastExpression
                    Return TryGenerateCastExpression(DirectCast(expression, CastExpressionSyntax))
 
                Case SyntaxKind.PredefinedCastExpression
                    Return TryGeneratePredefinedCastExpression(DirectCast(expression, PredefinedCastExpressionSyntax))
 
                Case SyntaxKind.MeExpression
                    GenerateThisReference()
                    Return True
 
                Case SyntaxKind.AddressOfExpression
                    Return TryGenerateAddressOfExpression(DirectCast(expression, UnaryExpressionSyntax))
            End Select
 
            Return False
        End Function
 
        Private Function TryGenerateLiteral(expression As ExpressionSyntax) As Boolean
            Using LiteralTag()
                Dim constantValue = SemanticModel.GetConstantValue(expression)
                If Not constantValue.HasValue Then
                    Return False
                End If
 
                Dim type = SemanticModel.GetTypeInfo(expression).Type
                If type Is Nothing Then
                    Return False
                End If
 
                Select Case expression.Kind
                    Case SyntaxKind.UnaryMinusExpression,
                         SyntaxKind.NumericLiteralExpression
                        GenerateNumber(constantValue.Value, type)
                        Return True
 
                    Case SyntaxKind.CharacterLiteralExpression
                        GenerateChar(CChar(constantValue.Value))
                        Return True
 
                    Case SyntaxKind.StringLiteralExpression
                        GenerateString(CStr(constantValue.Value))
                        Return True
 
                    Case SyntaxKind.TrueLiteralExpression,
                         SyntaxKind.FalseLiteralExpression
                        GenerateBoolean(CBool(constantValue.Value))
                        Return True
                End Select
            End Using
 
            Return False
        End Function
 
        Private Function TryGenerateParenthesizedExpression(parenthesizedExpression As ParenthesizedExpressionSyntax) As Boolean
            Using ParenthesesTag()
                Return TryGenerateExpression(parenthesizedExpression.Expression)
            End Using
        End Function
 
        Private Function TryGenerateBinaryOperation(binaryExpression As BinaryExpressionSyntax) As Boolean
            Dim kind As BinaryOperatorKind
            Select Case binaryExpression.Kind
                Case SyntaxKind.AddExpression
                    kind = BinaryOperatorKind.Plus
                Case SyntaxKind.OrExpression
                    kind = BinaryOperatorKind.BitwiseOr
                Case SyntaxKind.AndExpression
                    kind = BinaryOperatorKind.BitwiseAnd
                Case SyntaxKind.ConcatenateExpression
                    kind = BinaryOperatorKind.Concatenate
                Case Else
                    Return False
            End Select
 
            Using BinaryOperationTag(kind)
                Return TryGenerateExpression(binaryExpression.Left) AndAlso
                       TryGenerateExpression(binaryExpression.Right)
            End Using
        End Function
 
        Private Function TryGenerateNewClass(objectCreationExpression As ObjectCreationExpressionSyntax) As Boolean
            Dim type = TryCast(SemanticModel.GetSymbolInfo(objectCreationExpression.Type).Symbol, ITypeSymbol)
            If type Is Nothing Then
                Return False
            End If
 
            Using NewClassTag()
                GenerateType(type)
 
                If objectCreationExpression.ArgumentList IsNot Nothing Then
                    For Each argument In objectCreationExpression.ArgumentList.Arguments
                        If Not TryGenerateArgument(argument) Then
                            Return False
                        End If
                    Next
                End If
            End Using
 
            Return True
        End Function
 
        Private Function TryGenerateArgument(argument As ArgumentSyntax) As Boolean
            Using ArgumentTag()
                Return TryGenerateExpression(argument.GetArgumentExpression())
            End Using
        End Function
 
        Protected Overrides Function GetVariableKind(symbol As ISymbol) As VariableKind
            Dim kind = MyBase.GetVariableKind(symbol)
 
            ' need to special case WithEvent properties. CodeModel wants them as fields.
            If symbol?.Kind = SymbolKind.Property Then
                Dim propertySymbol = TryCast(symbol, IPropertySymbol)
                If propertySymbol IsNot Nothing AndAlso propertySymbol.IsWithEvents Then
                    kind = VariableKind.Field
                End If
            End If
 
            Return kind
        End Function
 
        Private Shared Function GetFullNameText(symbol As ISymbol) As String
            If symbol Is Nothing Then
                Return Nothing
            End If
 
            If symbol.IsAccessor() Then
                Return Nothing
            End If
 
            Return symbol.ContainingSymbol.ToDisplayString(s_fullNameFormat) & "." & symbol.Name
        End Function
 
        Private Function TryGenerateNameRef(
            memberAccess As MemberAccessExpressionSyntax,
            Optional symbolOpt As ISymbol = Nothing,
            Optional generateAttributes As Boolean = False
        ) As Boolean
 
            symbolOpt = If(symbolOpt, SemanticModel.GetSymbolInfo(memberAccess).Symbol)
 
            ' Note: There's no null check for 'symbolOpt' here. If 'symbolOpt' is Nothing, we'll generate an "unknown" name ref.
            Dim varKind As VariableKind = GetVariableKind(symbolOpt)
 
            Dim name = If(symbolOpt IsNot Nothing, symbolOpt.Name, memberAccess.Name.Identifier.ValueText)
            Dim nameAttribute = If(generateAttributes, name, Nothing)
            Dim fullNameAttribute = If(generateAttributes, GetFullNameText(symbolOpt), Nothing)
 
            Using NameRefTag(varKind, nameAttribute, fullNameAttribute)
 
                Dim leftHandSymbol = SemanticModel.GetSymbolInfo(memberAccess.GetExpressionOfMemberAccessExpression()).Symbol
                If leftHandSymbol IsNot Nothing Then
                    If leftHandSymbol.Kind = SymbolKind.Alias Then
                        leftHandSymbol = DirectCast(leftHandSymbol, IAliasSymbol).Target
                    End If
 
                    ' This can occur if a module member is referenced without the module name. In that case,
                    ' we'll go ahead and try to use the module namespace name.
                    If leftHandSymbol.Kind = SymbolKind.Namespace AndAlso
                       symbolOpt?.ContainingType?.TypeKind = TypeKind.Module Then
 
                        leftHandSymbol = symbolOpt.ContainingType
                    End If
                End If
 
                ' If the left-hand side is a named type, we generate a literal expression
                ' with the type name. Otherwise, we generate the expression normally.
                If leftHandSymbol IsNot Nothing AndAlso leftHandSymbol.Kind = SymbolKind.NamedType Then
                    Using ExpressionTag()
                        Using LiteralTag()
                            GenerateType(DirectCast(leftHandSymbol, ITypeSymbol))
                        End Using
                    End Using
                ElseIf Not TryGenerateExpression(memberAccess.GetExpressionOfMemberAccessExpression(), generateAttributes:=generateAttributes) Then
                    Return False
                End If
 
                If Not generateAttributes Then
                    GenerateName(name)
                End If
            End Using
 
            Return True
        End Function
 
        Private Function TryGenerateNameRef(
            identifierName As IdentifierNameSyntax,
            Optional symbolOpt As ISymbol = Nothing,
            Optional generateAttributes As Boolean = False
        ) As Boolean
 
            symbolOpt = If(symbolOpt, SemanticModel.GetSymbolInfo(identifierName).Symbol)
 
            ' Note: There's no null check for 'symbolOpt' here. If 'symbolOpt' is Nothing, we'll generate an "unknown" name ref.
            Dim varKind = GetVariableKind(symbolOpt)
 
            Dim name = If(symbolOpt IsNot Nothing, symbolOpt.Name, identifierName.Identifier.ValueText)
            Dim nameAttribute = If(generateAttributes, name, Nothing)
            Dim fullNameAttribute = If(generateAttributes, GetFullNameText(symbolOpt), Nothing)
 
            Using NameRefTag(varKind, nameAttribute, fullNameAttribute)
                If symbolOpt IsNot Nothing AndAlso varKind <> VariableKind.Local Then
                    GenerateLastNameRef(symbolOpt)
                End If
 
                If Not generateAttributes Then
                    GenerateName(name)
                End If
            End Using
 
            Return True
        End Function
 
        Private Sub GenerateLastNameRef(symbol As ISymbol)
            ' This is a little tricky -- if our method symbol's containing type inherits from
            ' or is the same as the identifier symbol's containing type, we'll go ahead and
            ' generate a <ThisReference />. Otherwise, because this is an identifier, we assume
            ' that it is a Shared member or an imported type (for example, a Module) and generate
            ' an <Expression><Literal><Type/></Literal></Expression>
            If Me.Symbol.ContainingType.InheritsFromOrEquals(symbol.ContainingType) Then
                Using ExpressionTag()
                    GenerateThisReference()
                End Using
            Else
                Using ExpressionTag()
                    Using LiteralTag()
                        GenerateType(symbol.ContainingType)
                    End Using
                End Using
            End If
        End Sub
 
        Private Function TryGenerateMethodCall(invocationExpression As InvocationExpressionSyntax) As Boolean
            Using MethodCallTag()
                If Not TryGenerateExpression(invocationExpression.Expression) Then
                    Return False
                End If
 
                If invocationExpression.ArgumentList IsNot Nothing Then
                    For Each argument In invocationExpression.ArgumentList.Arguments
                        If Not TryGenerateArgument(argument) Then
                            Return False
                        End If
                    Next
                End If
            End Using
 
            Return True
        End Function
 
        Private Function TryGenerateGetTypeExpression(getTypeExpression As GetTypeExpressionSyntax) As Boolean
            If getTypeExpression.Type Is Nothing Then
                Return False
            End If
 
            Dim type = SemanticModel.GetTypeInfo(getTypeExpression.Type).Type
            If type Is Nothing Then
                Return False
            End If
 
            GenerateType(type)
 
            Return True
        End Function
 
        Private Function TryGenerateCast(type As ITypeSymbol, expression As ExpressionSyntax, Optional specialCastKind As SpecialCastKind? = Nothing) As Boolean
            Using (CastTag(specialCastKind))
                GenerateType(type)
 
                Return TryGenerateExpression(expression)
            End Using
        End Function
 
        Private Function TryGenerateCastExpression(castExpression As CastExpressionSyntax) As Boolean
            If castExpression.Type Is Nothing Then
                Return False
            End If
 
            Dim type = SemanticModel.GetTypeInfo(castExpression.Type).Type
            If type Is Nothing Then
                Return False
            End If
 
            If Not TryGenerateCast(type, castExpression.Expression, GetSpecialCastKind(castExpression)) Then
                Return False
            End If
 
            Return True
        End Function
 
        Private Shared Function GetSpecialCastKind(castExpression As CastExpressionSyntax) As SpecialCastKind?
            Select Case castExpression.Kind()
                Case SyntaxKind.DirectCastExpression
                    Return SpecialCastKind.DirectCast
                Case SyntaxKind.TryCastExpression
                    Return SpecialCastKind.TryCast
                Case Else
                    Return Nothing
            End Select
        End Function
 
        Private Function TryGeneratePredefinedCastExpression(predefinedCastExpression As PredefinedCastExpressionSyntax) As Boolean
            Dim type = GetTypeFromPredefinedCastKeyword(SemanticModel.Compilation, predefinedCastExpression.Keyword.Kind)
            If type Is Nothing Then
                Return False
            End If
 
            If Not TryGenerateCast(type, predefinedCastExpression.Expression) Then
                Return False
            End If
 
            Return True
        End Function
 
        Private Function TryGenerateConstantArrayBound(expression As ExpressionSyntax) As Boolean
            Dim constantValue = SemanticModel.GetConstantValue(expression)
 
            If Not constantValue.HasValue Then
                Return False
            End If
 
            If Not TypeOf constantValue.Value Is Integer Then
                Return False
            End If
 
            Dim upperBound = CInt(constantValue.Value) + 1
 
            Using ExpressionTag()
                Using LiteralTag()
                    GenerateNumber(upperBound, SemanticModel.Compilation.GetSpecialType(SpecialType.System_Int32))
                End Using
            End Using
 
            Return True
        End Function
 
        Private Function TryGenerateSimpleArrayBound(argument As ArgumentSyntax) As Boolean
            If Not TypeOf argument Is SimpleArgumentSyntax Then
                Return False
            End If
 
            Return TryGenerateConstantArrayBound(DirectCast(argument, SimpleArgumentSyntax).Expression)
        End Function
 
        Private Function TryGenerateRangeArrayBound(argument As ArgumentSyntax) As Boolean
            If Not TypeOf argument Is RangeArgumentSyntax Then
                Return False
            End If
 
            Return TryGenerateConstantArrayBound(DirectCast(argument, RangeArgumentSyntax).UpperBound)
        End Function
 
        Private Function TryGenerateCollectionInitializer(collectionInitializer As CollectionInitializerSyntax) As Boolean
            For Each initializer In collectionInitializer.Initializers
                If Not TryGenerateExpression(initializer) Then
                    Return False
                End If
            Next
 
            Return True
        End Function
 
        Private Function TryGenerateNewArray(arrayBounds As ArgumentListSyntax, initializer As ExpressionSyntax, type As ITypeSymbol) As Boolean
            Using NewArrayTag()
                GenerateType(type)
 
                If arrayBounds IsNot Nothing Then
 
                    If Not TryGenerateArrayBounds(arrayBounds) Then
                        Return False
                    End If
 
                    If initializer IsNot Nothing AndAlso initializer.Kind = SyntaxKind.CollectionInitializer Then
                        If Not TryGenerateCollectionInitializer(DirectCast(initializer, CollectionInitializerSyntax)) Then
                            Return False
                        End If
                    End If
 
                Else
                    ' No array bounds...
 
                    If initializer IsNot Nothing Then
                        If type.TypeKind = TypeKind.Array Then
                            Select Case initializer.Kind
                                Case SyntaxKind.ArrayCreationExpression
                                    If Not TryGenerateArrayCreation(DirectCast(initializer, ArrayCreationExpressionSyntax)) Then
                                        Return False
                                    End If
                                Case SyntaxKind.CollectionInitializer
                                    If Not TryGenerateArrayInitializer(DirectCast(initializer, CollectionInitializerSyntax)) Then
                                        Return False
                                    End If
                                Case Else
                                    Return False
                            End Select
                        ElseIf Not TryGenerateExpression(initializer) Then
                            Return False
                        End If
                    End If
 
                End If
 
                Return True
            End Using
        End Function
 
        Private Function TryGenerateArrayBounds(argumentList As ArgumentListSyntax) As Boolean
            For Each argument In argumentList.Arguments
                Using BoundTag()
                    If Not TryGenerateSimpleArrayBound(argument) AndAlso
                       Not TryGenerateRangeArrayBound(argument) Then
                        Return False
                    End If
                End Using
            Next
 
            Return True
        End Function
 
        Private Function TryGenerateArrayInitializer(collectionInitializer As CollectionInitializerSyntax) As Boolean
            Using BoundTag()
                Using ExpressionTag()
                    Using LiteralTag()
                        Using NumberTag()
                            EncodedText(collectionInitializer.Initializers.Count.ToString())
                        End Using
                    End Using
                End Using
            End Using
 
            Return TryGenerateCollectionInitializer(collectionInitializer)
        End Function
 
        Private Function TryGenerateArrayCreation(arrayCreationExpression As ArrayCreationExpressionSyntax) As Boolean
            Dim type = SemanticModel.GetTypeInfo(arrayCreationExpression).Type
            If type Is Nothing Then
                Return False
            End If
 
            If Not TryGenerateNewArray(arrayCreationExpression.ArrayBounds, arrayCreationExpression.Initializer, type) Then
                Return False
            End If
 
            Return True
        End Function
 
        Private Function TryGenerateAddressOfExpression(expression As UnaryExpressionSyntax) As Boolean
            Debug.Assert(expression.Kind() = SyntaxKind.AddressOfExpression)
 
            Dim delegateExpression = expression.Operand
 
            Dim delegateSymbol = TryCast(SemanticModel.GetSymbolInfo(delegateExpression).Symbol, IMethodSymbol)
            If delegateSymbol Is Nothing Then
                Return False
            End If
 
            Dim eventType = SemanticModel.GetTypeInfo(expression).Type
            If eventType Is Nothing Then
                Return False
            End If
 
            Using NewDelegateTag(delegateSymbol.Name)
                GenerateType(eventType, implicit:=True, assemblyQualify:=True)
 
                If delegateExpression.Kind() = SyntaxKind.IdentifierName Then
                    GenerateLastNameRef(delegateSymbol)
                ElseIf delegateExpression.Kind() = SyntaxKind.SimpleMemberAccessExpression
                    Dim memberAccess = DirectCast(delegateExpression, MemberAccessExpressionSyntax)
                    If Not TryGenerateExpression(memberAccess.GetExpressionOfMemberAccessExpression(), generateAttributes:=True) Then
                        Return False
                    End If
                End If
 
                GenerateType(delegateSymbol.ContainingType, implicit:=True, assemblyQualify:=True)
 
                Return True
            End Using
        End Function
 
        Public Shared Function Generate(methodBlock As MethodBlockBaseSyntax, semanticModel As SemanticModel) As String
            Dim symbol = semanticModel.GetDeclaredSymbol(methodBlock)
            Dim builder = New MethodXmlBuilder(symbol, semanticModel)
 
            builder.GenerateStatementBlock(methodBlock.Statements)
 
            Return builder.ToString()
        End Function
 
    End Class
End Namespace