File: Shared\Utilities\EditorBrowsableHelpers.cs
Web Access
Project: ..\..\..\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.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Shared.Utilities
{
    internal static class EditorBrowsableHelpers
    {
        public readonly struct EditorBrowsableInfo
        {
            public Compilation Compilation { get; }
            public INamedTypeSymbol? HideModuleNameAttribute { get; }
            public IMethodSymbol? EditorBrowsableAttributeConstructor { get; }
            public ImmutableArray<IMethodSymbol> TypeLibTypeAttributeConstructors { get; }
            public ImmutableArray<IMethodSymbol> TypeLibFuncAttributeConstructors { get; }
            public ImmutableArray<IMethodSymbol> TypeLibVarAttributeConstructors { get; }
            public bool IsDefault => Compilation == null;
 
            public EditorBrowsableInfo(Compilation compilation)
            {
                Compilation = compilation;
                HideModuleNameAttribute = compilation.HideModuleNameAttribute();
                EditorBrowsableAttributeConstructor = GetSpecialEditorBrowsableAttributeConstructor(compilation);
                TypeLibTypeAttributeConstructors = GetSpecialTypeLibTypeAttributeConstructors(compilation);
                TypeLibFuncAttributeConstructors = GetSpecialTypeLibFuncAttributeConstructors(compilation);
                TypeLibVarAttributeConstructors = GetSpecialTypeLibVarAttributeConstructors(compilation);
            }
        }
 
        /// <summary>
        /// Finds the constructor which takes exactly one argument, which must be of type EditorBrowsableState.
        /// It does not require that the EditorBrowsableAttribute and EditorBrowsableState types be those
        /// shipped by Microsoft, but it does demand the types found follow the expected pattern. If at any
        /// point that pattern appears to be violated, return null to indicate that an appropriate constructor
        /// could not be found.
        /// </summary>
        public static IMethodSymbol? GetSpecialEditorBrowsableAttributeConstructor(Compilation compilation)
        {
            var editorBrowsableAttributeType = compilation.EditorBrowsableAttributeType();
            var editorBrowsableStateType = compilation.EditorBrowsableStateType();
 
            if (editorBrowsableAttributeType == null || editorBrowsableStateType == null)
            {
                return null;
            }
 
            var candidateConstructors = editorBrowsableAttributeType.Constructors
                                                                    .Where(c => c.Parameters.Length == 1 && Equals(c.Parameters[0].Type, editorBrowsableStateType));
 
            // Ensure the constructor adheres to the expected EditorBrowsable pattern
            candidateConstructors = candidateConstructors.Where(c => (!c.IsVararg &&
                                                                      !c.Parameters[0].IsRefOrOut() &&
                                                                      !c.Parameters[0].CustomModifiers.Any()));
 
            // If there are multiple constructors that look correct then the discovered types do not match the
            // expected pattern, so return null.
            if (candidateConstructors.Count() <= 1)
            {
                return candidateConstructors.FirstOrDefault();
            }
            else
            {
                return null;
            }
        }
 
        public static ImmutableArray<IMethodSymbol> GetSpecialTypeLibTypeAttributeConstructors(Compilation compilation)
        {
            return GetSpecialTypeLibAttributeConstructorsWorker(
                compilation,
                "System.Runtime.InteropServices.TypeLibTypeAttribute",
                "System.Runtime.InteropServices.TypeLibTypeFlags");
        }
 
        public static ImmutableArray<IMethodSymbol> GetSpecialTypeLibFuncAttributeConstructors(Compilation compilation)
        {
            return GetSpecialTypeLibAttributeConstructorsWorker(
                compilation,
                "System.Runtime.InteropServices.TypeLibFuncAttribute",
                "System.Runtime.InteropServices.TypeLibFuncFlags");
        }
 
        public static ImmutableArray<IMethodSymbol> GetSpecialTypeLibVarAttributeConstructors(Compilation compilation)
        {
            return GetSpecialTypeLibAttributeConstructorsWorker(
                compilation,
                "System.Runtime.InteropServices.TypeLibVarAttribute",
                "System.Runtime.InteropServices.TypeLibVarFlags");
        }
 
        /// <summary>
        /// The TypeLib*Attribute classes that accept TypeLib*Flags with FHidden as an option all have two constructors,
        /// one accepting a TypeLib*Flags and the other a short. This methods gets those two constructor symbols for any
        /// of these attribute classes. It does not require that the either of these types be those shipped by Microsoft,
        /// but it does demand the types found follow the expected pattern. If at any point that pattern appears to be
        /// violated, return an empty enumerable to indicate that no appropriate constructors were found.
        /// </summary>
        private static ImmutableArray<IMethodSymbol> GetSpecialTypeLibAttributeConstructorsWorker(
            Compilation compilation,
            string attributeMetadataName,
            string flagsMetadataName)
        {
            var typeLibAttributeType = compilation.GetTypeByMetadataName(attributeMetadataName);
            var typeLibFlagsType = compilation.GetTypeByMetadataName(flagsMetadataName);
            var shortType = compilation.GetSpecialType(SpecialType.System_Int16);
 
            if (typeLibAttributeType == null || typeLibFlagsType == null || shortType == null)
            {
                return ImmutableArray<IMethodSymbol>.Empty;
            }
 
            var candidateConstructors = typeLibAttributeType.Constructors
                                                            .Where(c => c.Parameters.Length == 1 &&
                                                                        (Equals(c.Parameters[0].Type, typeLibFlagsType) || Equals(c.Parameters[0].Type, shortType)));
 
            candidateConstructors = candidateConstructors.Where(c => (!c.IsVararg &&
                                                                      !c.Parameters[0].IsRefOrOut() &&
                                                                      !c.Parameters[0].CustomModifiers.Any()));
 
            return candidateConstructors.ToImmutableArrayOrEmpty();
        }
    }
}