File: Binder\Semantics\OverloadResolution\MethodGroup.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.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    // pooled class used for input to overload resolution
    internal sealed class MethodGroup
    {
        internal BoundExpression Receiver { get; private set; }
        internal ArrayBuilder<MethodSymbol> Methods { get; }
        internal ArrayBuilder<TypeWithAnnotations> TypeArguments { get; }
        internal bool IsExtensionMethodGroup { get; private set; }
        internal DiagnosticInfo Error { get; private set; }
        internal LookupResultKind ResultKind { get; private set; }
 
        private MethodGroup()
        {
            this.Methods = new ArrayBuilder<MethodSymbol>();
            this.TypeArguments = new ArrayBuilder<TypeWithAnnotations>();
        }
 
        internal void PopulateWithSingleMethod(
            BoundExpression receiverOpt,
            MethodSymbol method,
            LookupResultKind resultKind = LookupResultKind.Viable,
            DiagnosticInfo error = null)
        {
            this.PopulateHelper(receiverOpt, resultKind, error);
            this.Methods.Add(method);
        }
 
        internal void PopulateWithExtensionMethods(
            BoundExpression receiverOpt,
            ArrayBuilder<Symbol> members,
            ImmutableArray<TypeWithAnnotations> typeArguments,
            LookupResultKind resultKind = LookupResultKind.Viable,
            DiagnosticInfo error = null)
        {
            this.PopulateHelper(receiverOpt, resultKind, error);
            this.IsExtensionMethodGroup = true;
            foreach (var member in members)
            {
                this.Methods.Add((MethodSymbol)member);
            }
            if (!typeArguments.IsDefault)
            {
                this.TypeArguments.AddRange(typeArguments);
            }
        }
 
        internal void PopulateWithNonExtensionMethods(
            BoundExpression receiverOpt,
            ImmutableArray<MethodSymbol> methods,
            ImmutableArray<TypeWithAnnotations> typeArguments,
            LookupResultKind resultKind = LookupResultKind.Viable,
            DiagnosticInfo error = null)
        {
            this.PopulateHelper(receiverOpt, resultKind, error);
            this.Methods.AddRange(methods);
            if (!typeArguments.IsDefault)
            {
                this.TypeArguments.AddRange(typeArguments);
            }
        }
 
        private void PopulateHelper(BoundExpression receiverOpt, LookupResultKind resultKind, DiagnosticInfo error)
        {
            VerifyClear();
            this.Receiver = receiverOpt;
            this.Error = error;
            this.ResultKind = resultKind;
        }
 
        public void Clear()
        {
            this.Receiver = null;
            this.Methods.Clear();
            this.TypeArguments.Clear();
            this.IsExtensionMethodGroup = false;
            this.Error = null;
            this.ResultKind = LookupResultKind.Empty;
 
            VerifyClear();
        }
 
        public string Name
        {
            get
            {
                return this.Methods.Count > 0 ? this.Methods[0].Name : null;
            }
        }
 
        public BoundExpression InstanceOpt
        {
            get
            {
                if (this.Receiver == null)
                {
                    return null;
                }
 
                if (this.Receiver.Kind == BoundKind.TypeExpression)
                {
                    return null;
                }
 
                return this.Receiver;
            }
        }
 
        [Conditional("DEBUG")]
        private void VerifyClear()
        {
            Debug.Assert(this.Receiver == null);
            Debug.Assert(this.Methods.Count == 0);
            Debug.Assert(this.TypeArguments.Count == 0);
            Debug.Assert(!this.IsExtensionMethodGroup);
            Debug.Assert(this.Error == null);
            Debug.Assert(this.ResultKind == LookupResultKind.Empty);
        }
 
        #region "Poolable"
 
        public static MethodGroup GetInstance()
        {
            return Pool.Allocate();
        }
 
        public void Free()
        {
            this.Clear();
            Pool.Free(this);
        }
 
        //2) Expose the pool or the way to create a pool or the way to get an instance.
        //       for now we will expose both and figure which way works better
        public static readonly ObjectPool<MethodGroup> Pool = CreatePool();
 
        private static ObjectPool<MethodGroup> CreatePool()
        {
            ObjectPool<MethodGroup> pool = null;
            pool = new ObjectPool<MethodGroup>(() => new MethodGroup(), 10);
            return pool;
        }
 
        #endregion
    }
}