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;
38 using System.Reflection.Emit;
39 using System.Collections.Generic;
43 internal class MonoCustomAttrs
45 static Assembly corlib;
47 /* Treat as user types all corlib types extending System.Type that are not MonoType and TypeBuilder */
48 static bool IsUserCattrProvider (object obj)
50 Type type = obj as Type;
51 if ((type is MonoType) || (type is TypeBuilder))
56 corlib = typeof (int).Assembly;
57 return obj.GetType ().Assembly != corlib;
60 [MethodImplAttribute (MethodImplOptions.InternalCall)]
61 internal static extern object[] GetCustomAttributesInternal (ICustomAttributeProvider obj, Type attributeType, bool pseudoAttrs);
63 internal static object[] GetPseudoCustomAttributes (ICustomAttributeProvider obj, Type attributeType) {
64 object[] pseudoAttrs = null;
66 /* FIXME: Add other types */
67 if (obj is MonoMethod)
68 pseudoAttrs = ((MonoMethod)obj).GetPseudoCustomAttributes ();
69 else if (obj is FieldInfo)
70 pseudoAttrs = ((FieldInfo)obj).GetPseudoCustomAttributes ();
71 else if (obj is ParameterInfo)
72 pseudoAttrs = ((ParameterInfo)obj).GetPseudoCustomAttributes ();
74 pseudoAttrs = ((Type)obj).GetPseudoCustomAttributes ();
76 if ((attributeType != null) && (pseudoAttrs != null)) {
77 for (int i = 0; i < pseudoAttrs.Length; ++i)
78 if (attributeType.IsAssignableFrom (pseudoAttrs [i].GetType ()))
79 if (pseudoAttrs.Length == 1)
82 return new object [] { pseudoAttrs [i] };
83 return new object [0];
89 internal static object[] GetCustomAttributesBase (ICustomAttributeProvider obj, Type attributeType)
92 if (IsUserCattrProvider (obj))
93 attrs = obj.GetCustomAttributes (attributeType, true);
95 attrs = GetCustomAttributesInternal (obj, attributeType, false);
97 object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
98 if (pseudoAttrs != null) {
99 object[] res = new object [attrs.Length + pseudoAttrs.Length];
100 System.Array.Copy (attrs, res, attrs.Length);
101 System.Array.Copy (pseudoAttrs, 0, res, attrs.Length, pseudoAttrs.Length);
108 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
112 object[] res = GetCustomAttributes (obj, attributeType, inherit);
117 else if (res.Length > 1)
119 string msg = "'{0}' has more than one attribute of type '{1}";
120 msg = String.Format (msg, obj, attributeType);
121 throw new AmbiguousMatchException (msg);
124 return (Attribute) res[0];
127 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
130 throw new ArgumentNullException ("obj");
131 if (attributeType == null)
132 throw new ArgumentNullException ("attributeType");
134 if (attributeType == typeof (MonoCustomAttrs))
135 attributeType = null;
138 object[] res = GetCustomAttributesBase (obj, attributeType);
140 if (!inherit && res.Length == 1)
143 throw new CustomAttributeFormatException ("Invalid custom attribute format");
145 if (attributeType != null)
147 if (attributeType.IsAssignableFrom (res[0].GetType ()))
149 r = (object[]) Array.CreateInstance (attributeType, 1);
154 r = (object[]) Array.CreateInstance (attributeType, 0);
159 r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
165 // if AttributeType is sealed, and Inherited is set to false, then
166 // there's no use in scanning base types
167 if ((attributeType != null && attributeType.IsSealed) && inherit)
169 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
171 if (!usageAttribute.Inherited)
177 int initialSize = res.Length < 16 ? res.Length : 16;
179 Hashtable attributeInfos = new Hashtable (initialSize);
180 ArrayList a = new ArrayList (initialSize);
181 ICustomAttributeProvider btype = obj;
183 int inheritanceLevel = 0;
187 foreach (object attr in res)
189 AttributeUsageAttribute usage;
191 throw new CustomAttributeFormatException ("Invalid custom attribute format");
193 Type attrType = attr.GetType ();
194 if (attributeType != null)
196 if (!attributeType.IsAssignableFrom (attrType))
202 AttributeInfo firstAttribute = (AttributeInfo) attributeInfos[attrType];
203 if (firstAttribute != null)
205 usage = firstAttribute.Usage;
209 usage = RetrieveAttributeUsage (attrType);
212 // only add attribute to the list of attributes if
213 // - we are on the first inheritance level, or the attribute can be inherited anyway
215 // - multiple attributes of the type are allowed
217 // - this is the first attribute we've discovered
219 // - the attribute is on same inheritance level than the first
220 // attribute that was discovered for this attribute type ))
221 if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple ||
222 (firstAttribute == null || (firstAttribute != null
223 && firstAttribute.InheritanceLevel == inheritanceLevel))))
228 if (firstAttribute == null)
230 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
234 if ((btype = GetBase (btype)) != null)
237 res = GetCustomAttributesBase (btype, attributeType);
239 } while (inherit && btype != null);
241 object[] array = null;
242 if (attributeType == null || attributeType.IsValueType)
244 array = (object[]) Array.CreateInstance (typeof(Attribute), a.Count);
248 array = Array.CreateInstance (attributeType, a.Count) as object[];
251 // copy attributes to array
257 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
260 throw new ArgumentNullException ("obj");
263 return (object[]) GetCustomAttributesBase (obj, null).Clone ();
265 return GetCustomAttributes (obj, typeof (MonoCustomAttrs), inherit);
268 [MethodImplAttribute (MethodImplOptions.InternalCall)]
269 static extern CustomAttributeData [] GetCustomAttributesDataInternal (ICustomAttributeProvider obj);
271 internal static IList<CustomAttributeData> GetCustomAttributesData (ICustomAttributeProvider obj)
274 throw new ArgumentNullException ("obj");
276 CustomAttributeData [] attrs = GetCustomAttributesDataInternal (obj);
277 return Array.AsReadOnly<CustomAttributeData> (attrs);
280 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
282 if (attributeType == null)
283 throw new ArgumentNullException ("attributeType");
285 AttributeUsageAttribute usage = null;
287 if (IsUserCattrProvider (obj))
288 return obj.IsDefined (attributeType, inherit);
290 if (IsDefinedInternal (obj, attributeType))
293 object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
294 if (pseudoAttrs != null) {
295 for (int i = 0; i < pseudoAttrs.Length; ++i)
296 if (attributeType.IsAssignableFrom (pseudoAttrs[i].GetType ()))
304 usage = RetrieveAttributeUsage (attributeType);
305 if (!usage.Inherited)
310 } while (obj != null);
315 [MethodImplAttribute (MethodImplOptions.InternalCall)]
316 internal static extern bool IsDefinedInternal (ICustomAttributeProvider obj, Type AttributeType);
318 static PropertyInfo GetBasePropertyDefinition (PropertyInfo property)
320 MethodInfo method = property.GetGetMethod (true);
321 if (method == null || !method.IsVirtual)
322 method = property.GetSetMethod (true);
323 if (method == null || !method.IsVirtual)
326 MethodInfo baseMethod = method.GetBaseMethod ();
327 if (baseMethod != null && baseMethod != method) {
328 ParameterInfo[] parameters = property.GetIndexParameters ();
329 if (parameters != null && parameters.Length > 0) {
330 Type[] paramTypes = new Type[parameters.Length];
331 for (int i=0; i < paramTypes.Length; i++)
332 paramTypes[i] = parameters[i].ParameterType;
333 return baseMethod.DeclaringType.GetProperty (property.Name, property.PropertyType,
336 return baseMethod.DeclaringType.GetProperty (property.Name, property.PropertyType);
343 static EventInfo GetBaseEventDefinition (EventInfo evt)
345 MethodInfo method = evt.GetAddMethod (true);
346 if (method == null || !method.IsVirtual)
347 method = evt.GetRaiseMethod (true);
348 if (method == null || !method.IsVirtual)
349 method = evt.GetRemoveMethod (true);
350 if (method == null || !method.IsVirtual)
353 MethodInfo baseMethod = method.GetBaseMethod ();
354 if (baseMethod != null && baseMethod != method) {
355 BindingFlags flags = method.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
356 flags |= method.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
358 return baseMethod.DeclaringType.GetEvent (evt.Name, flags);
363 // Handles Type, MonoProperty and MonoMethod.
364 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
365 // but for those we return null here.
366 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
372 return ((Type) obj).BaseType;
374 MethodInfo method = null;
375 if (obj is MonoProperty)
376 return GetBasePropertyDefinition ((MonoProperty) obj);
377 else if (obj is MonoEvent)
378 return GetBaseEventDefinition ((MonoEvent)obj);
379 else if (obj is MonoMethod)
380 method = (MethodInfo) obj;
383 * ParameterInfo -> null
388 if (method == null || !method.IsVirtual)
391 MethodInfo baseMethod = method.GetBaseMethod ();
392 if (baseMethod == method)
398 private static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
400 if (attributeType == typeof (AttributeUsageAttribute))
401 /* Avoid endless recursion */
402 return new AttributeUsageAttribute (AttributeTargets.Class);
404 AttributeUsageAttribute usageAttribute = null;
405 object[] attribs = GetCustomAttributes (attributeType,
406 MonoCustomAttrs.AttributeUsageType, false);
407 if (attribs.Length == 0)
409 // if no AttributeUsage was defined on the attribute level, then
410 // try to retrieve if from its base type
411 if (attributeType.BaseType != null)
413 usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
416 if (usageAttribute != null)
418 // return AttributeUsage of base class
419 return usageAttribute;
422 // return default AttributeUsageAttribute if no AttributeUsage
423 // was defined on attribute, or its base class
424 return DefaultAttributeUsage;
426 // check if more than one AttributeUsageAttribute has been specified
428 // NOTE: compilers should prevent this, but that doesn't prevent
429 // anyone from using IL ofcourse
430 if (attribs.Length > 1)
432 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
435 return ((AttributeUsageAttribute) attribs[0]);
438 private static readonly Type AttributeUsageType = typeof(AttributeUsageAttribute);
439 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
440 new AttributeUsageAttribute (AttributeTargets.All);
442 private class AttributeInfo
444 private AttributeUsageAttribute _usage;
445 private int _inheritanceLevel;
447 public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
450 _inheritanceLevel = inheritanceLevel;
453 public AttributeUsageAttribute Usage
461 public int InheritanceLevel
465 return _inheritanceLevel;