File: Symbols\Extensions\SourceExtensionImplementationMethodSymbol.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.
 
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.PooledObjects;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    internal sealed class SourceExtensionImplementationMethodSymbol : RewrittenMethodSymbol // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Do we need to implement ISynthesizedMethodBodyImplementationSymbol?
    {
        public SourceExtensionImplementationMethodSymbol(MethodSymbol sourceMethod)
            : base(sourceMethod, TypeMap.Empty, sourceMethod.ContainingType.TypeParameters.Concat(sourceMethod.TypeParameters))
        {
            Debug.Assert(sourceMethod.GetIsNewExtensionMember());
            Debug.Assert(sourceMethod.IsStatic || sourceMethod.ContainingType.ExtensionParameter is not null);
            Debug.Assert(!sourceMethod.IsExtern);
            Debug.Assert(!sourceMethod.IsExternal);
 
            // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Are we creating type parameters with the right emit behavior? Attributes, etc.
            //            Also, they should be IsImplicitlyDeclared
        }
 
        public override int Arity => TypeParameters.Length;
 
        public override bool IsGenericMethod => Arity != 0;
 
        public override MethodKind MethodKind => MethodKind.Ordinary;
        public override bool IsImplicitlyDeclared => true;
 
        internal override bool HasSpecialName => true; // Tracked by https://github.com/dotnet/roslyn/issues/76130 : reconcile with spec
 
        internal override int ParameterCount
        {
            get
            {
                return _originalMethod.ParameterCount + (_originalMethod.IsStatic ? 0 : 1);
            }
        }
 
        public sealed override bool IsExtensionMethod => !_originalMethod.IsStatic && _originalMethod.MethodKind is MethodKind.Ordinary;
        public sealed override bool IsVirtual => false;
 
        public sealed override bool IsOverride => false;
        public sealed override bool IsAbstract => false;
        public sealed override bool IsSealed => false;
 
        internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) => false;
        internal sealed override bool IsMetadataFinal => false;
        internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) => false;
 
        internal sealed override bool IsAccessCheckedOnOverride => false;
 
        public sealed override bool IsExtern => false;
        public sealed override DllImportData? GetDllImportData() => null;
        internal sealed override bool IsExternal => false;
 
        // Tracked by https://github.com/dotnet/roslyn/issues/76130 : How doc comments are supposed to work? GetDocumentationCommentXml
 
        internal sealed override bool IsDeclaredReadOnly => false;
 
        public sealed override Symbol ContainingSymbol => _originalMethod.ContainingType.ContainingSymbol;
 
        internal sealed override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder<CSharpAttributeData> attributes)
        {
            base.AddSynthesizedAttributes(moduleBuilder, ref attributes);
            SourceMethodSymbol.AddSynthesizedAttributes(this, moduleBuilder, ref attributes);
        }
 
        public override bool IsStatic => true;
        public override bool RequiresInstanceReceiver => false;
 
        internal override Microsoft.Cci.CallingConvention CallingConvention
        {
            get
            {
                return (_originalMethod.CallingConvention & (~Cci.CallingConvention.HasThis)) |
                       (Arity != 0 ? Cci.CallingConvention.Generic : 0);
            }
        }
 
        public override Symbol? AssociatedSymbol => null;
 
        protected override ImmutableArray<ParameterSymbol> MakeParameters()
        {
            var sourceParameters = _originalMethod.Parameters;
            var parameters = ArrayBuilder<ParameterSymbol>.GetInstance(ParameterCount);
 
            if (!_originalMethod.IsStatic)
            {
                // Tracked by https://github.com/dotnet/roslyn/issues/76130 : Need to confirm if this rewrite going to break LocalStateTracingInstrumenter
                //            Specifically BoundParameterId, etc.   
                parameters.Add(new ExtensionMetadataMethodParameterSymbol(this, ((SourceNamedTypeSymbol)_originalMethod.ContainingType).ExtensionParameter!));
            }
 
            foreach (var parameter in sourceParameters)
            {
                parameters.Add(new ExtensionMetadataMethodParameterSymbol(this, parameter));
            }
 
            Debug.Assert(parameters.Count == ParameterCount);
            return parameters.ToImmutableAndFree();
        }
 
        internal override bool TryGetThisParameter(out ParameterSymbol? thisParameter)
        {
            thisParameter = null;
            return true;
        }
 
        private sealed class ExtensionMetadataMethodParameterSymbol : RewrittenMethodParameterSymbol
        {
            public ExtensionMetadataMethodParameterSymbol(SourceExtensionImplementationMethodSymbol containingMethod, ParameterSymbol sourceParameter) :
                base(containingMethod, sourceParameter)
            {
            }
 
            public override bool IsImplicitlyDeclared => true;
 
            public override int Ordinal
            {
                get
                {
                    if (this._underlyingParameter.ContainingSymbol is NamedTypeSymbol)
                    {
                        return 0;
                    }
 
                    var ordinal = this._underlyingParameter.Ordinal;
 
                    if (this._underlyingParameter.ContainingSymbol.IsStatic)
                    {
                        return ordinal;
                    }
 
                    return ordinal + 1;
                }
            }
        }
    }
}