File: Emit\NoPia\EmbeddedEvent.vb
Web Access
Project: src\src\roslyn\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 Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols

#If Not DEBUG Then
Imports EventSymbolAdapter = Microsoft.CodeAnalysis.VisualBasic.Symbols.EventSymbol
#End If

Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia

    Friend NotInheritable Class EmbeddedEvent
        Inherits EmbeddedTypesManager.CommonEmbeddedEvent

        Public Sub New(underlyingEvent As EventSymbolAdapter, adder As EmbeddedMethod, remover As EmbeddedMethod, caller As EmbeddedMethod)
            MyBase.New(underlyingEvent, adder, remover, caller)
        End Sub

        Protected Overrides Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData)
            Return UnderlyingEvent.AdaptedEventSymbol.GetCustomAttributesToEmit(moduleBuilder)
        End Function

        Protected Overrides ReadOnly Property IsRuntimeSpecial As Boolean
            Get
                Return UnderlyingEvent.AdaptedEventSymbol.HasRuntimeSpecialName
            End Get
        End Property

        Protected Overrides ReadOnly Property IsSpecialName As Boolean
            Get
                Return UnderlyingEvent.AdaptedEventSymbol.HasSpecialName
            End Get
        End Property

        Protected Overrides Function [GetType](moduleBuilder As PEModuleBuilder, syntaxNodeOpt As SyntaxNode, diagnostics As DiagnosticBag) As Cci.ITypeReference
            Return moduleBuilder.Translate(UnderlyingEvent.AdaptedEventSymbol.Type, syntaxNodeOpt, diagnostics)
        End Function

        Protected Overrides ReadOnly Property ContainingType As EmbeddedType
            Get
                Return AnAccessor.ContainingType
            End Get
        End Property

        Protected Overrides ReadOnly Property Visibility As Cci.TypeMemberVisibility
            Get
                Return UnderlyingEvent.AdaptedEventSymbol.MetadataVisibility
            End Get
        End Property

        Protected Overrides ReadOnly Property Name As String
            Get
                Return UnderlyingEvent.AdaptedEventSymbol.MetadataName
            End Get
        End Property

        Protected Overrides Sub EmbedCorrespondingComEventInterfaceMethodInternal(syntaxNodeOpt As SyntaxNode, diagnostics As DiagnosticBag, isUsedForComAwareEventBinding As Boolean)
            ' If the event happens to belong to a class with a ComEventInterfaceAttribute, there will also be
            ' a paired method living on its source interface. The ComAwareEventInfo class expects to find this 
            ' method through reflection. If we embed an event, therefore, we must ensure that the associated source
            ' interface method is also included, even if it is not otherwise referenced in the embedding project.
            Dim underlyingContainingType = ContainingType.UnderlyingNamedType

            For Each attrData In underlyingContainingType.AdaptedNamedTypeSymbol.GetAttributes()
                Dim signatureIndex As Integer = attrData.GetTargetAttributeSignatureIndex(AttributeDescription.ComEventInterfaceAttribute)

                If signatureIndex = 0 Then
                    Dim foundMatch = False
                    Dim sourceInterface As NamedTypeSymbol = Nothing

                    Dim errorInfo As DiagnosticInfo = attrData.ErrorInfo
                    If errorInfo IsNot Nothing Then
                        diagnostics.Add(errorInfo, If(syntaxNodeOpt?.Location, NoLocation.Singleton))
                    End If

                    If Not attrData.HasErrors Then
                        sourceInterface = TryCast(attrData.CommonConstructorArguments(0).ValueInternal, NamedTypeSymbol)
                        If sourceInterface IsNot Nothing Then
                            foundMatch = EmbedMatchingInterfaceMethods(sourceInterface, syntaxNodeOpt, diagnostics)

                            For Each source In sourceInterface.AllInterfacesNoUseSiteDiagnostics
                                If EmbedMatchingInterfaceMethods(source, syntaxNodeOpt, diagnostics) Then
                                    foundMatch = True
                                End If
                            Next
                        End If
                    End If

                    If Not foundMatch AndAlso isUsedForComAwareEventBinding Then
                        If sourceInterface Is Nothing Then
                            ' ERRID_SourceInterfaceMustBeInterface/ERR_MissingSourceInterface
                            EmbeddedTypesManager.ReportDiagnostic(diagnostics, ERRID.ERR_SourceInterfaceMustBeInterface, syntaxNodeOpt, underlyingContainingType.AdaptedNamedTypeSymbol, UnderlyingEvent.AdaptedEventSymbol)
                        Else
                            Dim useSiteInfo = CompoundUseSiteInfo(Of AssemblySymbol).DiscardedDependencies
                            sourceInterface.AllInterfacesWithDefinitionUseSiteDiagnostics(useSiteInfo)
                            diagnostics.Add(If(syntaxNodeOpt Is Nothing, NoLocation.Singleton, syntaxNodeOpt.GetLocation()), useSiteInfo.Diagnostics)

                            ' ERRID_EventNoPIANoBackingMember/ERR_MissingMethodOnSourceInterface
                            EmbeddedTypesManager.ReportDiagnostic(diagnostics, ERRID.ERR_EventNoPIANoBackingMember, syntaxNodeOpt, sourceInterface, UnderlyingEvent.AdaptedEventSymbol.MetadataName, UnderlyingEvent.AdaptedEventSymbol)
                        End If
                    End If

                    Exit For
                End If
            Next
        End Sub

        Private Function EmbedMatchingInterfaceMethods(sourceInterface As NamedTypeSymbol, syntaxNodeOpt As SyntaxNode, diagnostics As DiagnosticBag) As Boolean
            Dim foundMatch = False
            For Each m In sourceInterface.GetMembers(UnderlyingEvent.AdaptedEventSymbol.MetadataName)
                If m.Kind = SymbolKind.Method Then
                    TypeManager.EmbedMethodIfNeedTo(DirectCast(m, MethodSymbol).GetCciAdapter(), syntaxNodeOpt, diagnostics)
                    foundMatch = True
                End If
            Next
            Return foundMatch
        End Function

    End Class

End Namespace