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 [MethodImplAttribute (MethodImplOptions.InternalCall)]
44 internal static extern object[] GetCustomAttributes (ICustomAttributeProvider obj);
46 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
50 object[] res = GetCustomAttributes (obj, attributeType, inherit);
55 else if (res.Length > 1)
57 string msg = "'{0}' has more than one attribute of type '{1}";
58 msg = String.Format (msg, obj, attributeType);
59 throw new AmbiguousMatchException (msg);
62 return (Attribute) res[0];
65 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
68 throw new ArgumentNullException ("obj");
71 object[] res = GetCustomAttributes (obj);
73 if (!inherit && res.Length == 1)
75 if (attributeType != null)
77 if (attributeType.IsAssignableFrom (res[0].GetType ()))
79 r = (object[]) Array.CreateInstance (attributeType, 1);
84 r = (object[]) Array.CreateInstance (attributeType, 0);
89 r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
95 // if AttributeType is sealed, and Inherited is set to false, then
96 // there's no use in scanning base types
97 if ((attributeType != null && attributeType.IsSealed) && !inherit)
99 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
101 if (!usageAttribute.Inherited)
107 int initialSize = res.Length < 16 ? res.Length : 16;
109 Hashtable attributeInfos = new Hashtable (initialSize);
110 ArrayList a = new ArrayList (initialSize);
111 ICustomAttributeProvider btype = obj;
113 int inheritanceLevel = 0;
117 foreach (object attr in res)
119 AttributeUsageAttribute usage;
121 Type attrType = attr.GetType ();
122 if (attributeType != null)
124 if (!attributeType.IsAssignableFrom (attrType))
130 AttributeInfo firstAttribute = (AttributeInfo) attributeInfos[attrType];
131 if (firstAttribute != null)
133 usage = firstAttribute.Usage;
137 usage = RetrieveAttributeUsage (attrType);
140 // only add attribute to the list of attributes if
141 // - we are on the first inheritance level, or the attribute can be inherited anyway
143 // - multiple attributes of the type are allowed
145 // - this is the first attribute we've discovered
147 // - the attribute is on same inheritance level than the first
148 // attribute that was discovered for this attribute type ))
149 if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple ||
150 (firstAttribute == null || (firstAttribute != null
151 && firstAttribute.InheritanceLevel == inheritanceLevel))))
156 if (firstAttribute == null)
158 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
162 if ((btype = GetBase (btype)) != null)
165 res = GetCustomAttributes (btype);
167 } while (inherit && btype != null);
169 object[] array = null;
170 if (attributeType == null || attributeType.IsValueType)
172 array = (object[]) Array.CreateInstance (typeof(Attribute), a.Count);
176 array = Array.CreateInstance (attributeType, a.Count) as object[];
179 // copy attributes to array
185 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
188 throw new ArgumentNullException ("obj");
191 return (object[]) GetCustomAttributes (obj).Clone ();
193 return GetCustomAttributes (obj, null, inherit);
196 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
198 object[] res = GetCustomAttributes (obj);
199 foreach (object attr in res)
201 if (attributeType.Equals (attr.GetType ()))
205 ICustomAttributeProvider btype = GetBase (obj);
206 if (inherit && (btype != null))
207 return IsDefined (btype, attributeType, inherit);
212 // Handles Type, MonoProperty and MonoMethod.
213 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
214 // but for those we return null here.
215 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
221 return ((Type) obj).BaseType;
223 MethodInfo method = null;
224 if (obj is MonoProperty)
226 MonoProperty prop = (MonoProperty) obj;
227 method = prop.GetGetMethod (true);
229 method = prop.GetSetMethod (true);
231 else if (obj is MonoMethod)
233 method = (MethodInfo) obj;
237 * ParameterInfo -> null
242 if (method == null || !method.IsVirtual)
245 MethodInfo baseMethod = method.GetBaseDefinition ();
246 if (baseMethod == method)
252 private static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
254 AttributeUsageAttribute usageAttribute = null;
255 object[] attribs = GetCustomAttributes (attributeType,
256 MonoCustomAttrs.AttributeUsageType, false);
257 if (attribs.Length == 0)
259 // if no AttributeUsage was defined on the attribute level, then
260 // try to retrieve if from its base type
261 if (attributeType.BaseType != null)
263 usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
266 if (usageAttribute != null)
268 // return AttributeUsage of base class
269 return usageAttribute;
272 // return default AttributeUsageAttribute if no AttributeUsage
273 // was defined on attribute, or its base class
274 return DefaultAttributeUsage;
276 // check if more than one AttributeUsageAttribute has been specified
278 // NOTE: compilers should prevent this, but that doesn't prevent
279 // anyone from using IL ofcourse
280 if (attribs.Length > 1)
282 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
285 return ((AttributeUsageAttribute) attribs[0]);
288 private static readonly Type AttributeUsageType = typeof(AttributeUsageAttribute);
289 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
290 new AttributeUsageAttribute (AttributeTargets.All);
292 private class AttributeInfo
294 private AttributeUsageAttribute _usage;
295 private int _inheritanceLevel;
297 public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
300 _inheritanceLevel = inheritanceLevel;
303 public AttributeUsageAttribute Usage
311 public int InheritanceLevel
315 return _inheritanceLevel;