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;
41 internal class MonoCustomAttrs
43 #if NET_2_0 || BOOTSTRAP_NET_2_0
44 internal static readonly bool pseudoAttrs = true;
46 internal static readonly bool pseudoAttrs = false;
49 [MethodImplAttribute (MethodImplOptions.InternalCall)]
50 internal static extern object[] GetCustomAttributesInternal (ICustomAttributeProvider obj, bool pseudoAttrs);
52 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
56 object[] res = GetCustomAttributes (obj, attributeType, inherit);
61 else if (res.Length > 1)
63 string msg = "'{0}' has more than one attribute of type '{1}";
64 msg = String.Format (msg, obj, attributeType);
65 throw new AmbiguousMatchException (msg);
68 return (Attribute) res[0];
71 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
74 throw new ArgumentNullException ("obj");
77 object[] res = GetCustomAttributesInternal (obj, pseudoAttrs);
79 if (!inherit && res.Length == 1)
81 if (attributeType != null)
83 if (attributeType.IsAssignableFrom (res[0].GetType ()))
85 r = (object[]) Array.CreateInstance (attributeType, 1);
90 r = (object[]) Array.CreateInstance (attributeType, 0);
95 r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
101 // if AttributeType is sealed, and Inherited is set to false, then
102 // there's no use in scanning base types
103 if ((attributeType != null && attributeType.IsSealed) && !inherit)
105 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
107 if (!usageAttribute.Inherited)
113 int initialSize = res.Length < 16 ? res.Length : 16;
115 Hashtable attributeInfos = new Hashtable (initialSize);
116 ArrayList a = new ArrayList (initialSize);
117 ICustomAttributeProvider btype = obj;
119 int inheritanceLevel = 0;
123 foreach (object attr in res)
125 AttributeUsageAttribute usage;
127 Type attrType = attr.GetType ();
128 if (attributeType != null)
130 if (!attributeType.IsAssignableFrom (attrType))
136 AttributeInfo firstAttribute = (AttributeInfo) attributeInfos[attrType];
137 if (firstAttribute != null)
139 usage = firstAttribute.Usage;
143 usage = RetrieveAttributeUsage (attrType);
146 // only add attribute to the list of attributes if
147 // - we are on the first inheritance level, or the attribute can be inherited anyway
149 // - multiple attributes of the type are allowed
151 // - this is the first attribute we've discovered
153 // - the attribute is on same inheritance level than the first
154 // attribute that was discovered for this attribute type ))
155 if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple ||
156 (firstAttribute == null || (firstAttribute != null
157 && firstAttribute.InheritanceLevel == inheritanceLevel))))
162 if (firstAttribute == null)
164 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
168 if ((btype = GetBase (btype)) != null)
171 res = GetCustomAttributesInternal (btype, pseudoAttrs);
173 } while (inherit && btype != null);
175 object[] array = null;
176 if (attributeType == null || attributeType.IsValueType)
178 array = (object[]) Array.CreateInstance (typeof(Attribute), a.Count);
182 array = Array.CreateInstance (attributeType, a.Count) as object[];
185 // copy attributes to array
191 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
194 throw new ArgumentNullException ("obj");
197 return (object[]) GetCustomAttributesInternal (obj, pseudoAttrs).Clone ();
199 return GetCustomAttributes (obj, null, inherit);
202 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
204 object [] res = GetCustomAttributesInternal (obj, pseudoAttrs);
205 foreach (object attr in res)
206 if (attributeType.Equals (attr.GetType ()))
209 ICustomAttributeProvider btype;
210 if (inherit && ((btype = GetBase (obj)) != null))
211 return IsDefined (btype, attributeType, inherit);
216 // Handles Type, MonoProperty and MonoMethod.
217 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
218 // but for those we return null here.
219 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
225 return ((Type) obj).BaseType;
227 MethodInfo method = null;
228 if (obj is MonoProperty)
230 MonoProperty prop = (MonoProperty) obj;
231 method = prop.GetGetMethod (true);
233 method = prop.GetSetMethod (true);
235 else if (obj is MonoMethod)
237 method = (MethodInfo) obj;
241 * ParameterInfo -> null
246 if (method == null || !method.IsVirtual)
249 MethodInfo baseMethod = method.GetBaseDefinition ();
250 if (baseMethod == method)
256 private static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
258 AttributeUsageAttribute usageAttribute = null;
259 object[] attribs = GetCustomAttributes (attributeType,
260 MonoCustomAttrs.AttributeUsageType, false);
261 if (attribs.Length == 0)
263 // if no AttributeUsage was defined on the attribute level, then
264 // try to retrieve if from its base type
265 if (attributeType.BaseType != null)
267 usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
270 if (usageAttribute != null)
272 // return AttributeUsage of base class
273 return usageAttribute;
276 // return default AttributeUsageAttribute if no AttributeUsage
277 // was defined on attribute, or its base class
278 return DefaultAttributeUsage;
280 // check if more than one AttributeUsageAttribute has been specified
282 // NOTE: compilers should prevent this, but that doesn't prevent
283 // anyone from using IL ofcourse
284 if (attribs.Length > 1)
286 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
289 return ((AttributeUsageAttribute) attribs[0]);
292 private static readonly Type AttributeUsageType = typeof(AttributeUsageAttribute);
293 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
294 new AttributeUsageAttribute (AttributeTargets.All);
296 private class AttributeInfo
298 private AttributeUsageAttribute _usage;
299 private int _inheritanceLevel;
301 public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
304 _inheritanceLevel = inheritanceLevel;
307 public AttributeUsageAttribute Usage
315 public int InheritanceLevel
319 return _inheritanceLevel;