/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Symbols/Source/CustomEventAccessorSymbol.vb
283 строки
14 KB
Tomáš Matoušek
Refactoring of extension methods in source packages (#78620) - take 2 (#78894)
26 июн 2025, 18:42
Не верифицирован
26 июн 2025, 18:42
05fc006
Код
Авторство
О чём код?
' 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.Threading Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend NotInheritable Class CustomEventAccessorSymbol Inherits SourceNonPropertyAccessorMethodSymbol Private ReadOnly _event As SourceEventSymbol Private ReadOnly _name As String Private _lazyExplicitImplementations As ImmutableArray(Of MethodSymbol) ' lazily populated with explicit implementations Friend Sub New(container As SourceMemberContainerTypeSymbol, [event] As SourceEventSymbol, name As String, flags As SourceMemberFlags, syntaxRef As SyntaxReference, location As Location) MyBase.New(container, flags, syntaxRef, locations:=ImmutableArray.Create(location)) _event = [event] _name = name End Sub Public Overrides ReadOnly Property Name As String Get Return _name End Get End Property Public Overrides ReadOnly Property MetadataName As String Get ' Event symbols aren't affected if the output kind is winmd, mark false ' (N.B., events only emits helpers named add_ and remove_, not set_) Return Binder.GetAccessorName(_event.MetadataName, Me.MethodKind, isWinMd:=False) End Get End Property Public Overrides ReadOnly Property TypeParameters As ImmutableArray(Of TypeParameterSymbol) Get Return ImmutableArray(Of TypeParameterSymbol).Empty End Get End Property Public Overrides ReadOnly Property DeclaredAccessibility As Accessibility Get ' Raise is always private If Me.MethodKind = MethodKind.EventRaise Then Return Accessibility.Private End If Return _event.DeclaredAccessibility End Get End Property Protected Overrides Function GetParameters(sourceModule As SourceModuleSymbol, diagBag As BindingDiagnosticBag) As ImmutableArray(Of ParameterSymbol) Dim type = DirectCast(Me.ContainingType, SourceMemberContainerTypeSymbol) Dim binder As Binder = BinderBuilder.CreateBinderForType(sourceModule, Me.SyntaxTree, type) binder = New LocationSpecificBinder(BindingLocation.EventAccessorSignature, Me, binder) Return BindParameters(Me.Locations.FirstOrDefault, binder, BlockSyntax.BlockStatement.ParameterList, diagBag) End Function Public Overrides ReadOnly Property AssociatedSymbol As Symbol Get Return _event End Get End Property Friend Overrides ReadOnly Property ShadowsExplicitly As Boolean Get Return _event.ShadowsExplicitly End Get End Property Public Overrides ReadOnly Property ExplicitInterfaceImplementations As ImmutableArray(Of MethodSymbol) Get If _lazyExplicitImplementations.IsDefault Then ImmutableInterlocked.InterlockedCompareExchange( _lazyExplicitImplementations, _event.GetAccessorImplementations(Me.MethodKind), Nothing) End If Return _lazyExplicitImplementations End Get End Property Public Overrides ReadOnly Property OverriddenMethod As MethodSymbol Get ' custom event methods do not override Return Nothing End Get End Property Public Overrides ReadOnly Property ReturnTypeCustomModifiers As ImmutableArray(Of CustomModifier) Get ' custom event methods do not have explicit returns and never implement or override Return ImmutableArray(Of CustomModifier).Empty End Get End Property Public Overrides ReadOnly Property IsExtensionMethod As Boolean Get ' Event accessors can never be an extension method. Return False End Get End Property Friend Overrides ReadOnly Property MayBeReducibleExtensionMethod As Boolean Get ' Event accessors can never be an extension method. Return False End Get End Property Protected Overrides Function GetAttributeDeclarations() As OneOrMany(Of SyntaxList(Of AttributeListSyntax)) Return OneOrMany.Create(AttributeDeclarationSyntaxList) End Function Protected Overrides Function GetReturnTypeAttributeDeclarations() As OneOrMany(Of SyntaxList(Of AttributeListSyntax)) Return Nothing End Function ''' <remarks> ''' We're going to ignore SourceMemberFlags.MethodIsSub and override IsSub explicitly. We do this because ''' the flags have to be set at construction time, but IsSub depends on IsWindowsRuntimeEvent, which depends ''' on interface implementations, which we don't want to bind until the member list is complete. (It's probably ''' okay now (2012/12/17), but it would be very fragile to take a dependency on the exact mechanism by which ''' interface members are looked up.) ''' </remarks> Public Overrides ReadOnly Property IsSub As Boolean Get Return Not (Me.MethodKind = MethodKind.EventAdd AndAlso _event.IsWindowsRuntimeEvent) End Get End Property ''' <summary> ''' Bind and validate parameters declared on the accessor. ''' </summary> Private Function BindParameters(location As Location, binder As Binder, parameterListOpt As ParameterListSyntax, diagnostics As BindingDiagnosticBag) As ImmutableArray(Of ParameterSymbol) Dim parameterListSyntax = If(parameterListOpt Is Nothing, Nothing, parameterListOpt.Parameters) Dim nParameters = parameterListSyntax.Count Dim paramBuilder = ArrayBuilder(Of ParameterSymbol).GetInstance(nParameters) ' Bind all parameters (even though we know how many to expect), ' to ensure all diagnostics are generated and ensure parameter symbols are available for binding the method body. binder.DecodeParameterList( Me, False, SourceMemberFlags.None, parameterListSyntax, paramBuilder, If(Me.MethodKind = MethodKind.EventRaise, s_checkRaiseParameterModifierCallback, s_checkAddRemoveParameterModifierCallback), diagnostics) Dim parameters = paramBuilder.ToImmutableAndFree() If Me.MethodKind = MethodKind.EventRaise Then ' Dev10 does something weird here - it checks for method conversion, but does it ' backwards - it allows delegate Invoke to be more specific than signature of Raise. ' Example: delegate may take int, but Raise may take long argument. ' ' For backwards compatibility we will do the same. ' ' NOTE: no change in raise event shape for WinRT events. Dim eventType = TryCast(_event.Type, NamedTypeSymbol) If eventType IsNot Nothing AndAlso Not eventType.IsErrorType Then Dim delInvoke = eventType.DelegateInvokeMethod ' If delegate is a function method we should already have diagnostics about that If delInvoke IsNot Nothing AndAlso delInvoke.IsSub Then Dim useSiteInfo = binder.GetNewCompoundUseSiteInfo(diagnostics) Dim conversion = Conversions.ClassifyMethodConversionForEventRaise( delInvoke, parameters, useSiteInfo) If Not diagnostics.Add(location, useSiteInfo) AndAlso (Not Conversions.IsDelegateRelaxationSupportedFor(conversion) OrElse (binder.OptionStrict = OptionStrict.On AndAlso Conversions.IsNarrowingMethodConversion(conversion, False))) Then diagnostics.Add(ERRID.ERR_RaiseEventShapeMismatch1, location, eventType) End If End If End If Else If parameters.Length <> 1 Then diagnostics.Add(ERRID.ERR_EventAddRemoveHasOnlyOneParam, location) Else Dim eventType = _event.Type Debug.Assert(eventType IsNot Nothing) Dim parameterType = parameters(0).Type Debug.Assert(parameterType IsNot Nothing) If Me.MethodKind = MethodKind.EventAdd Then If Not eventType.IsErrorType AndAlso Not TypeSymbol.Equals(eventType, parameterType, TypeCompareKind.ConsiderEverything) Then Dim errid As ERRID = If(_event.IsWindowsRuntimeEvent, ERRID.ERR_AddParamWrongForWinRT, ERRID.ERR_AddRemoveParamNotEventType) diagnostics.Add(errid, location) End If Else Debug.Assert(Me.MethodKind = MethodKind.EventRemove) If _event.ExplicitInterfaceImplementations.Any() Then ' Reporting diagnostics when this type is missing will only ever result in cascading, so don't bother. Dim registrationTokenType As NamedTypeSymbol = binder.Compilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationToken) Dim firstImplementedEvent As EventSymbol = _event.ExplicitInterfaceImplementations(0) If Not registrationTokenType.IsErrorType AndAlso firstImplementedEvent.IsWindowsRuntimeEvent <> (TypeSymbol.Equals(parameterType, registrationTokenType, TypeCompareKind.ConsiderEverything)) Then diagnostics.Add(ERRID.ERR_EventImplRemoveHandlerParamWrong, location, _event.Name, firstImplementedEvent.Name, firstImplementedEvent.ContainingType) End If ElseIf _event.IsWindowsRuntimeEvent Then ' Reporting diagnostics when this type is missing will only ever result in cascading, so don't bother. Dim registrationTokenType As NamedTypeSymbol = binder.Compilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationToken) If Not registrationTokenType.IsErrorType AndAlso Not TypeSymbol.Equals(parameterType, registrationTokenType, TypeCompareKind.ConsiderEverything) Then diagnostics.Add(ERRID.ERR_RemoveParamWrongForWinRT, location) End If Else If Not eventType.IsErrorType AndAlso Not TypeSymbol.Equals(eventType, parameterType, TypeCompareKind.ConsiderEverything) Then diagnostics.Add(ERRID.ERR_AddRemoveParamNotEventType, location) End If End If End If End If End If Return parameters End Function Private Shared ReadOnly s_checkAddRemoveParameterModifierCallback As Binder.CheckParameterModifierDelegate = AddressOf CheckAddRemoveParameterModifier Private Shared ReadOnly s_checkRaiseParameterModifierCallback As Binder.CheckParameterModifierDelegate = AddressOf CheckEventMethodParameterModifier ' applicable to all event methods Private Shared Function CheckEventMethodParameterModifier(container As Symbol, token As SyntaxToken, flag As SourceParameterFlags, diagnostics As BindingDiagnosticBag) As SourceParameterFlags If (flag And SourceParameterFlags.Optional) <> 0 Then Dim location = token.GetLocation() diagnostics.Add(ERRID.ERR_EventMethodOptionalParamIllegal1, location, token.ToString()) flag = flag And (Not SourceParameterFlags.Optional) End If If (flag And SourceParameterFlags.ParamArray) <> 0 Then Dim location = token.GetLocation() diagnostics.Add(ERRID.ERR_EventMethodOptionalParamIllegal1, location, token.ToString()) flag = flag And (Not SourceParameterFlags.ParamArray) End If Return flag End Function ' additional rules for Add and Remove Private Shared Function CheckAddRemoveParameterModifier(container As Symbol, token As SyntaxToken, flag As SourceParameterFlags, diagnostics As BindingDiagnosticBag) As SourceParameterFlags If (flag And SourceParameterFlags.ByRef) <> 0 Then Dim location = token.GetLocation() diagnostics.Add(ERRID.ERR_EventAddRemoveByrefParamIllegal, location, token.ToString()) flag = flag And (Not SourceParameterFlags.ByRef) End If Return CheckEventMethodParameterModifier(container, token, flag, diagnostics) End Function End Class End Namespace