File: src\Workspaces\SharedUtilitiesAndExtensions\Compiler\Core\Extensions\ISymbolExtensions.RequiresUnsafeModifierVisitor.cs
Web Access
Project: src\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// 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.Generic;
using System.Diagnostics;
using System.Linq;
 
namespace Microsoft.CodeAnalysis.Shared.Extensions;
 
internal static partial class ISymbolExtensions
{
    /// <summary>
    /// Visits types or members that have signatures (i.e. methods, fields, etc.) and determines
    /// if any of them reference a pointer type and should thus have the <see
    /// langword="unsafe"/> modifier on them.
    /// </summary>
    private sealed class RequiresUnsafeModifierVisitor : SymbolVisitor<bool>
    {
        private readonly HashSet<ISymbol> _visited = [];
 
        public override bool DefaultVisit(ISymbol node)
        {
            Debug.Fail("Unhandled symbol kind in RequiresUnsafeModifierVisitor: " + node.Kind);
            return false;
        }
 
        public override bool VisitArrayType(IArrayTypeSymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return symbol.ElementType.Accept(this);
        }
 
        public override bool VisitDynamicType(IDynamicTypeSymbol symbol)
        {
            // The dynamic type is never unsafe (well....you know what I mean)
            return false;
        }
 
        public override bool VisitField(IFieldSymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return symbol.Type.Accept(this);
        }
 
        public override bool VisitNamedType(INamedTypeSymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return symbol.GetAllTypeArguments().Any(ts => ts.Accept(this));
        }
 
        public override bool VisitPointerType(IPointerTypeSymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return true;
        }
 
        public override bool VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return true;
        }
 
        public override bool VisitProperty(IPropertySymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return
                symbol.Type.Accept(this) ||
                symbol.Parameters.Any(static (p, self) => p.Accept(self), this);
        }
 
        public override bool VisitTypeParameter(ITypeParameterSymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return symbol.ConstraintTypes.Any(static (ts, self) => ts.Accept(self), this);
        }
 
        public override bool VisitMethod(IMethodSymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return
                symbol.ReturnType.Accept(this) ||
                symbol.Parameters.Any(static (p, self) => p.Accept(self), this) ||
                symbol.TypeParameters.Any(static (tp, self) => tp.Accept(self), this);
        }
 
        public override bool VisitParameter(IParameterSymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return symbol.Type.Accept(this);
        }
 
        public override bool VisitEvent(IEventSymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return symbol.Type.Accept(this);
        }
 
        public override bool VisitAlias(IAliasSymbol symbol)
        {
            if (!_visited.Add(symbol))
            {
                return false;
            }
 
            return symbol.Target.Accept(this);
        }
    }
}