// Copyright Keysight Technologies 2012-2019
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at http://mozilla.org/MPL/2.0/.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using OpenTap.Translation;
namespace OpenTap
{
/// Helpers for work with ITypeInfo objects.
public static class ReflectionDataExtensions
{
///
/// Creates an instance of this type using the default constructor.
///
public static object CreateInstance(this ITypeData type)
{
return type?.CreateInstance(Array.Empty());
}
/// returns true if 'type' is a descendant of 'basetype'.
///
///
///
public static bool DescendsTo(this ITypeData type, ITypeData basetype)
{
if (basetype is TypeData basetype2)
{
return DescendsTo(type, basetype2.Type);
}
while (type != null)
{
if (object.Equals(type, basetype))
return true;
type = type.BaseType;
}
return false;
}
/// returns tru if 'type' is a descendant of 'basetype'.
///
///
///
public static bool DescendsTo(this ITypeData type, Type basetype)
{
while (type != null)
{
if (type is TypeData cst)
{
return cst.Type.DescendsTo(basetype);
}
type = type.BaseType;
}
return false;
}
internal static bool HasAttributeInherited(this IReflectionData mem) where T : class
{
if (mem is ITypeData td)
{
while (td != null)
{
if (td.HasAttribute()) return true;
td = td.BaseType;
}
return false;
}
throw new ArgumentException("Inherited attributes can only be read from type data instances.");
}
internal static IEnumerable GetAttributesInherited(this IReflectionData mem) where T : class
{
if (mem is ITypeData td)
{
IEnumerable result = null;
while (td != null)
{
var r = td.Attributes?.OfType();
if (r?.Any() == true)
{
if(result != null)
result = result.Concat(r);
else result = r;
}
td = td.BaseType;
}
return result ?? Array.Empty();
}
throw new ArgumentException("Inherited attributes can only be read from type data instances.");
}
///
/// Returns true if a reflection ifno has an attribute of type T.
///
///
///
///
static public bool HasAttribute(this IReflectionData mem) where T: class
{
return mem.GetAttribute() != null;
}
/// Gets the attribute of type T from mem.
///
///
///
public static T GetAttribute(this IReflectionData mem)
{
if (mem is TypeData td)
{
if(typeof(T) == typeof(DisplayAttribute))
{
return (T)(object)td.Display;
}
if (typeof(T) == typeof(HelpLinkAttribute))
{
return (T)(object)td.HelpLink;
}
}
var attributes = mem.Attributes;
if (attributes is object[] array)
{
// performance optimization: faster iterations if we know its an array.
foreach (var thing in array)
if (thing is T x)
return x;
}
else
{
foreach (var thing in attributes)
if (thing is T x)
return x;
}
return default;
}
internal static bool IsBrowsable(this IReflectionData mem)
{
if (mem is TypeData td)
{
return td.IsBrowsable;
}
var attr = mem.GetAttribute();
if (attr is null)
return true;
return attr.Browsable;
}
/// Gets all the attributes of type T.
///
///
///
public static IEnumerable GetAttributes(this IReflectionData mem)
{
var attrs = mem.Attributes;
bool once = false;
T first = default;
if (attrs is object[] attrsArray)
{
// performance optimization: faster iterations if we know its an array.
foreach (var elem in attrsArray)
{
if (elem is T x)
{
if (once) // multiple instances of T, lets just use OfType.
return attrsArray.OfType();
once = true;
first = x;
}
}
}
else
{
foreach (var elem in attrs)
{
if (elem is T x)
{
if (once) // multiple instances of T, lets just use OfType.
return attrs.OfType();
once = true;
first = x;
}
}
}
if (once) return new [] { first };
return Array.Empty();
}
/// Gets a display attribute of mem in the selected language, if available. Otherwise the default display attribute is returned.
/// The member to translate
/// The desired language of the translation. If not specified, the language from EngineSettings is used.
///
public static DisplayAttribute GetTranslatedDisplayAttribute(this IReflectionData mem, CultureInfo language = null)
{
return TranslationManager.TranslateMember(mem, language);
}
/// Gets the display attribute of mem.
/// The member to translate
///
public static DisplayAttribute GetDisplayAttribute(this IReflectionData mem)
{
DisplayAttribute attr;
if (mem is TypeData td)
attr = td.Display;
else
attr = mem.GetAttribute();
if (attr != null) return attr;
// auto-generate a display attribute.
return new DefaultDisplayAttribute(mem);
}
/// Gets the help link of 'member'
///
///
internal static HelpLinkAttribute GetHelpLink(this IReflectionData member)
{
var attr = member.GetAttribute();
if (attr != null)
return attr;
if (member is IMemberData meminfo)// Recursively look for class level help.
return meminfo.DeclaringType.GetHelpLink();
return null;
}
}
}