/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Portable/Symbols/Source/SourceCustomEventSymbol.cs
246 строк
12 KB
AlekseyTs
Use proper "unsafe" context while binding type in explicit interface specifier (#80610)
13 окт 2025, 18:30
Не верифицирован
13 окт 2025, 18:30
e21823f
Код
Авторство
О чём код?
// 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. using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols { /// <summary> /// This class represents an event declared in source with explicit accessors /// (i.e. not a field-like event). /// </summary> internal sealed class SourceCustomEventSymbol : SourceEventSymbol { private readonly TypeWithAnnotations _type; private readonly string _name; private readonly SourceEventAccessorSymbol? _addMethod; private readonly SourceEventAccessorSymbol? _removeMethod; private readonly TypeSymbol _explicitInterfaceType; private readonly ImmutableArray<EventSymbol> _explicitInterfaceImplementations; internal SourceCustomEventSymbol(SourceMemberContainerTypeSymbol containingType, Binder binder, EventDeclarationSyntax syntax, BindingDiagnosticBag diagnostics) : base(containingType, syntax, syntax.Modifiers, isFieldLike: false, interfaceSpecifierSyntaxOpt: syntax.ExplicitInterfaceSpecifier, nameTokenSyntax: syntax.Identifier, diagnostics: diagnostics) { ExplicitInterfaceSpecifierSyntax? interfaceSpecifier = syntax.ExplicitInterfaceSpecifier; SyntaxToken nameToken = syntax.Identifier; bool isExplicitInterfaceImplementation = interfaceSpecifier != null; string? aliasQualifierOpt; _name = ExplicitInterfaceHelpers.GetMemberNameAndInterfaceSymbol(binder, syntax.Modifiers, interfaceSpecifier, nameToken.ValueText, diagnostics, out _explicitInterfaceType, out aliasQualifierOpt); _type = BindEventType(binder, syntax.Type, diagnostics); var explicitlyImplementedEvent = this.FindExplicitlyImplementedEvent(_explicitInterfaceType, nameToken.ValueText, interfaceSpecifier, diagnostics); this.FindExplicitlyImplementedMemberVerification(explicitlyImplementedEvent, diagnostics); // The runtime will not treat the accessors of this event as overrides or implementations // of those of another event unless both the signatures and the custom modifiers match. // Hence, in the case of overrides and *explicit* implementations, we need to copy the custom // modifiers that are in the signatures of the overridden/implemented event accessors. // (From source, we know that there can only be one overridden/implemented event, so there // are no conflicts.) This is unnecessary for implicit implementations because, if the custom // modifiers don't match, we'll insert bridge methods for the accessors (explicit implementations // that delegate to the implicit implementations) with the correct custom modifiers // (see SourceMemberContainerTypeSymbol.SynthesizeInterfaceMemberImplementation). // Note: we're checking if the syntax indicates explicit implementation rather, // than if explicitInterfaceType is null because we don't want to look for an // overridden event if this is supposed to be an explicit implementation. if (!isExplicitInterfaceImplementation) { // If this event is an override, we may need to copy custom modifiers from // the overridden event (so that the runtime will recognize it as an override). // We check for this case here, while we can still modify the parameters and // return type without losing the appearance of immutability. if (this.IsOverride) { EventSymbol? overriddenEvent = this.OverriddenEvent; if ((object?)overriddenEvent != null) { CopyEventCustomModifiers(overriddenEvent, ref _type, ContainingAssembly); } } } else if ((object)explicitlyImplementedEvent != null) { CopyEventCustomModifiers(explicitlyImplementedEvent, ref _type, ContainingAssembly); } AccessorDeclarationSyntax? addSyntax = null; AccessorDeclarationSyntax? removeSyntax = null; if (syntax.AccessorList != null) { foreach (AccessorDeclarationSyntax accessor in syntax.AccessorList.Accessors) { bool checkBody = false; switch (accessor.Kind()) { case SyntaxKind.AddAccessorDeclaration: if (addSyntax == null) { addSyntax = accessor; checkBody = true; } else { diagnostics.Add(ErrorCode.ERR_DuplicateAccessor, accessor.Keyword.GetLocation()); } break; case SyntaxKind.RemoveAccessorDeclaration: if (removeSyntax == null) { removeSyntax = accessor; checkBody = true; } else { diagnostics.Add(ErrorCode.ERR_DuplicateAccessor, accessor.Keyword.GetLocation()); } break; case SyntaxKind.GetAccessorDeclaration: case SyntaxKind.SetAccessorDeclaration: case SyntaxKind.InitAccessorDeclaration: diagnostics.Add(ErrorCode.ERR_AddOrRemoveExpected, accessor.Keyword.GetLocation()); break; case SyntaxKind.UnknownAccessorDeclaration: // Don't need to handle UnknownAccessorDeclaration. An error will have // already been produced for it in the parser. break; default: throw ExceptionUtilities.UnexpectedValue(accessor.Kind()); } if (checkBody && !IsAbstract && accessor.Body == null && accessor.ExpressionBody == null && accessor.SemicolonToken.Kind() == SyntaxKind.SemicolonToken) { diagnostics.Add(ErrorCode.ERR_AddRemoveMustHaveBody, accessor.SemicolonToken.GetLocation()); } } if (IsAbstract) { if (!syntax.AccessorList.OpenBraceToken.IsMissing) { diagnostics.Add(ErrorCode.ERR_AbstractEventHasAccessors, syntax.AccessorList.OpenBraceToken.GetLocation(), this); } } else if ((addSyntax == null || removeSyntax == null) && (!syntax.AccessorList.OpenBraceToken.IsMissing || !isExplicitInterfaceImplementation)) { diagnostics.Add(ErrorCode.ERR_EventNeedsBothAccessors, this.GetFirstLocation(), this); } } else if (isExplicitInterfaceImplementation && !IsAbstract) { diagnostics.Add(ErrorCode.ERR_ExplicitEventFieldImpl, this.GetFirstLocation()); } if (isExplicitInterfaceImplementation && IsAbstract && syntax.AccessorList == null) { Debug.Assert(containingType.IsInterface); Binder.CheckFeatureAvailability(syntax, MessageID.IDS_DefaultInterfaceImplementation, diagnostics, this.GetFirstLocation()); if (!ContainingAssembly.RuntimeSupportsDefaultInterfaceImplementation) { diagnostics.Add(ErrorCode.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, this.GetFirstLocation()); } _addMethod = new SynthesizedEventAccessorSymbol(this, isAdder: true, isExpressionBodied: false, explicitlyImplementedEvent, aliasQualifierOpt); _removeMethod = new SynthesizedEventAccessorSymbol(this, isAdder: false, isExpressionBodied: false, explicitlyImplementedEvent, aliasQualifierOpt); } else { _addMethod = CreateAccessorSymbol(DeclaringCompilation, addSyntax, explicitlyImplementedEvent, aliasQualifierOpt, diagnostics); _removeMethod = CreateAccessorSymbol(DeclaringCompilation, removeSyntax, explicitlyImplementedEvent, aliasQualifierOpt, diagnostics); } _explicitInterfaceImplementations = (object?)explicitlyImplementedEvent == null ? ImmutableArray<EventSymbol>.Empty : ImmutableArray.Create<EventSymbol>(explicitlyImplementedEvent); } protected override bool AccessorsHaveImplementation => true; public override TypeWithAnnotations TypeWithAnnotations { get { return _type; } } public override string Name { get { return _name; } } public override MethodSymbol? AddMethod { get { return _addMethod; } } public override MethodSymbol? RemoveMethod { get { return _removeMethod; } } protected override AttributeLocation AllowedAttributeLocations { get { return AttributeLocation.Event; } } private ExplicitInterfaceSpecifierSyntax? ExplicitInterfaceSpecifier { get { return ((EventDeclarationSyntax)this.CSharpSyntaxNode).ExplicitInterfaceSpecifier; } } internal override bool IsExplicitInterfaceImplementation { get { return this.ExplicitInterfaceSpecifier != null; } } public override ImmutableArray<EventSymbol> ExplicitInterfaceImplementations { get { return _explicitInterfaceImplementations; } } internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, BindingDiagnosticBag diagnostics) { base.AfterAddingTypeMembersChecks(conversions, diagnostics); if ((object)_explicitInterfaceType != null) { var explicitInterfaceSpecifier = this.ExplicitInterfaceSpecifier; RoslynDebug.Assert(explicitInterfaceSpecifier != null); _explicitInterfaceType.CheckAllConstraints(DeclaringCompilation, conversions, new SourceLocation(explicitInterfaceSpecifier.Name), diagnostics); } if (!_explicitInterfaceImplementations.IsEmpty) { // Note: we delayed nullable-related checks that could pull on NonNullTypes EventSymbol explicitlyImplementedEvent = _explicitInterfaceImplementations[0]; TypeSymbol.CheckModifierMismatchOnImplementingMember(this.ContainingType, this, explicitlyImplementedEvent, isExplicit: true, diagnostics); } } [return: NotNullIfNotNull(parameterName: nameof(syntaxOpt))] private SourceCustomEventAccessorSymbol? CreateAccessorSymbol(CSharpCompilation compilation, AccessorDeclarationSyntax? syntaxOpt, EventSymbol? explicitlyImplementedEventOpt, string? aliasQualifierOpt, BindingDiagnosticBag diagnostics) { if (syntaxOpt == null) { return null; } return new SourceCustomEventAccessorSymbol(this, syntaxOpt, explicitlyImplementedEventOpt, aliasQualifierOpt, isNullableAnalysisEnabled: compilation.IsNullableAnalysisEnabledIn(syntaxOpt), diagnostics); } } }