1 // System.MonoCustomAttrs.cs
2 // Hooks into the runtime to get custom attributes for reflection handles
5 // Paolo Molaro (lupus@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Reflection;
36 using System.Collections;
37 using System.Runtime.CompilerServices;
40 using System.Collections.Generic;
45 internal class MonoCustomAttrs
47 [MethodImplAttribute (MethodImplOptions.InternalCall)]
48 internal static extern object[] GetCustomAttributesInternal (ICustomAttributeProvider obj, Type attributeType, bool pseudoAttrs);
50 internal static object[] GetPseudoCustomAttributes (ICustomAttributeProvider obj, Type attributeType) {
51 #if NET_2_0 || BOOTSTRAP_NET_2_0
52 object[] pseudoAttrs = null;
54 /* FIXME: Add other types */
55 if (obj is MonoMethod)
56 pseudoAttrs = ((MonoMethod)obj).GetPseudoCustomAttributes ();
57 else if (obj is FieldInfo)
58 pseudoAttrs = ((FieldInfo)obj).GetPseudoCustomAttributes ();
59 else if (obj is ParameterInfo)
60 pseudoAttrs = ((ParameterInfo)obj).GetPseudoCustomAttributes ();
62 pseudoAttrs = ((Type)obj).GetPseudoCustomAttributes ();
64 if ((attributeType != null) && (pseudoAttrs != null)) {
65 for (int i = 0; i < pseudoAttrs.Length; ++i)
66 if (attributeType.IsAssignableFrom (pseudoAttrs [i].GetType ()))
67 if (pseudoAttrs.Length == 1)
70 return new object [] { pseudoAttrs [i] };
71 return new object [0];
80 internal static object[] GetCustomAttributesBase (ICustomAttributeProvider obj, Type attributeType)
82 object[] attrs = GetCustomAttributesInternal (obj, attributeType, false);
84 object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
85 if (pseudoAttrs != null) {
86 object[] res = new object [attrs.Length + pseudoAttrs.Length];
87 System.Array.Copy (attrs, res, attrs.Length);
88 System.Array.Copy (pseudoAttrs, 0, res, attrs.Length, pseudoAttrs.Length);
95 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
99 object[] res = GetCustomAttributes (obj, attributeType, inherit);
104 else if (res.Length > 1)
106 string msg = "'{0}' has more than one attribute of type '{1}";
107 msg = String.Format (msg, obj, attributeType);
108 throw new AmbiguousMatchException (msg);
111 return (Attribute) res[0];
114 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
117 throw new ArgumentNullException ("obj");
120 object[] res = GetCustomAttributesBase (obj, attributeType);
122 if (!inherit && res.Length == 1)
124 if (attributeType != null)
126 if (attributeType.IsAssignableFrom (res[0].GetType ()))
128 r = (object[]) Array.CreateInstance (attributeType, 1);
133 r = (object[]) Array.CreateInstance (attributeType, 0);
138 r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
144 // if AttributeType is sealed, and Inherited is set to false, then
145 // there's no use in scanning base types
146 if ((attributeType != null && attributeType.IsSealed) && inherit)
148 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
150 if (!usageAttribute.Inherited)
156 int initialSize = res.Length < 16 ? res.Length : 16;
158 Hashtable attributeInfos = new Hashtable (initialSize);
159 ArrayList a = new ArrayList (initialSize);
160 ICustomAttributeProvider btype = obj;
162 int inheritanceLevel = 0;
166 foreach (object attr in res)
168 AttributeUsageAttribute usage;
170 Type attrType = attr.GetType ();
171 if (attributeType != null)
173 if (!attributeType.IsAssignableFrom (attrType))
179 AttributeInfo firstAttribute = (AttributeInfo) attributeInfos[attrType];
180 if (firstAttribute != null)
182 usage = firstAttribute.Usage;
186 usage = RetrieveAttributeUsage (attrType);
189 // only add attribute to the list of attributes if
190 // - we are on the first inheritance level, or the attribute can be inherited anyway
192 // - multiple attributes of the type are allowed
194 // - this is the first attribute we've discovered
196 // - the attribute is on same inheritance level than the first
197 // attribute that was discovered for this attribute type ))
198 if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple ||
199 (firstAttribute == null || (firstAttribute != null
200 && firstAttribute.InheritanceLevel == inheritanceLevel))))
205 if (firstAttribute == null)
207 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
211 if ((btype = GetBase (btype)) != null)
214 res = GetCustomAttributesBase (btype, attributeType);
216 } while (inherit && btype != null);
218 object[] array = null;
219 if (attributeType == null || attributeType.IsValueType)
221 array = (object[]) Array.CreateInstance (typeof(Attribute), a.Count);
225 array = Array.CreateInstance (attributeType, a.Count) as object[];
228 // copy attributes to array
234 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
237 throw new ArgumentNullException ("obj");
240 return (object[]) GetCustomAttributesBase (obj, null).Clone ();
242 return GetCustomAttributes (obj, null, inherit);
246 [MethodImplAttribute (MethodImplOptions.InternalCall)]
247 static extern CustomAttributeData [] GetCustomAttributesDataInternal (ICustomAttributeProvider obj);
249 internal static IList<CustomAttributeData> GetCustomAttributesData (ICustomAttributeProvider obj)
252 throw new ArgumentNullException ("obj");
254 CustomAttributeData [] attrs = GetCustomAttributesDataInternal (obj);
255 return Array.AsReadOnly<CustomAttributeData> (attrs);
259 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
261 if (attributeType == null)
262 throw new ArgumentNullException ("attributeType");
264 if (obj.GetType ().Assembly != typeof (int).Assembly)
265 // User types might overwrite GetCustomAttributes () but not
267 return obj.GetCustomAttributes (attributeType, inherit).Length > 0;
269 if (IsDefinedInternal (obj, attributeType))
272 object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
273 if (pseudoAttrs != null) {
274 for (int i = 0; i < pseudoAttrs.Length; ++i)
275 if (attributeType.IsAssignableFrom (pseudoAttrs [i].GetType ()))
281 AttributeUsageAttribute usage = RetrieveAttributeUsage (attributeType);
282 if (!usage.Inherited)
287 // FIXME (bug #82431):
288 // on 2.0 profile we should always walk the inheritance
289 // chain and base the behavior on the inheritance level:
291 // 0 : return true if "attributeType" is assignable from
292 // any of the custom attributes
294 // > 0: return true if "attributeType" is assignable from
295 // any of the custom attributes and AttributeUsageAttribute
296 // .Inherited of the assignable attribute is true
298 ICustomAttributeProvider btype;
299 if (inherit && ((btype = GetBase (obj)) != null))
300 return IsDefined (btype, attributeType, inherit);
305 [MethodImplAttribute (MethodImplOptions.InternalCall)]
306 internal static extern bool IsDefinedInternal (ICustomAttributeProvider obj, Type AttributeType);
308 // Handles Type, MonoProperty and MonoMethod.
309 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
310 // but for those we return null here.
311 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
317 return ((Type) obj).BaseType;
319 MethodInfo method = null;
320 if (obj is MonoProperty)
322 MonoProperty prop = (MonoProperty) obj;
323 method = prop.GetGetMethod (true);
325 method = prop.GetSetMethod (true);
327 MonoProperty prop = (MonoProperty) obj;
328 if (prop.DeclaringType.BaseType != null) {
329 PropertyInfo baseProp = prop.DeclaringType.BaseType.GetProperty (prop.Name);
330 if (baseProp != prop)
336 else if (obj is MonoMethod)
338 method = (MethodInfo) obj;
342 * ParameterInfo -> null
347 if (method == null || !method.IsVirtual)
350 MethodInfo baseMethod = method.GetBaseDefinition ();
351 if (baseMethod == method)
357 private static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
359 if (attributeType == typeof (AttributeUsageAttribute))
360 /* Avoid endless recursion */
361 return new AttributeUsageAttribute (AttributeTargets.Class);
363 AttributeUsageAttribute usageAttribute = null;
364 object[] attribs = GetCustomAttributes (attributeType,
365 MonoCustomAttrs.AttributeUsageType, false);
366 if (attribs.Length == 0)
368 // if no AttributeUsage was defined on the attribute level, then
369 // try to retrieve if from its base type
370 if (attributeType.BaseType != null)
372 usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
375 if (usageAttribute != null)
377 // return AttributeUsage of base class
378 return usageAttribute;
381 // return default AttributeUsageAttribute if no AttributeUsage
382 // was defined on attribute, or its base class
383 return DefaultAttributeUsage;
385 // check if more than one AttributeUsageAttribute has been specified
387 // NOTE: compilers should prevent this, but that doesn't prevent
388 // anyone from using IL ofcourse
389 if (attribs.Length > 1)
391 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
394 return ((AttributeUsageAttribute) attribs[0]);
397 private static readonly Type AttributeUsageType = typeof(AttributeUsageAttribute);
398 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
399 new AttributeUsageAttribute (AttributeTargets.All);
401 private class AttributeInfo
403 private AttributeUsageAttribute _usage;
404 private int _inheritanceLevel;
406 public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
409 _inheritanceLevel = inheritanceLevel;
412 public AttributeUsageAttribute Usage
420 public int InheritanceLevel
424 return _inheritanceLevel;