| File: Symbols\EventSymbol.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// 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.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols { /// <summary> /// Represents an event. /// </summary> internal abstract partial class EventSymbol : Symbol, IEventSymbolInternal { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Changes to the public interface of this class should remain synchronized with the VB version. // Do not make any changes to the public interface without making the corresponding change // to the VB version. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! internal EventSymbol() { } /// <summary> /// The original definition of this symbol. If this symbol is constructed from another /// symbol by type substitution then OriginalDefinition gets the original symbol as it was defined in /// source or metadata. /// </summary> public new virtual EventSymbol OriginalDefinition { get { return this; } } protected sealed override Symbol OriginalSymbolDefinition { get { return this.OriginalDefinition; } } /// <summary> /// The type of the event along with its annotations. /// </summary> public abstract TypeWithAnnotations TypeWithAnnotations { get; } /// <summary> /// The type of the event. /// </summary> public TypeSymbol Type => TypeWithAnnotations.Type; /// <summary> /// The 'add' accessor of the event. Null only in error scenarios. /// </summary> public abstract MethodSymbol? AddMethod { get; } /// <summary> /// The 'remove' accessor of the event. Null only in error scenarios. /// </summary> public abstract MethodSymbol? RemoveMethod { get; } internal bool HasAssociatedField { get { return (object?)this.AssociatedField != null; } } /// <summary> /// Returns true if this symbol requires an instance reference as the implicit receiver. This is false if the symbol is static. /// </summary> public virtual bool RequiresInstanceReceiver => !IsStatic; /// <summary> /// True if this is a Windows Runtime-style event. /// /// A normal C# event, "event D E", has accessors /// void add_E(D d) /// void remove_E(D d) /// /// A Windows Runtime event, "event D E", has accessors /// EventRegistrationToken add_E(D d) /// void remove_E(EventRegistrationToken t) /// </summary> public abstract bool IsWindowsRuntimeEvent { get; } /// <summary> /// True if the event itself is excluded from code coverage instrumentation. /// True for source events marked with <see cref="AttributeDescription.ExcludeFromCodeCoverageAttribute"/>. /// </summary> internal virtual bool IsDirectlyExcludedFromCodeCoverage { get => false; } /// <summary> /// True if this symbol has a special name (metadata flag SpecialName is set). /// </summary> internal abstract bool HasSpecialName { get; } /// <summary> /// Gets the attributes on event's associated field, if any. /// Returns an empty <see cref="ImmutableArray<AttributeData>"/> if /// there are no attributes. /// </summary> /// <remarks> /// This publicly exposes the attributes of the internal backing field. /// </remarks> public ImmutableArray<CSharpAttributeData> GetFieldAttributes() { return (object?)this.AssociatedField == null ? ImmutableArray<CSharpAttributeData>.Empty : this.AssociatedField.GetAttributes(); } internal virtual FieldSymbol? AssociatedField { get { return null; } } /// <summary> /// Returns the overridden event, or null. /// </summary> public EventSymbol? OverriddenEvent { get { if (this.IsOverride) { if (IsDefinition) { return (EventSymbol)OverriddenOrHiddenMembers.GetOverriddenMember(); } return (EventSymbol)OverriddenOrHiddenMembersResult.GetOverriddenMember(this, OriginalDefinition.OverriddenEvent); } return null; } } internal virtual OverriddenOrHiddenMembersResult OverriddenOrHiddenMembers { get { return this.MakeOverriddenOrHiddenMembers(); } } internal bool HidesBaseEventsByName { get { MethodSymbol? accessor = AddMethod ?? RemoveMethod; return (object?)accessor != null && accessor.HidesBaseMethodsByName; } } internal EventSymbol GetLeastOverriddenEvent(NamedTypeSymbol? accessingTypeOpt) { accessingTypeOpt = accessingTypeOpt?.OriginalDefinition; EventSymbol e = this; while (e.IsOverride && !e.HidesBaseEventsByName) { // NOTE: We might not be able to access the overridden event. For example, // // .assembly A // { // InternalsVisibleTo("B") // public class A { internal virtual event Action E { add; remove; } } // } // // .assembly B // { // InternalsVisibleTo("C") // public class B : A { internal override event Action E { add; remove; } } // } // // .assembly C // { // public class C : B { ... new B().E += null ... } // A.E is not accessible from here // } // // See InternalsVisibleToAndStrongNameTests: IvtVirtualCall1, IvtVirtualCall2, IvtVirtual_ParamsAndDynamic. EventSymbol? overridden = e.OverriddenEvent; var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded; if ((object?)overridden == null || (accessingTypeOpt is { } && !AccessCheck.IsSymbolAccessible(overridden, accessingTypeOpt, ref discardedUseSiteInfo))) { break; } e = overridden; } return e; } /// <summary> /// Source: Was the member name qualified with a type name? /// Metadata: Is the member an explicit implementation? /// </summary> /// <remarks> /// Will not always agree with ExplicitInterfaceImplementations.Any() /// (e.g. if binding of the type part of the name fails). /// </remarks> internal virtual bool IsExplicitInterfaceImplementation { get { return ExplicitInterfaceImplementations.Any(); } } /// <summary> /// Returns interface events explicitly implemented by this event. /// </summary> /// <remarks> /// Events imported from metadata can explicitly implement more than one event. /// </remarks> public abstract ImmutableArray<EventSymbol> ExplicitInterfaceImplementations { get; } internal virtual EventSymbol? PartialImplementationPart => null; internal virtual EventSymbol? PartialDefinitionPart => null; internal virtual bool IsPartialDefinition => false; /// <summary> /// Gets the kind of this symbol. /// </summary> public sealed override SymbolKind Kind { get { return SymbolKind.Event; } } /// <summary> /// Implements visitor pattern. /// </summary> internal override TResult Accept<TArgument, TResult>(CSharpSymbolVisitor<TArgument, TResult> visitor, TArgument argument) { return visitor.VisitEvent(this, argument); } public override void Accept(CSharpSymbolVisitor visitor) { visitor.VisitEvent(this); } public override TResult Accept<TResult>(CSharpSymbolVisitor<TResult> visitor) { return visitor.VisitEvent(this); } internal EventSymbol AsMember(NamedTypeSymbol newOwner) { Debug.Assert(this.IsDefinition); Debug.Assert(ReferenceEquals(newOwner.OriginalDefinition, this.ContainingSymbol.OriginalDefinition)); Debug.Assert(newOwner.IsDefinition || newOwner is SubstitutedNamedTypeSymbol); return newOwner.IsDefinition ? this : new SubstitutedEventSymbol((newOwner as SubstitutedNamedTypeSymbol)!, this); } internal abstract bool MustCallMethodsDirectly { get; } #region Use-Site Diagnostics internal override UseSiteInfo<AssemblySymbol> GetUseSiteInfo() { if (this.IsDefinition) { return new UseSiteInfo<AssemblySymbol>(PrimaryDependency); } return this.OriginalDefinition.GetUseSiteInfo(); } internal bool CalculateUseSiteDiagnostic(ref UseSiteInfo<AssemblySymbol> result) { Debug.Assert(this.IsDefinition); // Check event type. if (DeriveUseSiteInfoFromType(ref result, this.TypeWithAnnotations, AllowedRequiredModifierType.None)) { return true; } if (this.ContainingModule.HasUnifiedReferences) { // If the member is in an assembly with unified references, // we check if its definition depends on a type from a unified reference. HashSet<TypeSymbol>? unificationCheckedTypes = null; DiagnosticInfo? diagnosticInfo = result.DiagnosticInfo; if (this.TypeWithAnnotations.GetUnificationUseSiteDiagnosticRecursive(ref diagnosticInfo, this, ref unificationCheckedTypes)) { result = result.AdjustDiagnosticInfo(diagnosticInfo); return true; } result = result.AdjustDiagnosticInfo(diagnosticInfo); } return false; } protected sealed override bool IsHighestPriorityUseSiteErrorCode(int code) => code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BindToBogus; public sealed override bool HasUnsupportedMetadata { get { DiagnosticInfo? info = GetUseSiteInfo().DiagnosticInfo; return (object?)info != null && info.Code is (int)ErrorCode.ERR_BindToBogus or (int)ErrorCode.ERR_UnsupportedCompilerFeature; } } #endregion protected sealed override ISymbol CreateISymbol() { return new PublicModel.EventSymbol(this); } #region Equality public override bool Equals(Symbol? obj, TypeCompareKind compareKind) { EventSymbol? other = obj as EventSymbol; if (ReferenceEquals(null, other)) { return false; } if (ReferenceEquals(this, other)) { return true; } // This checks if the events have the same definition and the type parameters on the containing types have been // substituted in the same way. return TypeSymbol.Equals(this.ContainingType, other.ContainingType, compareKind) && ReferenceEquals(this.OriginalDefinition, other.OriginalDefinition); } public override int GetHashCode() { int hash = 1; hash = Hash.Combine(this.ContainingType, hash); hash = Hash.Combine(this.Name, hash); return hash; } #endregion Equality } }