File: Lowering\SynthesizedMethodBaseSymbol.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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using Microsoft.Cci;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    /// <summary>
    /// A base method symbol used as a base class for lambda method symbol and base method wrapper symbol.
    /// </summary>
    internal abstract class SynthesizedMethodBaseSymbol : SourceMemberMethodSymbol
    {
        protected readonly MethodSymbol BaseMethod;
        internal TypeMap TypeMap { get; private set; }
 
        private readonly string _name;
        private ImmutableArray<TypeParameterSymbol> _typeParameters;
        private ImmutableArray<ParameterSymbol> _parameters;
 
        protected SynthesizedMethodBaseSymbol(NamedTypeSymbol containingType,
                                              MethodSymbol baseMethod,
                                              SyntaxReference syntaxReference,
                                              Location location,
                                              string name,
                                              DeclarationModifiers declarationModifiers,
                                              bool isIterator)
            : base(containingType, syntaxReference, location, isIterator,
                   (declarationModifiers, MakeFlags(
                                                    methodKind: MethodKind.Ordinary,
                                                    refKind: baseMethod.RefKind,
                                                    declarationModifiers,
                                                    returnsVoid: baseMethod.ReturnsVoid,
                                                    returnsVoidIsSet: true,
                                                    isExtensionMethod: false,
                                                    isNullableAnalysisEnabled: false,
                                                    isVarArg: baseMethod.IsVararg,
                                                    isExpressionBodied: false,
                                                    isExplicitInterfaceImplementation: false,
                                                    hasThisInitializer: false)))
        {
            Debug.Assert((object)containingType != null);
            Debug.Assert((object)baseMethod != null);
 
            this.BaseMethod = baseMethod;
            _name = name;
        }
 
        protected void AssignTypeMapAndTypeParameters(TypeMap typeMap, ImmutableArray<TypeParameterSymbol> typeParameters)
        {
            Debug.Assert(typeMap != null);
            Debug.Assert(this.TypeMap == null);
            Debug.Assert(!typeParameters.IsDefault);
            Debug.Assert(_typeParameters.IsDefault);
            this.TypeMap = typeMap;
            _typeParameters = typeParameters;
        }
 
        protected override void MethodChecks(BindingDiagnosticBag diagnostics)
        {
            // TODO: move more functionality into here, making these symbols more lazy
        }
 
        internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder<SynthesizedAttributeData> attributes)
        {
            base.AddSynthesizedAttributes(moduleBuilder, ref attributes);
 
            // do not generate attributes for members of compiler-generated types:
            if (ContainingType.IsImplicitlyDeclared)
            {
                return;
            }
 
            var compilation = this.DeclaringCompilation;
 
            AddSynthesizedAttribute(ref attributes,
                compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor));
        }
 
        public sealed override ImmutableArray<TypeParameterSymbol> TypeParameters
        {
            get { return _typeParameters; }
        }
 
        public sealed override ImmutableArray<ImmutableArray<TypeWithAnnotations>> GetTypeParameterConstraintTypes()
            => ImmutableArray<ImmutableArray<TypeWithAnnotations>>.Empty;
 
        public sealed override ImmutableArray<TypeParameterConstraintKind> GetTypeParameterConstraintKinds()
            => ImmutableArray<TypeParameterConstraintKind>.Empty;
 
        internal override int ParameterCount
        {
            get { return this.Parameters.Length; }
        }
 
        public sealed override ImmutableArray<ParameterSymbol> Parameters
        {
            get
            {
                if (_parameters.IsDefault)
                {
                    ImmutableInterlocked.InterlockedInitialize(ref _parameters, MakeParameters());
                }
                return _parameters;
            }
        }
 
        protected virtual ImmutableArray<TypeSymbol> ExtraSynthesizedRefParameters
        {
            get { return default(ImmutableArray<TypeSymbol>); }
        }
 
        protected virtual ImmutableArray<ParameterSymbol> BaseMethodParameters
        {
            get { return this.BaseMethod.Parameters; }
        }
 
        private ImmutableArray<ParameterSymbol> MakeParameters()
        {
            int ordinal = 0;
            var builder = ArrayBuilder<ParameterSymbol>.GetInstance();
            var parameters = this.BaseMethodParameters;
            var inheritAttributes = InheritsBaseMethodAttributes;
            foreach (var p in parameters)
            {
                builder.Add(SynthesizedParameterSymbol.Create(
                    this,
                    this.TypeMap.SubstituteType(p.OriginalDefinition.TypeWithAnnotations),
                    ordinal++,
                    p.RefKind,
                    p.Name,
                    p.EffectiveScope,
                    p.ExplicitDefaultConstantValue,
                    // the synthesized parameter doesn't need to have the same ref custom modifiers as the base
                    refCustomModifiers: default,
                    inheritAttributes ? p as SourceComplexParameterSymbolBase : null));
            }
            var extraSynthed = ExtraSynthesizedRefParameters;
            if (!extraSynthed.IsDefaultOrEmpty)
            {
                foreach (var extra in extraSynthed)
                {
                    builder.Add(SynthesizedParameterSymbol.Create(this, this.TypeMap.SubstituteType(extra), ordinal++, RefKind.Ref));
                }
            }
            return builder.ToImmutableAndFree();
        }
 
        /// <summary>
        /// Indicates that this method inherits attributes from the base method, its parameters, return type, and type parameters.
        /// </summary>
        internal virtual bool InheritsBaseMethodAttributes => false;
 
        public sealed override ImmutableArray<CSharpAttributeData> GetAttributes()
        {
            Debug.Assert(base.GetAttributes().IsEmpty);
            return InheritsBaseMethodAttributes
                ? BaseMethod.GetAttributes()
                : ImmutableArray<CSharpAttributeData>.Empty;
        }
 
        public sealed override ImmutableArray<CSharpAttributeData> GetReturnTypeAttributes()
        {
            Debug.Assert(base.GetReturnTypeAttributes().IsEmpty);
            return InheritsBaseMethodAttributes ? BaseMethod.GetReturnTypeAttributes() : ImmutableArray<CSharpAttributeData>.Empty;
        }
 
