// 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; } } }