chr
2026-04-05 fe750b791d5b517cc4e9bc8e99a9a75139a0cfba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
//            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
{
    /// <summary> Helpers for work with ITypeInfo objects. </summary>
    public static class ReflectionDataExtensions
    {
        /// <summary>
        /// Creates an instance of this type using the default constructor.
        /// </summary>
        public static object CreateInstance(this ITypeData type)
        {
            return type?.CreateInstance(Array.Empty<object>());
        }
 
        /// <summary> returns true if 'type' is a descendant of 'basetype'. </summary>
        /// <param name="type"></param>
        /// <param name="basetype"></param>
        /// <returns></returns>
        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;
        }
        /// <summary> returns tru if 'type' is a descendant of 'basetype'. </summary>
        /// <param name="type"></param>
        /// <param name="basetype"></param>
        /// <returns></returns>
        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<T>(this IReflectionData mem) where T : class
        {
            if (mem is ITypeData td)
            {
                while (td != null)
                {
                    if (td.HasAttribute<T>()) return true;
                    td = td.BaseType;
                }
 
                return false;
            }
 
            throw new ArgumentException("Inherited attributes can only be read from type data instances.");
        }
        
        internal static IEnumerable<T> GetAttributesInherited<T>(this IReflectionData mem) where T : class
        {
            if (mem is ITypeData td)
            {
                IEnumerable<T> result = null;
                while (td != null)
                {
                    var r = td.Attributes?.OfType<T>();
                    if (r?.Any() == true)
                    {
                        if(result != null)
                            result = result.Concat(r);
                        else result = r;
                    }
 
                    td = td.BaseType;
                }
 
                return result ?? Array.Empty<T>();
            }
 
            throw new ArgumentException("Inherited attributes can only be read from type data instances.");
        }
 
        /// <summary>
        /// Returns true if a reflection ifno has an attribute of type T.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mem"></param>
        /// <returns></returns>
        static public bool HasAttribute<T>(this IReflectionData mem) where T: class
        {
            return mem.GetAttribute<T>() != null;
        }
 
        /// <summary> Gets the attribute of type T from mem. </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mem"></param>
        /// <returns></returns>
        public static T GetAttribute<T>(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<BrowsableAttribute>();
            if (attr is null)
                return true;
            return attr.Browsable;
        }
 
        /// <summary> Gets all the attributes of type T.</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mem"></param>
        /// <returns></returns>
        public static IEnumerable<T> GetAttributes<T>(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<T>();
                        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<T>();
                        once = true;
                        first = x;
                    }
                }
            }
 
            if (once) return new [] { first };
            return Array.Empty<T>();
        }
 
        /// <summary> Gets a display attribute of mem in the selected language, if available. Otherwise the default display attribute is returned. </summary>
        /// <param name="mem">The member to translate</param>
        /// <param name="language">The desired language of the translation. If not specified, the language from EngineSettings is used.</param>
        /// <returns></returns>
        public static DisplayAttribute GetTranslatedDisplayAttribute(this IReflectionData mem, CultureInfo language = null)
        {
            return TranslationManager.TranslateMember(mem, language);
        }
 
        /// <summary> Gets the display attribute of mem. </summary>
        /// <param name="mem">The member to translate</param>
        /// <returns></returns>
        public static DisplayAttribute GetDisplayAttribute(this IReflectionData mem)
        {
            DisplayAttribute attr;
            if (mem is TypeData td)
                attr = td.Display;
            else
                attr = mem.GetAttribute<DisplayAttribute>();
            if (attr != null) return attr;
            // auto-generate a display attribute.
            return new DefaultDisplayAttribute(mem);
        }
 
        /// <summary>Gets the help link of 'member'</summary>
        /// <param name="member"></param>
        /// <returns></returns>
        internal static HelpLinkAttribute GetHelpLink(this IReflectionData member)
        {
            var attr = member.GetAttribute<HelpLinkAttribute>();
            if (attr != null)
                return attr;
            if (member is IMemberData meminfo)// Recursively look for class level help.
                return meminfo.DeclaringType.GetHelpLink();
            return null;
        }
    }
}