#nullable enable
        public sealed override DllImportData? GetDllImportData() => InheritsBaseMethodAttributes ? BaseMethod.GetDllImportData() : null;
 
        internal sealed override MethodImplAttributes ImplementationAttributes => InheritsBaseMethodAttributes ? BaseMethod.ImplementationAttributes : default;
 
        internal sealed override MarshalPseudoCustomAttributeData? ReturnValueMarshallingInformation => InheritsBaseMethodAttributes ? BaseMethod.ReturnValueMarshallingInformation : null;
 
        internal sealed override bool HasSpecialName => InheritsBaseMethodAttributes && BaseMethod.HasSpecialName;
 
        // Synthesized methods created from a base method with [SkipLocalsInitAttribute] will also
        // skip locals init where applicable, even if the synthesized method does not inherit attributes.
        // Note that this doesn't affect BaseMethodWrapperSymbol for example because the implementation has no locals.
        public sealed override bool AreLocalsZeroed => !(BaseMethod is SourceMethodSymbol sourceMethod) || sourceMethod.AreLocalsZeroed;
 
        internal sealed override bool RequiresSecurityObject => InheritsBaseMethodAttributes && BaseMethod.RequiresSecurityObject;
 
        internal sealed override bool HasDeclarativeSecurity => InheritsBaseMethodAttributes && BaseMethod.HasDeclarativeSecurity;
 
        internal sealed override IEnumerable<SecurityAttribute> GetSecurityInformation() => InheritsBaseMethodAttributes
                ? BaseMethod.GetSecurityInformation()
                : SpecializedCollections.EmptyEnumerable<SecurityAttribute>();
 
#nullable disable
 
        public sealed override TypeWithAnnotations ReturnTypeWithAnnotations
        {
            get { return this.TypeMap.SubstituteType(this.BaseMethod.OriginalDefinition.ReturnTypeWithAnnotations); }
        }
 
        public sealed override FlowAnalysisAnnotations ReturnTypeFlowAnalysisAnnotations => BaseMethod.ReturnTypeFlowAnalysisAnnotations;
 
        public sealed override ImmutableHashSet<string> ReturnNotNullIfParameterNotNull => BaseMethod.ReturnNotNullIfParameterNotNull;
 
        public sealed override FlowAnalysisAnnotations FlowAnalysisAnnotations => FlowAnalysisAnnotations.None;
 
        public sealed override string Name
        {
            get { return _name; }
        }
 
        public sealed override bool IsImplicitlyDeclared
        {
            get { return true; }
        }
    }
}