File: AbstractTypeParameterChecker.cs
Web Access
Project: src\src\ExpressionEvaluator\Core\Source\ExpressionCompiler\Microsoft.CodeAnalysis.ExpressionCompiler.csproj (Microsoft.CodeAnalysis.ExpressionEvaluator.ExpressionCompiler)
// 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.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
    /// <summary>
    /// Shared <see cref="SymbolVisitor"/> that looks for instances of <see cref="ITypeParameterSymbol"/>
    /// that are not in a provided allow list.
    /// </summary>
    internal abstract class AbstractTypeParameterChecker : SymbolVisitor
    {
        private readonly HashSet<ITypeParameterSymbol> _acceptableTypeParameters;
 
        protected AbstractTypeParameterChecker(ImmutableArray<ITypeParameterSymbol> acceptableTypeParameters)
        {
            _acceptableTypeParameters = new HashSet<ITypeParameterSymbol>(acceptableTypeParameters);
        }
 
        public abstract IParameterSymbol GetThisParameter(IMethodSymbol method);
 
        public sealed override void VisitTypeParameter(ITypeParameterSymbol symbol)
        {
            // Using an if, rather than assert condition, to make debugging easier.
            if (!_acceptableTypeParameters.Contains(symbol))
            {
                Debug.Assert(false,
                    string.Format("Unexpected type parameter {0} owned by {1}", symbol, symbol.ContainingSymbol));
            }
 
            foreach (var constraintType in symbol.ConstraintTypes)
            {
                Visit(constraintType);
            }
        }
 
        public sealed override void VisitAlias(IAliasSymbol symbol)
        {
            Visit(symbol.Target);
        }
 
        public sealed override void VisitArrayType(IArrayTypeSymbol symbol)
        {
            Visit(symbol.ElementType);
        }
 
        public sealed override void VisitPointerType(IPointerTypeSymbol symbol)
        {
            Visit(symbol.PointedAtType);
        }
 
        public sealed override void VisitParameter(IParameterSymbol symbol)
        {
            Visit(symbol.Type);
 
            // Specifically not visiting containing symbol because VisitMethod visits the parameters (i.e. cycle).
        }
 
        public sealed override void VisitLocal(ILocalSymbol symbol)
        {
            Visit(symbol.Type);
 
            Visit(symbol.ContainingSymbol);
        }
 
        public sealed override void VisitEvent(IEventSymbol symbol)
        {
            Visit(symbol.Type);
 
            Visit(symbol.ContainingSymbol);
        }
 
        public sealed override void VisitField(IFieldSymbol symbol)
        {
            Visit(symbol.Type);
 
            Visit(symbol.ContainingSymbol);
        }
 
        public sealed override void VisitMethod(IMethodSymbol symbol)
        {
            if (!symbol.ReturnsVoid)
            {
                Visit(symbol.ReturnType);
            }
 
            foreach (var typeArgument in symbol.TypeArguments)
            {
                Visit(typeArgument);
            }
 
            Visit(GetThisParameter(symbol));
 
            foreach (var parameter in symbol.Parameters)
            {
                Visit(parameter);
            }
 
            Visit(symbol.ContainingSymbol);
        }
 
        public sealed override void VisitProperty(IPropertySymbol symbol)
        {
            Visit(symbol.Type);
 
            foreach (var parameter in symbol.Parameters)
            {
                Visit(parameter);
            }
 
            Visit(symbol.ContainingSymbol);
        }
 
        public sealed override void VisitNamedType(INamedTypeSymbol symbol)
        {
            foreach (var typeArgument in symbol.TypeArguments)
            {
                Visit(typeArgument);
            }
 
            Visit(symbol.ContainingSymbol);
        }
 
        public sealed override void VisitDynamicType(IDynamicTypeSymbol symbol)
        {
            // Fine.
        }
 
        public sealed override void VisitLabel(ILabelSymbol symbol)
        {
            // Fine.
        }
 
        public sealed override void VisitNamespace(INamespaceSymbol symbol)
        {
            // Fine.
        }
 
        public sealed override void VisitAssembly(IAssemblySymbol symbol)
        {
            throw ExceptionUtilities.UnexpectedValue(symbol.Kind);
        }
 
        public sealed override void VisitModule(IModuleSymbol symbol)
        {
            throw ExceptionUtilities.UnexpectedValue(symbol.Kind);
        }
 
        public sealed override void VisitRangeVariable(IRangeVariableSymbol symbol)
        {
            throw ExceptionUtilities.UnexpectedValue(symbol.Kind);
        }
    }
}