File: Binder\Semantics\OverloadResolution\AnalyzedArguments.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 Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    // Note: instances of this object are pooled
    internal sealed class AnalyzedArguments
    {
        public readonly ArrayBuilder<BoundExpression> Arguments;
        public readonly ArrayBuilder<(string Name, Location Location)?> Names;
        public readonly ArrayBuilder<RefKind> RefKinds;
        public bool IsExtensionMethodInvocation;
        private ThreeState _lazyHasDynamicArgument;
 
        internal AnalyzedArguments()
        {
            this.Arguments = new ArrayBuilder<BoundExpression>(32);
            this.Names = new ArrayBuilder<(string, Location)?>(32);
            this.RefKinds = new ArrayBuilder<RefKind>(32);
        }
 
        public void Clear()
        {
            this.Arguments.Clear();
            this.Names.Clear();
            this.RefKinds.Clear();
            this.IsExtensionMethodInvocation = false;
            _lazyHasDynamicArgument = ThreeState.Unknown;
        }
 
        public BoundExpression Argument(int i)
        {
            return Arguments[i];
        }
 
        public void AddName(IdentifierNameSyntax name)
        {
            Names.Add((name.Identifier.ValueText, name.Location));
        }
 
        public string? Name(int i)
        {
            if (Names.Count == 0)
            {
                return null;
            }
 
            var nameAndLocation = Names[i];
            return nameAndLocation?.Name;
        }
 
        public ImmutableArray<string?> GetNames()
        {
            int count = this.Names.Count;
 
            if (count == 0)
            {
                return default;
            }
 
            var builder = ArrayBuilder<string?>.GetInstance(this.Names.Count);
            for (int i = 0; i < this.Names.Count; ++i)
            {
                builder.Add(Name(i));
            }
 
            return builder.ToImmutableAndFree();
        }
 
        public RefKind RefKind(int i)
        {
            return RefKinds.Count > 0 ? RefKinds[i] : Microsoft.CodeAnalysis.RefKind.None;
        }
 
        public bool IsExtensionMethodThisArgument(int i)
        {
            return (i == 0) && this.IsExtensionMethodInvocation;
        }
 
        public bool HasDynamicArgument
        {
            get
            {
                if (_lazyHasDynamicArgument.HasValue())
                {
                    return _lazyHasDynamicArgument.Value();
                }
 
                bool hasRefKinds = RefKinds.Count > 0;
                for (int i = 0; i < Arguments.Count; i++)
                {
                    var argument = Arguments[i];
 
                    // By-ref dynamic arguments don't make the invocation dynamic.
                    if ((object?)argument.Type != null && argument.Type.IsDynamic() && (!hasRefKinds || RefKinds[i] == Microsoft.CodeAnalysis.RefKind.None))
                    {
                        _lazyHasDynamicArgument = ThreeState.True;
                        return true;
                    }
                }
 
                _lazyHasDynamicArgument = ThreeState.False;
                return false;
            }
        }
 
        public bool HasErrors
        {
            get
            {
                foreach (var argument in this.Arguments)
                {
                    if (argument.HasAnyErrors)
                    {
                        return true;
                    }
                }
 
                return false;
            }
        }
 
        #region "Poolable"
 
        public static AnalyzedArguments GetInstance()
        {
            return Pool.Allocate();
        }
 
        public static AnalyzedArguments GetInstance(AnalyzedArguments original)
        {
            var instance = GetInstance();
            instance.Arguments.AddRange(original.Arguments);
            instance.Names.AddRange(original.Names);
            instance.RefKinds.AddRange(original.RefKinds);
            instance.IsExtensionMethodInvocation = original.IsExtensionMethodInvocation;
            instance._lazyHasDynamicArgument = original._lazyHasDynamicArgument;
            return instance;
        }
 
        public static AnalyzedArguments GetInstance(
            ImmutableArray<BoundExpression> arguments,
            ImmutableArray<RefKind> argumentRefKindsOpt,
            ImmutableArray<(string, Location)?> argumentNamesOpt)
        {
            var instance = GetInstance();
            instance.Arguments.AddRange(arguments);
            if (!argumentRefKindsOpt.IsDefault)
            {
                instance.RefKinds.AddRange(argumentRefKindsOpt);
            }
 
            if (!argumentNamesOpt.IsDefault)
            {
                instance.Names.AddRange(argumentNamesOpt);
            }
 
            return instance;
        }
 
        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<AnalyzedArguments> Pool = CreatePool();
 
        private static ObjectPool<AnalyzedArguments> CreatePool()
        {
            ObjectPool<AnalyzedArguments>? pool = null;
            pool = new ObjectPool<AnalyzedArguments>(() => new AnalyzedArguments(), 10);
            return pool;
        }
 
        #endregion
    }
}