File: Symbols\SubstitutedParameterSymbol.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;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    internal sealed class SubstitutedParameterSymbol : WrappedParameterSymbol
    {
        // initially set to map which is only used to get the type, which is once computed is stored here.
        private object _mapOrType;
 
        private readonly Symbol _containingSymbol;
 
        internal SubstitutedParameterSymbol(MethodSymbol containingSymbol, TypeMap map, ParameterSymbol originalParameter) :
            this((Symbol)containingSymbol, map, originalParameter)
        {
        }
 
        internal SubstitutedParameterSymbol(PropertySymbol containingSymbol, TypeMap map, ParameterSymbol originalParameter) :
            this((Symbol)containingSymbol, map, originalParameter)
        {
        }
 
        private SubstitutedParameterSymbol(Symbol containingSymbol, TypeMap map, ParameterSymbol originalParameter) :
            base(originalParameter)
        {
            Debug.Assert(originalParameter.IsDefinition);
            _containingSymbol = containingSymbol;
            _mapOrType = map;
        }
 
        public override ParameterSymbol OriginalDefinition
        {
            get { return _underlyingParameter.OriginalDefinition; }
        }
 
        public override Symbol ContainingSymbol
        {
            get { return _containingSymbol; }
        }
 
        public override TypeWithAnnotations TypeWithAnnotations
        {
            get
            {
                var mapOrType = _mapOrType;
                if (mapOrType is TypeWithAnnotations type)
                {
                    return type;
                }
 
                TypeWithAnnotations substituted = ((TypeMap)mapOrType).SubstituteType(this._underlyingParameter.TypeWithAnnotations);
 
                if (substituted.CustomModifiers.IsEmpty &&
                    this._underlyingParameter.TypeWithAnnotations.CustomModifiers.IsEmpty &&
                    this._underlyingParameter.RefCustomModifiers.IsEmpty)
                {
                    _mapOrType = substituted;
                }
 
                return substituted;
            }
        }
 
        internal override ImmutableArray<int> InterpolatedStringHandlerArgumentIndexes => _underlyingParameter.InterpolatedStringHandlerArgumentIndexes;
 
        internal override bool HasInterpolatedStringHandlerArgumentError => _underlyingParameter.HasInterpolatedStringHandlerArgumentError;
 
        public override ImmutableArray<CustomModifier> RefCustomModifiers
        {
            get
            {
                var map = _mapOrType as TypeMap;
                return map != null ? map.SubstituteCustomModifiers(this._underlyingParameter.RefCustomModifiers) : this._underlyingParameter.RefCustomModifiers;
            }
        }
 
        internal override bool IsCallerLineNumber
        {
            get { return _underlyingParameter.IsCallerLineNumber; }
        }
 
        internal override bool IsCallerFilePath
        {
            get { return _underlyingParameter.IsCallerFilePath; }
        }
 
        internal override bool IsCallerMemberName
        {
            get { return _underlyingParameter.IsCallerMemberName; }
        }
 
        internal override int CallerArgumentExpressionParameterIndex
        {
            get { return _underlyingParameter.CallerArgumentExpressionParameterIndex; }
        }
 
        public sealed override bool Equals(Symbol obj, TypeCompareKind compareKind)
        {
            if ((object)this == obj)
            {
                return true;
            }
 
            // Equality of ordinal and containing symbol is a correct
            // implementation for all ParameterSymbols, but we don't 
            // define it on the base type because most can simply use
            // ReferenceEquals.
 
            var other = obj as SubstitutedParameterSymbol;
            return other is not null &&
                this.Ordinal == other.Ordinal &&
                this.ContainingSymbol.Equals(other.ContainingSymbol, compareKind);
        }
 
        public sealed override int GetHashCode()
        {
            return Roslyn.Utilities.Hash.Combine(ContainingSymbol, _underlyingParameter.Ordinal);
        }
    }
}