File: Symbols\Synthesized\SynthesizedEventAccessorSymbol.cs
Web Access
Project: src\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.
 
#nullable disable
 
using System.Diagnostics;
using System.Reflection;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    /// <summary>
    /// Event accessor that has been synthesized for a field-like event declared in source,
    /// or for an event re-abstraction in an interface.
    /// </summary>
    /// <remarks>
    /// Associated with <see cref="SourceFieldLikeEventSymbol"/> and <see cref="SourceCustomEventSymbol"/>.
    /// </remarks>
    internal sealed class SynthesizedEventAccessorSymbol : SourceEventAccessorSymbol
    {
        // Since we don't have a syntax reference, we'll have to use another object for locking.
        private readonly object _methodChecksLockObject = new object();
 
        internal SynthesizedEventAccessorSymbol(SourceEventSymbol @event, bool isAdder, bool isExpressionBodied, EventSymbol explicitlyImplementedEventOpt = null, string aliasQualifierOpt = null)
            : base(@event, null, @event.Location, explicitlyImplementedEventOpt, aliasQualifierOpt, isAdder, isIterator: false, isNullableAnalysisEnabled: false, isExpressionBodied: isExpressionBodied)
        {
            Debug.Assert(IsAbstract || IsExtern || IsFieldLikeEventAccessor());
        }
 
        private bool IsFieldLikeEventAccessor()
        {
            return AssociatedEvent.HasAssociatedField;
        }
 
        public override bool IsImplicitlyDeclared
        {
            get { return true; }
        }
 
        internal override bool GenerateDebugInfo
        {
            get { return false; }
        }
 
        protected override SourceMemberMethodSymbol BoundAttributesSource
        {
            get
            {
                return this.MethodKind == MethodKind.EventAdd
                    ? (SourceMemberMethodSymbol)this.AssociatedEvent.RemoveMethod
                    : null;
            }
        }
 
        protected override IAttributeTargetSymbol AttributeOwner
        {
            get
            {
                // attributes for this accessor are specified on the associated event:
                return AssociatedEvent;
            }
        }
 
        internal override OneOrMany<SyntaxList<AttributeListSyntax>> GetAttributeDeclarations()
        {
            return OneOrMany.Create(this.AssociatedEvent.AttributeDeclarationSyntaxList);
        }
 
        internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder<SynthesizedAttributeData> attributes)
        {
            base.AddSynthesizedAttributes(moduleBuilder, ref attributes);
 
            var compilation = this.DeclaringCompilation;
            AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor));
        }
 
        protected override object MethodChecksLockObject
        {
            get { return _methodChecksLockObject; }
        }
 
        internal override MethodImplAttributes ImplementationAttributes
        {
            get
            {
                MethodImplAttributes result = base.ImplementationAttributes;
 
                if (!IsAbstract && !AssociatedEvent.IsWindowsRuntimeEvent && !ContainingType.IsStructType() &&
                    (object)DeclaringCompilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T) == null)
                {
                    // Under these conditions, this method needs to be synchronized.
                    result |= MethodImplAttributes.Synchronized;
                }
 
                return result;
            }
        }
 
        internal override ExecutableCodeBinder TryGetBodyBinder(BinderFactory binderFactoryOpt = null, bool ignoreAccessibility = false)
        {
            return TryGetBodyBinderFromSyntax(binderFactoryOpt, ignoreAccessibility);
        }
 
        internal override bool SynthesizesLoweredBoundBody
        {
            get
            {
                Debug.Assert(TryGetBodyBinder() is null);
 
                if (IsFieldLikeEventAccessor())
                {
                    return true;
                }
 
                return base.SynthesizesLoweredBoundBody;
            }
        }
 
        internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics)
        {
            if (IsFieldLikeEventAccessor())
            {
                SourceEventSymbol fieldLikeEvent = AssociatedEvent;
                if (fieldLikeEvent.Type.IsDelegateType())
                {
                    BoundBlock body = CSharp.MethodBodySynthesizer.ConstructFieldLikeEventAccessorBody(fieldLikeEvent, isAddMethod: MethodKind == MethodKind.EventAdd, compilationState.Compilation, diagnostics);
 
                    if (body != null)
                    {
                        compilationState.AddSynthesizedMethod(this, body);
                    }
                }
 
                return;
            }
 
            base.GenerateMethodBody(compilationState, diagnostics);
        }
    }
}