| File: Binder\Semantics\OverloadResolution\MethodGroup.cs | Web Access |
| Project: src\roslyn\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; 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<TSymbol>( BoundExpression receiverOpt, ArrayBuilder<TSymbol> members, ImmutableArray<TypeWithAnnotations> typeArguments, LookupResultKind resultKind = LookupResultKind.Viable, DiagnosticInfo error = null) where TSymbol : Symbol { this.PopulateHelper(receiverOpt, resultKind, error); this.IsExtensionMethodGroup = true; foreach (var member in members) { if (member is MethodSymbol method) { Debug.Assert(method.IsExtensionMethod || method.IsExtensionBlockMember()); this.Methods.Add(method); } } 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 } }