**** Merged from MCS ****
[mono-project.git] / mcs / class / corlib / System / MonoCustomAttrs.cs
blob4a00d26446edf57982764e80cbab879c37522208
1 // System.MonoCustomAttrs.cs
2 // Hooks into the runtime to get custom attributes for reflection handles
3 //
4 // Authors:
5 // Paolo Molaro (lupus@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
9 //
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:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
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.
34 using System;
35 using System.Reflection;
36 using System.Collections;
37 using System.Runtime.CompilerServices;
39 namespace System
41 internal class MonoCustomAttrs
43 [MethodImplAttribute (MethodImplOptions.InternalCall)]
44 internal static extern object[] GetCustomAttributesInternal (ICustomAttributeProvider obj, bool pseudoAttrs);
46 internal static object[] GetCustomAttributesBase (ICustomAttributeProvider obj)
48 object[] attrs = GetCustomAttributesInternal (obj, false);
50 #if NET_2_0 || BOOTSTRAP_NET_2_0
51 object[] pseudoAttrs = null;
53 /* FIXME: Add other types */
54 if (obj is Type)
55 pseudoAttrs = ((Type)obj).GetPseudoCustomAttributes ();
56 else if (obj is MonoMethod)
57 pseudoAttrs = ((MonoMethod)obj).GetPseudoCustomAttributes ();
58 else if (obj is FieldInfo)
59 pseudoAttrs = ((FieldInfo)obj).GetPseudoCustomAttributes ();
60 else if (obj is ParameterInfo)
61 pseudoAttrs = ((ParameterInfo)obj).GetPseudoCustomAttributes ();
63 if (pseudoAttrs != null) {
64 object[] res = new object [attrs.Length + pseudoAttrs.Length];
65 System.Array.Copy (attrs, res, attrs.Length);
66 System.Array.Copy (pseudoAttrs, 0, res, attrs.Length, pseudoAttrs.Length);
67 return res;
69 else
70 return attrs;
71 #else
72 return attrs;
73 #endif
76 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
77 Type attributeType,
78 bool inherit)
80 object[] res = GetCustomAttributes (obj, attributeType, inherit);
81 if (res.Length == 0)
83 return null;
85 else if (res.Length > 1)
87 string msg = "'{0}' has more than one attribute of type '{1}";
88 msg = String.Format (msg, obj, attributeType);
89 throw new AmbiguousMatchException (msg);
92 return (Attribute) res[0];
95 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
97 if (obj == null)
98 throw new ArgumentNullException ("obj");
100 object[] r;
101 object[] res = GetCustomAttributesBase (obj);
102 // shortcut
103 if (!inherit && res.Length == 1)
105 if (attributeType != null)
107 if (attributeType.IsAssignableFrom (res[0].GetType ()))
109 r = (object[]) Array.CreateInstance (attributeType, 1);
110 r[0] = res[0];
112 else
114 r = (object[]) Array.CreateInstance (attributeType, 0);
117 else
119 r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
120 r[0] = res[0];
122 return r;
125 // if AttributeType is sealed, and Inherited is set to false, then
126 // there's no use in scanning base types
127 if ((attributeType != null && attributeType.IsSealed) && inherit)
129 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
130 attributeType);
131 if (!usageAttribute.Inherited)
133 inherit = false;
137 int initialSize = res.Length < 16 ? res.Length : 16;
139 Hashtable attributeInfos = new Hashtable (initialSize);
140 ArrayList a = new ArrayList (initialSize);
141 ICustomAttributeProvider btype = obj;
143 int inheritanceLevel = 0;
147 foreach (object attr in res)
149 AttributeUsageAttribute usage;
151 Type attrType = attr.GetType ();
152 if (attributeType != null)
154 if (!attributeType.IsAssignableFrom (attrType))
156 continue;
160 AttributeInfo firstAttribute = (AttributeInfo) attributeInfos[attrType];
161 if (firstAttribute != null)
163 usage = firstAttribute.Usage;
165 else
167 usage = RetrieveAttributeUsage (attrType);
170 // only add attribute to the list of attributes if
171 // - we are on the first inheritance level, or the attribute can be inherited anyway
172 // and (
173 // - multiple attributes of the type are allowed
174 // or (
175 // - this is the first attribute we've discovered
176 // or
177 // - the attribute is on same inheritance level than the first
178 // attribute that was discovered for this attribute type ))
179 if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple ||
180 (firstAttribute == null || (firstAttribute != null
181 && firstAttribute.InheritanceLevel == inheritanceLevel))))
183 a.Add (attr);
186 if (firstAttribute == null)
188 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
192 if ((btype = GetBase (btype)) != null)
194 inheritanceLevel++;
195 res = GetCustomAttributesBase (btype);
197 } while (inherit && btype != null);
199 object[] array = null;
200 if (attributeType == null || attributeType.IsValueType)
202 array = (object[]) Array.CreateInstance (typeof(Attribute), a.Count);
204 else
206 array = Array.CreateInstance (attributeType, a.Count) as object[];
209 // copy attributes to array
210 a.CopyTo (array, 0);
212 return array;
215 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
217 if (obj == null)
218 throw new ArgumentNullException ("obj");
220 if (!inherit)
221 return (object[]) GetCustomAttributesBase (obj).Clone ();
223 return GetCustomAttributes (obj, null, inherit);
226 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
228 object [] res = GetCustomAttributesBase (obj);
229 foreach (object attr in res)
230 if (attributeType.Equals (attr.GetType ()))
231 return true;
233 ICustomAttributeProvider btype;
234 if (inherit && ((btype = GetBase (obj)) != null))
235 return IsDefined (btype, attributeType, inherit);
237 return false;
240 // Handles Type, MonoProperty and MonoMethod.
241 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
242 // but for those we return null here.
243 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
245 if (obj == null)
246 return null;
248 if (obj is Type)
249 return ((Type) obj).BaseType;
251 MethodInfo method = null;
252 if (obj is MonoProperty)
254 MonoProperty prop = (MonoProperty) obj;
255 method = prop.GetGetMethod (true);
256 if (method == null)
257 method = prop.GetSetMethod (true);
259 else if (obj is MonoMethod)
261 method = (MethodInfo) obj;
265 * ParameterInfo -> null
266 * Assembly -> null
267 * MonoEvent -> null
268 * MonoField -> null
270 if (method == null || !method.IsVirtual)
271 return null;
273 MethodInfo baseMethod = method.GetBaseDefinition ();
274 if (baseMethod == method)
275 return null;
277 return baseMethod;
280 private static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
282 if (attributeType == typeof (AttributeUsageAttribute))
283 /* Avoid endless recursion */
284 return new AttributeUsageAttribute (AttributeTargets.Class);
286 AttributeUsageAttribute usageAttribute = null;
287 object[] attribs = GetCustomAttributes (attributeType,
288 MonoCustomAttrs.AttributeUsageType, false);
289 if (attribs.Length == 0)
291 // if no AttributeUsage was defined on the attribute level, then
292 // try to retrieve if from its base type
293 if (attributeType.BaseType != null)
295 usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
298 if (usageAttribute != null)
300 // return AttributeUsage of base class
301 return usageAttribute;
304 // return default AttributeUsageAttribute if no AttributeUsage
305 // was defined on attribute, or its base class
306 return DefaultAttributeUsage;
308 // check if more than one AttributeUsageAttribute has been specified
309 // on the type
310 // NOTE: compilers should prevent this, but that doesn't prevent
311 // anyone from using IL ofcourse
312 if (attribs.Length > 1)
314 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
317 return ((AttributeUsageAttribute) attribs[0]);
320 private static readonly Type AttributeUsageType = typeof(AttributeUsageAttribute);
321 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
322 new AttributeUsageAttribute (AttributeTargets.All);
324 private class AttributeInfo
326 private AttributeUsageAttribute _usage;
327 private int _inheritanceLevel;
329 public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
331 _usage = usage;
332 _inheritanceLevel = inheritanceLevel;
335 public AttributeUsageAttribute Usage
339 return _usage;
343 public int InheritanceLevel
347 return _inheritanceLevel;