// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Microsoft.ClearScript.Util
{
internal static class MemberHelpers
{
public static bool IsScriptable(this EventInfo eventInfo, IHostContext context)
{
return !eventInfo.IsSpecialName && !eventInfo.IsExplicitImplementation() && eventInfo.IsAccessible(context) && !eventInfo.IsBlockedFromScript(context, context.DefaultAccess);
}
public static bool IsScriptable(this FieldInfo field, IHostContext context)
{
return !field.IsSpecialName && field.IsAccessible(context) && !field.IsBlockedFromScript(context, context.DefaultAccess);
}
public static bool IsScriptable(this MethodInfo method, IHostContext context)
{
return !method.IsSpecialName && !method.IsExplicitImplementation() && method.IsAccessible(context) && !method.IsBlockedFromScript(context, context.DefaultAccess);
}
public static bool IsScriptable(this PropertyInfo property, IHostContext context)
{
return !property.IsSpecialName && !property.IsExplicitImplementation() && property.IsAccessible(context) && !property.IsBlockedFromScript(context, context.DefaultAccess);
}
public static bool IsScriptable(this Type type, IHostContext context)
{
return !type.IsSpecialName && type.IsAccessible(context) && !type.IsBlockedFromScript(context, context.DefaultAccess);
}
public static bool IsAccessible(this EventInfo eventInfo, IHostContext context)
{
return eventInfo.AddMethod.IsAccessible(context);
}
public static bool IsAccessible(this FieldInfo field, IHostContext context)
{
var type = field.DeclaringType;
if (!type.IsAccessible(context))
{
return false;
}
var access = field.Attributes & FieldAttributes.FieldAccessMask;
if (access == FieldAttributes.Public)
{
return true;
}
var accessContext = context.AccessContext;
if (accessContext is null)
{
return false;
}
if (access == FieldAttributes.Private)
{
return type.EqualsOrDeclares(accessContext);
}
if (access == FieldAttributes.Family)
{
return accessContext.IsFamilyOf(type);
}
if (access == FieldAttributes.Assembly)
{
return accessContext.IsFriendOf(context, type);
}
if (access == FieldAttributes.FamORAssem)
{
return accessContext.IsFamilyOf(type) || accessContext.IsFriendOf(context, type);
}
if (access == FieldAttributes.FamANDAssem)
{
return accessContext.IsFamilyOf(type) && accessContext.IsFriendOf(context, type);
}
return false;
}
public static bool IsAccessible(this MethodBase method, IHostContext context)
{
var type = method.DeclaringType;
if (!type.IsAccessible(context))
{
return false;
}
var access = method.Attributes & MethodAttributes.MemberAccessMask;
if (access == MethodAttributes.Public)
{
return true;
}
var accessContext = context.AccessContext;
if (accessContext is null)
{
return false;
}
if (access == MethodAttributes.Private)
{
return type.EqualsOrDeclares(accessContext);
}
if (access == MethodAttributes.Family)
{
return accessContext.IsFamilyOf(type);
}
if (access == MethodAttributes.Assembly)
{
return accessContext.IsFriendOf(context, type);
}
if (access == MethodAttributes.FamORAssem)
{
return accessContext.IsFamilyOf(type) || accessContext.IsFriendOf(context, type);
}
if (access == MethodAttributes.FamANDAssem)
{
return accessContext.IsFamilyOf(type) && accessContext.IsFriendOf(context, type);
}
return false;
}
public static bool IsAccessible(this MethodInfo method, IHostContext context)
{
return ((MethodBase)method.GetBaseDefinition()).IsAccessible(context);
}
public static bool IsAccessible(this PropertyInfo property, IHostContext context)
{
var getMethod = property.GetMethod;
if ((getMethod is not null) && getMethod.IsAccessible(context))
{
return true;
}
var setMethod = property.SetMethod;
if ((setMethod is not null) && setMethod.IsAccessible(context))
{
return true;
}
return false;
}
public static bool IsAccessible(this Type type, IHostContext context)
{
var visibility = (type.IsAnonymous(context) && !context.Engine.EnforceAnonymousTypeAccess) ? TypeAttributes.Public : type.Attributes & TypeAttributes.VisibilityMask;
if (visibility == TypeAttributes.Public)
{
return true;
}
var accessContext = context.AccessContext;
if (accessContext is null)
{
return (visibility == TypeAttributes.NestedPublic) && type.DeclaringType.IsAccessible(context);
}
if (visibility == TypeAttributes.NotPublic)
{
return accessContext.IsFriendOf(context, type);
}
type = type.DeclaringType;
if (!type.IsAccessible(context))
{
return false;
}
if (visibility == TypeAttributes.NestedPublic)
{
return true;
}
if (visibility == TypeAttributes.NestedPrivate)
{
return type.EqualsOrDeclares(accessContext);
}
if (visibility == TypeAttributes.NestedFamily)
{
return accessContext.IsFamilyOf(type);
}
if (visibility == TypeAttributes.NestedAssembly)
{
return accessContext.IsFriendOf(context, type);
}
if (visibility == TypeAttributes.NestedFamORAssem)
{
return accessContext.IsFamilyOf(type) || accessContext.IsFriendOf(context, type);
}
if (visibility == TypeAttributes.NestedFamANDAssem)
{
return accessContext.IsFamilyOf(type) && accessContext.IsFriendOf(context, type);
}
return false;
}
public static string GetScriptName(this MemberInfo member, IHostContext context)
{
var attribute = member.GetOrLoadCustomAttribute