/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_AddRemoveHandler.vb
316 строк
16 KB
AlekseyTs
Follow up on addition of `InternalSpecialType` (#72704)
26 мар 2024, 01:29
Не верифицирован
26 мар 2024, 01:29
48812dd
Код
Авторство
О чём код?
' 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.Diagnostics Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.CodeGen Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic Partial Friend NotInheritable Class LocalRewriter Public Overrides Function VisitAddHandlerStatement(node As BoundAddHandlerStatement) As BoundNode Dim rewritten = RewriteAddRemoveHandler(node) If Instrument(node, rewritten) Then rewritten = _instrumenterOpt.InstrumentAddHandlerStatement(node, rewritten) End If Return rewritten End Function Public Overrides Function VisitRemoveHandlerStatement(node As BoundRemoveHandlerStatement) As BoundNode Dim rewritten = RewriteAddRemoveHandler(node) If Instrument(node, rewritten) Then rewritten = _instrumenterOpt.InstrumentRemoveHandlerStatement(node, rewritten) End If Return rewritten End Function Private Function RewriteAddRemoveHandler(node As BoundAddRemoveHandlerStatement) As BoundStatement Dim unwrappedEventAccess As BoundEventAccess = UnwrapEventAccess(node.EventAccess) Dim [event] = unwrappedEventAccess.EventSymbol Dim saveState As UnstructuredExceptionHandlingContext = LeaveUnstructuredExceptionHandlingContext(node) Dim result As BoundStatement If [event].IsWindowsRuntimeEvent Then result = RewriteWinRtEvent(node, unwrappedEventAccess, isAddition:=(node.Kind = BoundKind.AddHandlerStatement)) Else result = MakeEventAccessorCall(node, unwrappedEventAccess, If(node.Kind = BoundKind.AddHandlerStatement, [event].AddMethod, [event].RemoveMethod)) End If RestoreUnstructuredExceptionHandlingContext(node, saveState) If ShouldGenerateUnstructuredExceptionHandlingResumeCode(node) Then result = RegisterUnstructuredExceptionHandlingResumeTarget(node.Syntax, result, canThrow:=True) End If Return result End Function ''' <summary> ''' If we have a WinRT type event, we need to encapsulate the adder call ''' (which returns an EventRegistrationToken) with a call to ''' WindowsRuntimeMarshal.AddEventHandler or RemoveEventHandler, but these ''' require us to create a new Func representing the adder and another ''' Action representing the remover. ''' ''' The rewritten call looks something like: ''' ''' WindowsRuntimeMarshal.AddEventHandler(Of TEventHandler)( ''' New Func(Of TEventHandler, EventRegistrationToken)([object].add_T), ''' New Action(Of EventRegistrationToken)([object].remove_T), ''' New TEventHandler(Me.OnSuspending)) ''' ''' ''' where [object] is a compiler-generated local temp. ''' ''' For a remover, the call looks like: ''' ''' WindowsRuntimeMarshal.RemoveEventHandler(Of TEventHandler)( ''' New Action(Of EventRegistrationToken)([object].remove_T), ''' New TEventHandler(Me.OnSuspending)) ''' </summary> Private Function RewriteWinRtEvent(node As BoundAddRemoveHandlerStatement, unwrappedEventAccess As BoundEventAccess, isAddition As Boolean) As BoundStatement Dim syntax As SyntaxNode = node.Syntax Dim eventSymbol As EventSymbol = unwrappedEventAccess.EventSymbol Dim rewrittenReceiverOpt As BoundExpression = GetEventAccessReceiver(unwrappedEventAccess) Dim rewrittenHandler As BoundExpression = VisitExpressionNode(node.Handler) Dim tempAssignment As BoundAssignmentOperator = Nothing Dim boundTemp As BoundLocal = Nothing If Not eventSymbol.IsShared AndAlso EventReceiverNeedsTemp(rewrittenReceiverOpt) Then Dim receiverType As TypeSymbol = rewrittenReceiverOpt.Type boundTemp = New BoundLocal(syntax, New SynthesizedLocal(Me._currentMethodOrLambda, receiverType, SynthesizedLocalKind.LoweringTemp), receiverType) tempAssignment = New BoundAssignmentOperator(syntax, boundTemp, GenerateObjectCloneIfNeeded(unwrappedEventAccess.ReceiverOpt, rewrittenReceiverOpt.MakeRValue), True) End If Dim tokenType As NamedTypeSymbol = Me.Compilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationToken) Dim marshalType As NamedTypeSymbol = Me.Compilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal) Dim actionType As NamedTypeSymbol = Me.Compilation.GetWellKnownType(WellKnownType.System_Action_T) Dim eventType As TypeSymbol = eventSymbol.Type actionType = actionType.Construct(tokenType) Dim delegateCreationArgument = If(boundTemp, If(rewrittenReceiverOpt, New BoundTypeExpression(syntax, eventType).MakeCompilerGenerated)).MakeRValue Dim removeDelegate As BoundDelegateCreationExpression = New BoundDelegateCreationExpression( syntax:=syntax, receiverOpt:=delegateCreationArgument, method:=eventSymbol.RemoveMethod, relaxationLambdaOpt:=Nothing, relaxationReceiverPlaceholderOpt:=Nothing, methodGroupOpt:=Nothing, type:=actionType) Dim marshalMethodId As WellKnownMember Dim marshalArguments As ImmutableArray(Of BoundExpression) If isAddition Then Dim func2Type As NamedTypeSymbol = Me.Compilation.GetWellKnownType(WellKnownType.System_Func_T2) func2Type = func2Type.Construct(eventType, tokenType) Dim addDelegate As BoundDelegateCreationExpression = New BoundDelegateCreationExpression( syntax:=syntax, receiverOpt:=delegateCreationArgument, method:=eventSymbol.AddMethod, relaxationLambdaOpt:=Nothing, relaxationReceiverPlaceholderOpt:=Nothing, methodGroupOpt:=Nothing, type:=func2Type) marshalMethodId = WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal__AddEventHandler_T marshalArguments = ImmutableArray.Create(Of BoundExpression)(addDelegate, removeDelegate, rewrittenHandler) Else marshalMethodId = WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal__RemoveEventHandler_T marshalArguments = ImmutableArray.Create(Of BoundExpression)(removeDelegate, rewrittenHandler) End If Dim marshalMethod As MethodSymbol = Nothing If Not TryGetWellknownMember(marshalMethod, marshalMethodId, syntax) Then Return New BoundExpressionStatement( syntax, New BoundBadExpression( syntax, LookupResultKind.Empty, ImmutableArray.Create(Of Symbol)(eventSymbol), ImmutableArray(Of BoundExpression).Empty, ErrorTypeSymbol.UnknownResultType, hasErrors:=True)) End If marshalMethod = marshalMethod.Construct(eventType) Dim marshalCall As BoundExpression = New BoundCall( syntax:=syntax, method:=DirectCast(marshalMethod, MethodSymbol), methodGroupOpt:=Nothing, receiverOpt:=Nothing, arguments:=marshalArguments, constantValueOpt:=Nothing, suppressObjectClone:=True, type:=marshalMethod.ReturnType) If boundTemp Is Nothing Then Return New BoundExpressionStatement(syntax, marshalCall) End If Return New BoundBlock( syntax:=syntax, statementListSyntax:=Nothing, locals:=ImmutableArray.Create(Of LocalSymbol)(boundTemp.LocalSymbol), statements:=ImmutableArray.Create(Of BoundStatement)( New BoundExpressionStatement(syntax, tempAssignment), New BoundExpressionStatement(syntax, marshalCall))) End Function ' See LocalRewriter.NeedsTemp in C# if we want to use this more generally. Private Shared Function EventReceiverNeedsTemp(expression As BoundExpression) As Boolean Select Case expression.Kind Case BoundKind.MeReference, BoundKind.MyClassReference, BoundKind.MyBaseReference Return False Case BoundKind.Literal ' don't allocate a temp for simple integral primitive types Return expression.Type IsNot Nothing AndAlso Not expression.Type.SpecialType.IsClrInteger() Case BoundKind.Local, BoundKind.Parameter Return False Case Else Return True End Select End Function Public Overrides Function VisitEventAccess(node As BoundEventAccess) As BoundNode Debug.Assert(False, "All event accesses should be handled by AddHandler/RemoveHandler/RaiseEvent.") Return MyBase.VisitEventAccess(node) End Function Private Function MakeEventAccessorCall(node As BoundAddRemoveHandlerStatement, unwrappedEventAccess As BoundEventAccess, accessorSymbol As MethodSymbol) As BoundStatement Dim receiver As BoundExpression = GetEventAccessReceiver(unwrappedEventAccess) Dim handler As BoundExpression = VisitExpressionNode(node.Handler) Dim [event] = unwrappedEventAccess.EventSymbol Dim expr As BoundExpression = Nothing If receiver IsNot Nothing AndAlso [event].ContainingAssembly.IsLinked AndAlso [event].ContainingType.IsInterfaceType() Then Dim [interface] = [event].ContainingType For Each attrData In [interface].GetAttributes() Dim signatureIndex As Integer = attrData.GetTargetAttributeSignatureIndex(AttributeDescription.ComEventInterfaceAttribute) If signatureIndex = 0 Then Dim errorInfo As DiagnosticInfo = attrData.ErrorInfo If errorInfo IsNot Nothing Then _diagnostics.Add(errorInfo, node.EventAccess.Syntax.Location) End If If Not attrData.HasErrors Then expr = RewriteNoPiaAddRemoveHandler(node, receiver, [event], handler) Exit For End If End If Next End If If expr Is Nothing Then expr = New BoundCall(node.Syntax, accessorSymbol, Nothing, receiver, ImmutableArray.Create(handler), Nothing, accessorSymbol.ReturnType) End If Return New BoundExpressionStatement(node.Syntax, expr) End Function Private Function UnwrapEventAccess(node As BoundExpression) As BoundEventAccess If node.Kind = BoundKind.EventAccess Then Return DirectCast(node, BoundEventAccess) End If Debug.Assert(node.Kind = BoundKind.Parenthesized, "node can only be EventAccess or Parenthesized") Return UnwrapEventAccess(DirectCast(node, BoundParenthesized).Expression) End Function Private Function GetEventAccessReceiver(unwrappedEventAccess As BoundEventAccess) As BoundExpression If unwrappedEventAccess.ReceiverOpt Is Nothing Then Return Nothing End If ' Visit (for diagnostics) regardless of whether or not it will be returned. Dim rewrittenReceiver As BoundExpression = VisitExpressionNode(unwrappedEventAccess.ReceiverOpt) Return If(unwrappedEventAccess.EventSymbol.IsShared, Nothing, rewrittenReceiver) End Function Private Function RewriteNoPiaAddRemoveHandler( node As BoundAddRemoveHandlerStatement, receiver As BoundExpression, [event] As EventSymbol, handler As BoundExpression ) As BoundExpression ' Translate: AddHandler myPIA.Event, Handler ' to: New ComAwareEventInfo(GetType(myPIA), "Event").AddEventHandler(myPIA, Handler) Dim factory As New SyntheticBoundNodeFactory(_topMethod, _currentMethodOrLambda, node.Syntax, _compilationState, _diagnostics) Dim result As BoundExpression = Nothing Dim ctor = factory.WellKnownMember(Of MethodSymbol)(WellKnownMember.System_Runtime_InteropServices_ComAwareEventInfo__ctor) If ctor IsNot Nothing Then Dim addRemove = factory.WellKnownMember(Of MethodSymbol)(If(node.Kind = BoundKind.AddHandlerStatement, WellKnownMember.System_Runtime_InteropServices_ComAwareEventInfo__AddEventHandler, WellKnownMember.System_Runtime_InteropServices_ComAwareEventInfo__RemoveEventHandler)) If addRemove IsNot Nothing Then Dim eventInfo = factory.[New](ctor, factory.Typeof([event].ContainingType, ctor.Parameters(0).Type), factory.Literal([event].MetadataName)) result = factory.Call(eventInfo, addRemove, Convert(factory, addRemove.Parameters(0).Type, receiver.MakeRValue()), Convert(factory, addRemove.Parameters(1).Type, handler)) End If End If ' The code we just generated doesn't contain any direct references to the event itself, ' but the com event binder needs the event to exist on the local type. We'll poke the pia reference ' cache directly so that the event is embedded. If _emitModule IsNot Nothing Then _emitModule.EmbeddedTypesManagerOpt.EmbedEventIfNeedTo([event].GetCciAdapter(), node.Syntax, _diagnostics.DiagnosticBag, isUsedForComAwareEventBinding:=True) End If If result IsNot Nothing Then Return result End If Return New BoundBadExpression(node.Syntax, LookupResultKind.NotCreatable, ImmutableArray.Create(Of Symbol)([event]), ImmutableArray.Create(receiver, handler), ErrorTypeSymbol.UnknownResultType, hasErrors:=True) End Function Private Function Convert(factory As SyntheticBoundNodeFactory, type As TypeSymbol, expr As BoundExpression) As BoundExpression Return TransformRewrittenConversion(factory.Convert(type, expr)) End Function End Class End Namespace