|
// 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;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
/// <summary>
/// This class represents an event declared in source. It may be either
/// field-like (see <see cref="SourceFieldLikeEventSymbol"/>) or property-like (see
/// <see cref="SourceCustomEventSymbol"/>).
/// </summary>
internal abstract class SourceEventSymbol : EventSymbol, IAttributeTargetSymbol
{
private readonly Location _location;
private readonly SyntaxReference _syntaxRef;
private readonly DeclarationModifiers _modifiers;
internal readonly SourceMemberContainerTypeSymbol containingType;
private SymbolCompletionState _state;
private CustomAttributesBag<CSharpAttributeData>? _lazyCustomAttributesBag;
private string? _lazyDocComment;
private string? _lazyExpandedDocComment;
private OverriddenOrHiddenMembersResult? _lazyOverriddenOrHiddenMembers;
private ThreeState _lazyIsWindowsRuntimeEvent = ThreeState.Unknown;
// TODO: CLSCompliantAttribute
internal SourceEventSymbol(
SourceMemberContainerTypeSymbol containingType,
CSharpSyntaxNode syntax,
SyntaxTokenList modifiers,
bool isFieldLike,
ExplicitInterfaceSpecifierSyntax? interfaceSpecifierSyntaxOpt,
SyntaxToken nameTokenSyntax,
BindingDiagnosticBag diagnostics)
{
_location = nameTokenSyntax.GetLocation();
this.containingType = containingType;
_syntaxRef = syntax.GetReference();
var isExplicitInterfaceImplementation = interfaceSpecifierSyntaxOpt != null;
bool modifierErrors;
_modifiers = MakeModifiers(modifiers, isExplicitInterfaceImplementation, isFieldLike, _location, diagnostics, out modifierErrors);
this.CheckAccessibility(_location, diagnostics, isExplicitInterfaceImplementation);
}
public Location Location
=> _location;
internal sealed override bool RequiresCompletion
{
get { return true; }
}
internal sealed override bool HasComplete(CompletionPart part)
{
return _state.HasComplete(part);
}
internal override void ForceComplete(SourceLocation? locationOpt, Predicate<Symbol>? filter, CancellationToken cancellationToken)
{
if (filter?.Invoke(this) == false)
{
return;
}
_state.DefaultForceComplete(this, cancellationToken);
}
public abstract override string Name { get; }
public abstract override MethodSymbol? AddMethod { get; }
public abstract override MethodSymbol? RemoveMethod { get; }
public abstract override ImmutableArray<EventSymbol> ExplicitInterfaceImplementations { get; }
public abstract override TypeWithAnnotations TypeWithAnnotations { get; }
public sealed override Symbol ContainingSymbol
{
get
{
return containingType;
}
}
public override NamedTypeSymbol ContainingType
{
get
{
return this.containingType;
}
}
internal override LexicalSortKey GetLexicalSortKey()
{
return new LexicalSortKey(_location, this.DeclaringCompilation);
}
public sealed override ImmutableArray<Location> Locations
{
get
{
return ImmutableArray.Create(_location);
}
}
public override Location TryGetFirstLocation()
=> _location;
public sealed override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
{
get
{
return ImmutableArray.Create<SyntaxReference>(_syntaxRef);
}
}
/// <summary>
/// Gets the syntax list of custom attributes applied on the event symbol.
/// </summary>
internal SyntaxList<AttributeListSyntax> AttributeDeclarationSyntaxList
{
get
{
if (this.containingType.AnyMemberHasAttributes)
{
var syntax = this.CSharpSyntaxNode;
if (syntax != null)
{
switch (syntax.Kind())
{
case SyntaxKind.EventDeclaration:
return ((EventDeclarationSyntax)syntax).AttributeLists;
case SyntaxKind.VariableDeclarator:
Debug.Assert(syntax.Parent!.Parent is object);
return ((EventFieldDeclarationSyntax)syntax.Parent.Parent).AttributeLists;
default:
throw ExceptionUtilities.UnexpectedValue(syntax.Kind());
}
}
}
return default;
}
}
IAttributeTargetSymbol IAttributeTargetSymbol.AttributesOwner
{
get { return this; }
}
AttributeLocation IAttributeTargetSymbol.DefaultAttributeLocation
{
get { return AttributeLocation.Event; }
}
AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations
{
get
{
return this.AllowedAttributeLocations;
}
}
protected abstract AttributeLocation AllowedAttributeLocations
{
get;
}
/// <summary>
/// Returns a bag of applied custom attributes and data decoded from well-known attributes. Returns null if there are no attributes applied on the symbol.
/// </summary>
/// <remarks>
/// Forces binding and decoding of attributes.
/// </remarks>
private CustomAttributesBag<CSharpAttributeData> GetAttributesBag()
{
if ((_lazyCustomAttributesBag == null || !_lazyCustomAttributesBag.IsSealed) &&
LoadAndValidateAttributes(OneOrMany.Create(this.AttributeDeclarationSyntaxList), ref _lazyCustomAttributesBag))
{
DeclaringCompilation.SymbolDeclaredEvent(this);
var wasCompletedThisThread = _state.NotePartComplete(CompletionPart.Attributes);
Debug.Assert(wasCompletedThisThread);
}
RoslynDebug.AssertNotNull(_lazyCustomAttributesBag);
return _lazyCustomAttributesBag;
}
/// <summary>
/// Gets the attributes applied on this symbol.
/// Returns an empty array if there are no attributes.
/// </summary>
/// <remarks>
/// NOTE: This method should always be kept as a sealed override.
/// If you want to override attribute binding logic for a sub-class, then override <see cref="GetAttributesBag"/> method.
/// </remarks>
public sealed override ImmutableArray<CSharpAttributeData> GetAttributes()
{
return this.GetAttributesBag().Attributes;
}
/// <summary>
/// Returns data decoded from well-known attributes applied to the symbol or null if there are no applied attributes.
/// </summary>
/// <remarks>
/// Forces binding and decoding of attributes.
/// </remarks>
protected CommonEventWellKnownAttributeData GetDecodedWellKnownAttributeData()
{
var attributesBag = _lazyCustomAttributesBag;
if (attributesBag == null || !attributesBag.IsDecodedWellKnownAttributeDataComputed)
{
attributesBag = this.GetAttributesBag();
}
return (CommonEventWellKnownAttributeData)attributesBag.DecodedWellKnownAttributeData;
}
/// <summary>
/// Returns data decoded from special early bound well-known attributes applied to the symbol or null if there are no applied attributes.
/// </summary>
/// <remarks>
/// Forces binding and decoding of attributes.
/// </remarks>
internal CommonEventEarlyWellKnownAttributeData GetEarlyDecodedWellKnownAttributeData()
{
var attributesBag = _lazyCustomAttributesBag;
if (attributesBag == null || !attributesBag.IsEarlyDecodedWellKnownAttributeDataComputed)
{
attributesBag = this.GetAttributesBag();
}
return (CommonEventEarlyWellKnownAttributeData)attributesBag.EarlyDecodedWellKnownAttributeData;
}
internal override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAttribute(ref EarlyDecodeWellKnownAttributeArguments<EarlyWellKnownAttributeBinder, NamedTypeSymbol, AttributeSyntax, AttributeLocation> arguments)
{
CSharpAttributeData? attributeData;
BoundAttribute? boundAttribute;
ObsoleteAttributeData? obsoleteData;
if (EarlyDecodeDeprecatedOrExperimentalOrObsoleteAttribute(ref arguments, out attributeData, out boundAttribute, out obsoleteData))
{
if (obsoleteData != null)
{
arguments.GetOrCreateData<CommonEventEarlyWellKnownAttributeData>().ObsoleteAttributeData = obsoleteData;
}
return (attributeData, boundAttribute);
}
return base.EarlyDecodeWellKnownAttribute(ref arguments);
}
/// <summary>
/// Returns data decoded from Obsolete attribute or null if there is no Obsolete attribute.
/// This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet.
/// </summary>
internal override ObsoleteAttributeData? ObsoleteAttributeData
{
get
{
if (!this.containingType.AnyMemberHasAttributes)
{
return null;
}
var lazyCustomAttributesBag = _lazyCustomAttributesBag;
if (lazyCustomAttributesBag != null && lazyCustomAttributesBag.IsEarlyDecodedWellKnownAttributeDataComputed)
{
var data = (CommonEventEarlyWellKnownAttributeData)lazyCustomAttributesBag.EarlyDecodedWellKnownAttributeData;
return data != null ? data.ObsoleteAttributeData : null;
}
return ObsoleteAttributeData.Uninitialized;
}
}
protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments)
{
var attribute = arguments.Attribute;
Debug.Assert(!attribute.HasErrors);
Debug.Assert(arguments.SymbolPart == AttributeLocation.None);
var diagnostics = (BindingDiagnosticBag)arguments.Diagnostics;
if (attribute.IsTargetAttribute(AttributeDescription.SpecialNameAttribute))
{
arguments.GetOrCreateData<CommonEventWellKnownAttributeData>().HasSpecialNameAttribute = true;
}
else if (ReportExplicitUseOfReservedAttributes(in arguments, ReservedAttributes.NullableAttribute | ReservedAttributes.NativeIntegerAttribute | ReservedAttributes.TupleElementNamesAttribute))
{
}
else if (attribute.IsTargetAttribute(AttributeDescription.ExcludeFromCodeCoverageAttribute))
{
arguments.GetOrCreateData<CommonEventWellKnownAttributeData>().HasExcludeFromCodeCoverageAttribute = true;
}
else if (attribute.IsTargetAttribute(AttributeDescription.SkipLocalsInitAttribute))
{
CSharpAttributeData.DecodeSkipLocalsInitAttribute<CommonEventWellKnownAttributeData>(DeclaringCompilation, ref arguments);
}
else if (attribute.IsTargetAttribute(AttributeDescription.UnscopedRefAttribute))
{
diagnostics.Add(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, arguments.AttributeSyntaxOpt!.Location);
}
}
internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder<SynthesizedAttributeData>? attributes)
{
base.AddSynthesizedAttributes(moduleBuilder, ref attributes);
var compilation = this.DeclaringCompilation;
var type = this.TypeWithAnnotations;
if (type.Type.ContainsDynamic())
{
AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(type.Type, type.CustomModifiers.Length));
}
if (compilation.ShouldEmitNativeIntegerAttributes(type.Type))
{
AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeNativeIntegerAttribute(this, type.Type));
}
if (type.Type.ContainsTupleNames())
{
AddSynthesizedAttribute(ref attributes,
DeclaringCompilation.SynthesizeTupleNamesAttribute(type.Type));
}
if (compilation.ShouldEmitNullableAttributes(this))
{
AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeNullableAttributeIfNecessary(this, containingType.GetNullableContextValue(), type));
}
}
internal sealed override bool IsDirectlyExcludedFromCodeCoverage =>
GetDecodedWellKnownAttributeData()?.HasExcludeFromCodeCoverageAttribute == true;
internal sealed override bool HasSpecialName
{
get
{
var data = GetDecodedWellKnownAttributeData();
return data != null && data.HasSpecialNameAttribute;
}
}
public bool HasSkipLocalsInitAttribute
=> GetDecodedWellKnownAttributeData()?.HasSkipLocalsInitAttribute == true;
public sealed override bool IsAbstract
{
get { return (_modifiers & DeclarationModifiers.Abstract) != 0; }
}
public sealed override bool IsExtern
{
get { return (_modifiers & DeclarationModifiers.Extern) != 0; }
}
public sealed override bool IsStatic
{
get { return (_modifiers & DeclarationModifiers.Static) != 0; }
}
public sealed override bool IsOverride
{
get { return (_modifiers & DeclarationModifiers.Override) != 0; }
}
public sealed override bool IsSealed
{
get { return (_modifiers & DeclarationModifiers.Sealed) != 0; }
}
public sealed override bool IsVirtual
{
get { return (_modifiers & DeclarationModifiers.Virtual) != 0; }
}
internal bool IsReadOnly
{
get { return (_modifiers & DeclarationModifiers.ReadOnly) != 0; }
}
public sealed override Accessibility DeclaredAccessibility
{
get { return ModifierUtils.EffectiveAccessibility(_modifiers); }
}
internal sealed override bool MustCallMethodsDirectly
{
get { return false; } // always false for source events
}
internal SyntaxReference SyntaxReference
{
get { return _syntaxRef; }
}
internal CSharpSyntaxNode CSharpSyntaxNode
{
get { return (CSharpSyntaxNode)_syntaxRef.GetSyntax(); }
}
internal SyntaxTree SyntaxTree
{
get { return _syntaxRef.SyntaxTree; }
}
internal bool IsNew
{
get { return (_modifiers & DeclarationModifiers.New) != 0; }
}
internal DeclarationModifiers Modifiers
{
get { return _modifiers; }
}
private void CheckAccessibility(Location location, BindingDiagnosticBag diagnostics, bool isExplicitInterfaceImplementation)
{
ModifierUtils.CheckAccessibility(_modifiers, this, isExplicitInterfaceImplementation, diagnostics, location);
}
private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, bool explicitInterfaceImplementation,
bool isFieldLike, Location location,
BindingDiagnosticBag diagnostics, out bool modifierErrors)
{
bool isInterface = this.ContainingType.IsInterface;
var defaultAccess = isInterface && !explicitInterfaceImplementation ? DeclarationModifiers.Public : DeclarationModifiers.Private;
var defaultInterfaceImplementationModifiers = DeclarationModifiers.None;
// Check that the set of modifiers is allowed
var allowedModifiers = DeclarationModifiers.Unsafe;
if (!explicitInterfaceImplementation)
{
allowedModifiers |= DeclarationModifiers.New |
DeclarationModifiers.Sealed |
DeclarationModifiers.Abstract |
DeclarationModifiers.Static |
DeclarationModifiers.Virtual |
DeclarationModifiers.AccessibilityMask;
if (!isInterface)
{
allowedModifiers |= DeclarationModifiers.Override;
}
else
{
// This is needed to make sure we can detect 'public' modifier specified explicitly and
// check it against language version below.
defaultAccess = DeclarationModifiers.None;
allowedModifiers |= DeclarationModifiers.Extern;
defaultInterfaceImplementationModifiers |= DeclarationModifiers.Sealed |
DeclarationModifiers.Abstract |
DeclarationModifiers.Static |
DeclarationModifiers.Virtual |
DeclarationModifiers.Extern |
DeclarationModifiers.AccessibilityMask;
}
}
else
{
Debug.Assert(explicitInterfaceImplementation);
if (isInterface)
{
allowedModifiers |= DeclarationModifiers.Abstract;
}
allowedModifiers |= DeclarationModifiers.Static;
}
if (this.ContainingType.IsStructType())
{
allowedModifiers |= DeclarationModifiers.ReadOnly;
}
if (!isInterface)
{
allowedModifiers |= DeclarationModifiers.Extern;
}
var mods = ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: false, isForInterfaceMember: isInterface,
modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors);
ModifierUtils.CheckFeatureAvailabilityForStaticAbstractMembersInInterfacesIfNeeded(mods, explicitInterfaceImplementation, location, diagnostics);
this.CheckUnsafeModifier(mods, diagnostics);
ModifierUtils.ReportDefaultInterfaceImplementationModifiers(!isFieldLike, mods,
defaultInterfaceImplementationModifiers,
location, diagnostics);
// Let's overwrite modifiers for interface events with what they are supposed to be.
// Proper errors must have been reported by now.
if (isInterface)
{
mods = ModifierUtils.AdjustModifiersForAnInterfaceMember(mods, !isFieldLike, explicitInterfaceImplementation);
}
return mods;
}
protected void CheckModifiersAndType(BindingDiagnosticBag diagnostics)
{
Debug.Assert(!IsStatic || !IsOverride); // Otherwise should have been reported and cleared earlier.
Debug.Assert(!IsStatic || ContainingType.IsInterface || (!IsAbstract && !IsVirtual)); // Otherwise should have been reported and cleared earlier.
Location location = this.GetFirstLocation();
var useSiteInfo = new CompoundUseSiteInfo<AssemblySymbol>(diagnostics, ContainingAssembly);
bool isExplicitInterfaceImplementationInInterface = ContainingType.IsInterface && IsExplicitInterfaceImplementation;
if (this.DeclaredAccessibility == Accessibility.Private && (IsVirtual || (IsAbstract && !isExplicitInterfaceImplementationInInterface) || IsOverride))
{
diagnostics.Add(ErrorCode.ERR_VirtualPrivate, location, this);
}
else if (IsReadOnly && IsStatic)
{
// Static member '{0}' cannot be marked 'readonly'.
diagnostics.Add(ErrorCode.ERR_StaticMemberCantBeReadOnly, location, this);
}
else if (IsReadOnly && HasAssociatedField)
{
// Field-like event '{0}' cannot be 'readonly'.
diagnostics.Add(ErrorCode.ERR_FieldLikeEventCantBeReadOnly, location, this);
}
else if (IsOverride && (IsNew || IsVirtual))
{
// A member '{0}' marked as override cannot be marked as new or virtual
diagnostics.Add(ErrorCode.ERR_OverrideNotNew, location, this);
}
else if (IsSealed && !IsOverride && !(isExplicitInterfaceImplementationInInterface && IsAbstract))
{
// '{0}' cannot be sealed because it is not an override
diagnostics.Add(ErrorCode.ERR_SealedNonOverride, location, this);
}
else if (IsAbstract && ContainingType.TypeKind == TypeKind.Struct)
{
// The modifier '{0}' is not valid for this item
diagnostics.Add(ErrorCode.ERR_BadMemberFlag, location, SyntaxFacts.GetText(SyntaxKind.AbstractKeyword));
}
else if (IsVirtual && ContainingType.TypeKind == TypeKind.Struct)
{
// The modifier '{0}' is not valid for this item
diagnostics.Add(ErrorCode.ERR_BadMemberFlag, location, SyntaxFacts.GetText(SyntaxKind.VirtualKeyword));
}
else if (IsAbstract && IsExtern)
{
diagnostics.Add(ErrorCode.ERR_AbstractAndExtern, location, this);
}
else if (IsAbstract && IsSealed && !isExplicitInterfaceImplementationInInterface)
{
diagnostics.Add(ErrorCode.ERR_AbstractAndSealed, location, this);
}
else if (IsAbstract && IsVirtual)
{
diagnostics.Add(ErrorCode.ERR_AbstractNotVirtual, location, this.Kind.Localize(), this);
}
else if (ContainingType.IsSealed && this.DeclaredAccessibility.HasProtected() && !this.IsOverride)
{
diagnostics.Add(AccessCheck.GetProtectedMemberInSealedTypeError(ContainingType), location, this);
}
else if (ContainingType.IsStatic && !IsStatic)
{
diagnostics.Add(ErrorCode.ERR_InstanceMemberInStaticClass, location, Name);
}
else if (this.Type.IsVoidType())
{
// Diagnostic reported by parser.
}
else if (!this.IsNoMoreVisibleThan(this.Type, ref useSiteInfo) && (CSharpSyntaxNode as EventDeclarationSyntax)?.ExplicitInterfaceSpecifier == null)
{
// Dev10 reports different errors for field-like events (ERR_BadVisFieldType) and custom events (ERR_BadVisPropertyType).
// Both seem odd, so add a new one.
diagnostics.Add(ErrorCode.ERR_BadVisEventType, location, this, this.Type);
}
else if (!this.Type.IsDelegateType() && !this.Type.IsErrorType())
{
// Suppressed for error types.
diagnostics.Add(ErrorCode.ERR_EventNotDelegate, location, this);
}
else if (IsAbstract && !ContainingType.IsAbstract && (ContainingType.TypeKind == TypeKind.Class || ContainingType.TypeKind == TypeKind.Submission))
{
// '{0}' is abstract but it is contained in non-abstract type '{1}'
diagnostics.Add(ErrorCode.ERR_AbstractInConcreteClass, location, this, ContainingType);
}
else if (IsVirtual && ContainingType.IsSealed)
{
// '{0}' is a new virtual member in sealed type '{1}'
diagnostics.Add(ErrorCode.ERR_NewVirtualInSealed, location, this, ContainingType);
}
diagnostics.Add(location, useSiteInfo);
}
public override string GetDocumentationCommentXml(CultureInfo? preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default)
{
ref var lazyDocComment = ref expandIncludes ? ref _lazyExpandedDocComment : ref _lazyDocComment;
return SourceDocumentationCommentUtils.GetAndCacheDocumentationComment(this, expandIncludes, ref lazyDocComment);
}
protected static void CopyEventCustomModifiers(EventSymbol eventWithCustomModifiers, ref TypeWithAnnotations type, AssemblySymbol containingAssembly)
{
RoslynDebug.Assert((object)eventWithCustomModifiers != null);
TypeSymbol overriddenEventType = eventWithCustomModifiers.Type;
// We do an extra check before copying the type to handle the case where the overriding
// event (incorrectly) has a different type than the overridden event. In such cases,
// we want to retain the original (incorrect) type to avoid hiding the type given in source.
if (type.Type.Equals(overriddenEventType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes | TypeCompareKind.IgnoreDynamic))
{
type = type.WithTypeAndModifiers(CustomModifierUtils.CopyTypeCustomModifiers(overriddenEventType, type.Type, containingAssembly),
eventWithCustomModifiers.TypeWithAnnotations.CustomModifiers);
}
}
internal override OverriddenOrHiddenMembersResult OverriddenOrHiddenMembers
{
get
{
if (_lazyOverriddenOrHiddenMembers == null)
{
Interlocked.CompareExchange(ref _lazyOverriddenOrHiddenMembers, this.MakeOverriddenOrHiddenMembers(), null);
}
return _lazyOverriddenOrHiddenMembers;
}
}
public sealed override bool IsWindowsRuntimeEvent
{
get
{
if (!_lazyIsWindowsRuntimeEvent.HasValue())
{
// This would be a CompareExchange if there was an overload for ThreeState.
_lazyIsWindowsRuntimeEvent = ComputeIsWindowsRuntimeEvent().ToThreeState();
}
Debug.Assert(_lazyIsWindowsRuntimeEvent.HasValue());
return _lazyIsWindowsRuntimeEvent.Value();
}
}
private bool ComputeIsWindowsRuntimeEvent()
{
// If you explicitly implement an event, then you're a WinRT event if and only if it's a WinRT event.
ImmutableArray<EventSymbol> explicitInterfaceImplementations = this.ExplicitInterfaceImplementations;
if (!explicitInterfaceImplementations.IsEmpty)
{
// If there could be more than one, we'd have to worry about conflicts, but that's impossible for source events.
Debug.Assert(explicitInterfaceImplementations.Length == 1);
// Don't have to worry about conflicting with the override rule, since explicit impls are never overrides (in source).
Debug.Assert((object?)this.OverriddenEvent == null);
return explicitInterfaceImplementations[0].IsWindowsRuntimeEvent;
}
// Interface events don't override or implicitly implement other events, so they only
// depend on the output kind at this point.
if (this.containingType.IsInterfaceType())
{
return this.IsCompilationOutputWinMdObj();
}
// If you override an event, then you're a WinRT event if and only if it's a WinRT event.
EventSymbol? overriddenEvent = this.OverriddenEvent;
if ((object?)overriddenEvent != null)
{
return overriddenEvent.IsWindowsRuntimeEvent;
}
// If you implicitly implement one or more interface events (for yourself, not for a derived type),
// then you're a WinRT event if and only if at least one is a WinRT event.
//
// NOTE: it's possible that we returned false above even though we would have returned true
// below. Whenever this occurs, we need to report a diagnostic (because an event can't be
// both WinRT and non-WinRT), but we'll do that when we're checking interface implementations
// (see SourceMemberContainerTypeSymbol.ComputeInterfaceImplementations).
bool sawImplicitImplementation = false;
foreach (NamedTypeSymbol @interface in this.containingType.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics.Keys)
{
foreach (Symbol interfaceMember in @interface.GetMembers(this.Name))
{
if (interfaceMember.Kind == SymbolKind.Event && //quick check (necessary, not sufficient)
interfaceMember.IsImplementableInterfaceMember() &&
// We are passing ignoreImplementationInInterfacesIfResultIsNotReady: true to avoid a cycle. If false is passed, FindImplementationForInterfaceMemberInNonInterface
// will look how event accessors are implemented and we end up here again since we will need to know their signature for that.
this == this.containingType.FindImplementationForInterfaceMemberInNonInterface(interfaceMember, ignoreImplementationInInterfacesIfResultIsNotReady: true)) //slow check (necessary and sufficient)
{
sawImplicitImplementation = true;
if (((EventSymbol)interfaceMember).IsWindowsRuntimeEvent)
{
return true;
}
}
}
}
// If you implement one or more interface events and none of them are WinRT events, then you
// are not a WinRT event.
if (sawImplicitImplementation)
{
return false;
}
// If you're not constrained by your relationships with other members, then you're a WinRT event
// if and only if this compilation will produce a ".winmdobj" file.
return this.IsCompilationOutputWinMdObj();
}
internal static string GetAccessorName(string eventName, bool isAdder)
{
return (isAdder ? "add_" : "remove_") + eventName;
}
protected TypeWithAnnotations BindEventType(Binder binder, TypeSyntax typeSyntax, BindingDiagnosticBag diagnostics)
{
// NOTE: no point in reporting unsafe errors in the return type - anything unsafe will either
// fail to be a delegate or will be (invalidly) passed as a type argument.
// Prevent constraint checking.
binder = binder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks | BinderFlags.SuppressUnsafeDiagnostics, this);
return binder.BindType(typeSyntax, diagnostics);
}
internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, BindingDiagnosticBag diagnostics)
{
var compilation = DeclaringCompilation;
var location = this.GetFirstLocation();
this.CheckModifiersAndType(diagnostics);
this.Type.CheckAllConstraints(compilation, conversions, location, diagnostics);
if (compilation.ShouldEmitNativeIntegerAttributes(Type))
{
compilation.EnsureNativeIntegerAttributeExists(diagnostics, location, modifyCompilation: true);
}
if (compilation.ShouldEmitNullableAttributes(this) &&
TypeWithAnnotations.NeedsNullableAttribute())
{
compilation.EnsureNullableAttributeExists(diagnostics, location, modifyCompilation: true);
}
EventSymbol? explicitlyImplementedEvent = ExplicitInterfaceImplementations.FirstOrDefault();
if (explicitlyImplementedEvent is object)
{
CheckExplicitImplementationAccessor(AddMethod, explicitlyImplementedEvent.AddMethod, explicitlyImplementedEvent, diagnostics);
CheckExplicitImplementationAccessor(RemoveMethod, explicitlyImplementedEvent.RemoveMethod, explicitlyImplementedEvent, diagnostics);
}
}
private void CheckExplicitImplementationAccessor(MethodSymbol? thisAccessor, MethodSymbol? otherAccessor, EventSymbol explicitlyImplementedEvent, BindingDiagnosticBag diagnostics)
{
if (!otherAccessor.IsImplementable() && thisAccessor is object)
{
diagnostics.Add(ErrorCode.ERR_ExplicitPropertyAddingAccessor, thisAccessor.GetFirstLocation(), thisAccessor, explicitlyImplementedEvent);
}
}
}
}
|