2 // MonoCustomAttrs.cs: Hooks into the runtime to get custom attributes for reflection handles
5 // Paolo Molaro (lupus@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Marek Safar (marek.safar@gmail.com)
9 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Reflection;
35 using System.Collections;
36 using System.Runtime.CompilerServices;
37 using System.Runtime.InteropServices;
39 using System.Reflection.Emit;
42 using System.Collections.Generic;
46 static class MonoCustomAttrs
48 static Assembly corlib;
50 static Dictionary<Type, AttributeUsageAttribute> usage_cache;
52 /* Treat as user types all corlib types extending System.Type that are not MonoType and TypeBuilder */
53 static bool IsUserCattrProvider (object obj)
55 Type type = obj as Type;
57 if ((type is MonoType) || (type is TypeBuilder))
65 corlib = typeof (int).Assembly;
66 return obj.GetType ().Assembly != corlib;
69 [MethodImplAttribute (MethodImplOptions.InternalCall)]
70 internal static extern object[] GetCustomAttributesInternal (ICustomAttributeProvider obj, Type attributeType, bool pseudoAttrs);
72 internal static object[] GetPseudoCustomAttributes (ICustomAttributeProvider obj, Type attributeType) {
73 object[] pseudoAttrs = null;
75 /* FIXME: Add other types */
76 if (obj is MonoMethod)
77 pseudoAttrs = ((MonoMethod)obj).GetPseudoCustomAttributes ();
78 else if (obj is FieldInfo)
79 pseudoAttrs = ((FieldInfo)obj).GetPseudoCustomAttributes ();
80 else if (obj is ParameterInfo)
81 pseudoAttrs = ((ParameterInfo)obj).GetPseudoCustomAttributes ();
83 pseudoAttrs = GetPseudoCustomAttributes (((Type)obj));
85 if ((attributeType != null) && (pseudoAttrs != null)) {
86 for (int i = 0; i < pseudoAttrs.Length; ++i)
87 if (attributeType.IsAssignableFrom (pseudoAttrs [i].GetType ()))
88 if (pseudoAttrs.Length == 1)
91 return new object [] { pseudoAttrs [i] };
92 return EmptyArray<object>.Value;
98 static object[] GetPseudoCustomAttributes (Type type)
101 var Attributes = type.Attributes;
103 /* IsSerializable returns true for delegates/enums as well */
104 if ((Attributes & TypeAttributes.Serializable) != 0)
106 if ((Attributes & TypeAttributes.Import) != 0)
111 object[] attrs = new object [count];
114 if ((Attributes & TypeAttributes.Serializable) != 0)
115 attrs [count ++] = new SerializableAttribute ();
116 if ((Attributes & TypeAttributes.Import) != 0)
117 attrs [count ++] = new ComImportAttribute ();
122 internal static object[] GetCustomAttributesBase (ICustomAttributeProvider obj, Type attributeType, bool inheritedOnly)
125 if (IsUserCattrProvider (obj))
126 attrs = obj.GetCustomAttributes (attributeType, true);
128 attrs = GetCustomAttributesInternal (obj, attributeType, false);
131 // All pseudo custom attributes are Inherited = false hence we can avoid
132 // building attributes array which would be discarded by inherited checks
134 if (!inheritedOnly) {
135 object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
136 if (pseudoAttrs != null) {
137 object[] res = new object [attrs.Length + pseudoAttrs.Length];
138 System.Array.Copy (attrs, res, attrs.Length);
139 System.Array.Copy (pseudoAttrs, 0, res, attrs.Length, pseudoAttrs.Length);
147 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
151 object[] res = GetCustomAttributes (obj, attributeType, inherit);
156 else if (res.Length > 1)
158 string msg = "'{0}' has more than one attribute of type '{1}";
159 msg = String.Format (msg, obj, attributeType);
160 throw new AmbiguousMatchException (msg);
163 return (Attribute) res[0];
166 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
169 throw new ArgumentNullException ("obj");
170 if (attributeType == null)
171 throw new ArgumentNullException ("attributeType");
173 if (attributeType == typeof (MonoCustomAttrs))
174 attributeType = null;
177 object[] res = GetCustomAttributesBase (obj, attributeType, false);
179 if (!inherit && res.Length == 1) {
181 throw new CustomAttributeFormatException ("Invalid custom attribute format");
183 if (attributeType != null) {
184 if (attributeType.IsAssignableFrom (res[0].GetType ())) {
185 r = (object[]) Array.CreateInstance (attributeType, 1);
188 r = (object[]) Array.CreateInstance (attributeType, 0);
191 r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
197 if (inherit && GetBase (obj) == null)
200 // if AttributeType is sealed, and Inherited is set to false, then
201 // there's no use in scanning base types
202 if ((attributeType != null && attributeType.IsSealed) && inherit) {
203 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
205 if (!usageAttribute.Inherited)
209 var initialSize = Math.Max (res.Length, 16);
210 List<Object> a = null;
211 ICustomAttributeProvider btype = obj;
214 /* Non-inherit case */
216 if (attributeType == null) {
217 foreach (object attr in res) {
219 throw new CustomAttributeFormatException ("Invalid custom attribute format");
221 var result = new Attribute [res.Length];
222 res.CopyTo (result, 0);
226 a = new List<object> (initialSize);
227 foreach (object attr in res) {
229 throw new CustomAttributeFormatException ("Invalid custom attribute format");
231 Type attrType = attr.GetType ();
232 if (attributeType != null && !attributeType.IsAssignableFrom (attrType))
237 if (attributeType == null || attributeType.IsValueType)
238 array = new Attribute [a.Count];
240 array = Array.CreateInstance (attributeType, a.Count) as object[];
246 var attributeInfos = new Dictionary<Type, AttributeInfo> (initialSize);
247 int inheritanceLevel = 0;
248 a = new List<object> (initialSize);
251 foreach (object attr in res) {
252 AttributeUsageAttribute usage;
254 throw new CustomAttributeFormatException ("Invalid custom attribute format");
256 Type attrType = attr.GetType ();
257 if (attributeType != null) {
258 if (!attributeType.IsAssignableFrom (attrType))
262 AttributeInfo firstAttribute;
263 if (attributeInfos.TryGetValue (attrType, out firstAttribute))
264 usage = firstAttribute.Usage;
266 usage = RetrieveAttributeUsage (attrType);
268 // only add attribute to the list of attributes if
269 // - we are on the first inheritance level, or the attribute can be inherited anyway
271 // - multiple attributes of the type are allowed
273 // - this is the first attribute we've discovered
275 // - the attribute is on same inheritance level than the first
276 // attribute that was discovered for this attribute type ))
277 if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple ||
278 (firstAttribute == null || (firstAttribute != null
279 && firstAttribute.InheritanceLevel == inheritanceLevel))))
282 if (firstAttribute == null)
283 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
286 if ((btype = GetBase (btype)) != null) {
288 res = GetCustomAttributesBase (btype, attributeType, true);
290 } while (inherit && btype != null);
292 if (attributeType == null || attributeType.IsValueType)
293 array = new Attribute [a.Count];
295 array = Array.CreateInstance (attributeType, a.Count) as object[];
297 // copy attributes to array
303 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
306 throw new ArgumentNullException ("obj");
309 return (object[]) GetCustomAttributesBase (obj, null, false).Clone ();
311 return GetCustomAttributes (obj, typeof (MonoCustomAttrs), inherit);
314 [MethodImplAttribute (MethodImplOptions.InternalCall)]
315 static extern CustomAttributeData [] GetCustomAttributesDataInternal (ICustomAttributeProvider obj);
317 internal static IList<CustomAttributeData> GetCustomAttributesData (ICustomAttributeProvider obj)
320 throw new ArgumentNullException ("obj");
322 CustomAttributeData [] attrs = GetCustomAttributesDataInternal (obj);
323 return Array.AsReadOnly<CustomAttributeData> (attrs);
326 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
328 if (attributeType == null)
329 throw new ArgumentNullException ("attributeType");
331 AttributeUsageAttribute usage = null;
333 if (IsUserCattrProvider (obj))
334 return obj.IsDefined (attributeType, inherit);
336 if (IsDefinedInternal (obj, attributeType))
339 object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
340 if (pseudoAttrs != null) {
341 for (int i = 0; i < pseudoAttrs.Length; ++i)
342 if (attributeType.IsAssignableFrom (pseudoAttrs[i].GetType ()))
350 usage = RetrieveAttributeUsage (attributeType);
351 if (!usage.Inherited)
356 } while (obj != null);
361 [MethodImplAttribute (MethodImplOptions.InternalCall)]
362 internal static extern bool IsDefinedInternal (ICustomAttributeProvider obj, Type AttributeType);
364 static PropertyInfo GetBasePropertyDefinition (MonoProperty property)
366 MethodInfo method = property.GetGetMethod (true);
367 if (method == null || !method.IsVirtual)
368 method = property.GetSetMethod (true);
369 if (method == null || !method.IsVirtual)
372 MethodInfo baseMethod = method.GetBaseMethod ();
373 if (baseMethod != null && baseMethod != method) {
374 ParameterInfo[] parameters = property.GetIndexParameters ();
375 if (parameters != null && parameters.Length > 0) {
376 Type[] paramTypes = new Type[parameters.Length];
377 for (int i=0; i < paramTypes.Length; i++)
378 paramTypes[i] = parameters[i].ParameterType;
379 return baseMethod.DeclaringType.GetProperty (property.Name, property.PropertyType,
382 return baseMethod.DeclaringType.GetProperty (property.Name, property.PropertyType);
389 static EventInfo GetBaseEventDefinition (MonoEvent evt)
391 MethodInfo method = evt.GetAddMethod (true);
392 if (method == null || !method.IsVirtual)
393 method = evt.GetRaiseMethod (true);
394 if (method == null || !method.IsVirtual)
395 method = evt.GetRemoveMethod (true);
396 if (method == null || !method.IsVirtual)
399 MethodInfo baseMethod = method.GetBaseMethod ();
400 if (baseMethod != null && baseMethod != method) {
401 BindingFlags flags = method.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
402 flags |= method.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
404 return baseMethod.DeclaringType.GetEvent (evt.Name, flags);
409 // Handles Type, MonoProperty and MonoMethod.
410 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
411 // but for those we return null here.
412 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
418 return ((Type) obj).BaseType;
420 MethodInfo method = null;
421 if (obj is MonoProperty)
422 return GetBasePropertyDefinition ((MonoProperty) obj);
423 else if (obj is MonoEvent)
424 return GetBaseEventDefinition ((MonoEvent)obj);
425 else if (obj is MonoMethod)
426 method = (MethodInfo) obj;
429 * ParameterInfo -> null
434 if (method == null || !method.IsVirtual)
437 MethodInfo baseMethod = method.GetBaseMethod ();
438 if (baseMethod == method)
444 private static AttributeUsageAttribute RetrieveAttributeUsageNoCache (Type attributeType)
446 if (attributeType == typeof (AttributeUsageAttribute))
447 /* Avoid endless recursion */
448 return new AttributeUsageAttribute (AttributeTargets.Class);
450 AttributeUsageAttribute usageAttribute = null;
451 object[] attribs = GetCustomAttributes (attributeType, typeof(AttributeUsageAttribute), false);
452 if (attribs.Length == 0)
454 // if no AttributeUsage was defined on the attribute level, then
455 // try to retrieve if from its base type
456 if (attributeType.BaseType != null)
458 usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
461 if (usageAttribute != null)
463 // return AttributeUsage of base class
464 return usageAttribute;
467 // return default AttributeUsageAttribute if no AttributeUsage
468 // was defined on attribute, or its base class
469 return DefaultAttributeUsage;
471 // check if more than one AttributeUsageAttribute has been specified
473 // NOTE: compilers should prevent this, but that doesn't prevent
474 // anyone from using IL ofcourse
475 if (attribs.Length > 1)
477 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
480 return ((AttributeUsageAttribute) attribs[0]);
483 static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
485 AttributeUsageAttribute usageAttribute = null;
486 /* Usage a thread-local cache to speed this up, since it is called a lot from GetCustomAttributes () */
487 if (usage_cache == null)
488 usage_cache = new Dictionary<Type, AttributeUsageAttribute> ();
489 if (usage_cache.TryGetValue (attributeType, out usageAttribute))
490 return usageAttribute;
491 usageAttribute = RetrieveAttributeUsageNoCache (attributeType);
492 usage_cache [attributeType] = usageAttribute;
493 return usageAttribute;
496 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
497 new AttributeUsageAttribute (AttributeTargets.All);
499 private class AttributeInfo
501 private AttributeUsageAttribute _usage;
502 private int _inheritanceLevel;
504 public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
507 _inheritanceLevel = inheritanceLevel;
510 public AttributeUsageAttribute Usage
518 public int InheritanceLevel
522 return _inheritanceLevel;