Copied remotely
[mono.git] / mcs / class / corlib / System / MonoCustomAttrs.cs
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 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
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.
32 //
33
34 using System;
35 using System.Reflection;
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38
39 namespace System
40 {
41         internal class MonoCustomAttrs
42         {
43                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
44                 internal static extern object[] GetCustomAttributesInternal (ICustomAttributeProvider obj, bool pseudoAttrs);
45
46                 internal static object[] GetCustomAttributesBase (ICustomAttributeProvider obj)
47                 {
48                         object[] attrs = GetCustomAttributesInternal (obj, false);
49
50 #if NET_2_0 || BOOTSTRAP_NET_2_0
51                         object[] pseudoAttrs = null;
52
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 ();
62
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;
68                         }
69                         else
70                                 return attrs;
71 #else
72                         return attrs;
73 #endif
74                 }
75
76                 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
77                                                                 Type attributeType,
78                                                                 bool inherit)
79                 {
80                         object[] res = GetCustomAttributes (obj, attributeType, inherit);
81                         if (res.Length == 0)
82                         {
83                                 return null;
84                         }
85                         else if (res.Length > 1)
86                         {
87                                 string msg = "'{0}' has more than one attribute of type '{1}";
88                                 msg = String.Format (msg, obj, attributeType);
89                                 throw new AmbiguousMatchException (msg);
90                         }
91
92                         return (Attribute) res[0];
93                 }
94
95                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
96                 {
97                         if (obj == null)
98                                 throw new ArgumentNullException ("obj");
99
100                         object[] r;
101                         object[] res = GetCustomAttributesBase (obj);
102                         // shortcut
103                         if (!inherit && res.Length == 1)
104                         {
105                                 if (attributeType != null)
106                                 {
107                                         if (attributeType.IsAssignableFrom (res[0].GetType ()))
108                                         {
109                                                 r = (object[]) Array.CreateInstance (attributeType, 1);
110                                                 r[0] = res[0];
111                                         }
112                                         else
113                                         {
114                                                 r = (object[]) Array.CreateInstance (attributeType, 0);
115                                         }
116                                 }
117                                 else
118                                 {
119                                         r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
120                                         r[0] = res[0];
121                                 }
122                                 return r;
123                         }
124
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)
128                         {
129                                 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
130                                         attributeType);
131                                 if (!usageAttribute.Inherited)
132                                 {
133                                         inherit = false;
134                                 }
135                         }
136
137                         int initialSize = res.Length < 16 ? res.Length : 16;
138
139                         Hashtable attributeInfos = new Hashtable (initialSize);
140                         ArrayList a = new ArrayList (initialSize);
141                         ICustomAttributeProvider btype = obj;
142
143                         int inheritanceLevel = 0;
144
145                         do
146                         {
147                                 foreach (object attr in res)
148                                 {
149                                         AttributeUsageAttribute usage;
150
151                                         Type attrType = attr.GetType ();
152                                         if (attributeType != null)
153                                         {
154                                                 if (!attributeType.IsAssignableFrom (attrType))
155                                                 {
156                                                         continue;
157                                                 }
158                                         }
159
160                                         AttributeInfo firstAttribute = (AttributeInfo) attributeInfos[attrType];
161                                         if (firstAttribute != null)
162                                         {
163                                                 usage = firstAttribute.Usage;
164                                         }
165                                         else
166                                         {
167                                                 usage = RetrieveAttributeUsage (attrType);
168                                         }
169
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))))
182                                         {
183                                                 a.Add (attr);
184                                         }
185
186                                         if (firstAttribute == null)
187                                         {
188                                                 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
189                                         }
190                                 }
191
192                                 if ((btype = GetBase (btype)) != null)
193                                 {
194                                         inheritanceLevel++;
195                                         res = GetCustomAttributesBase (btype);
196                                 }
197                         } while (inherit && btype != null);
198
199                         object[] array = null;
200                         if (attributeType == null || attributeType.IsValueType)
201                         {
202                                 array = (object[]) Array.CreateInstance (typeof(Attribute), a.Count);
203                         }
204                         else
205                         {
206                                 array = Array.CreateInstance (attributeType, a.Count) as object[];
207                         }
208
209                         // copy attributes to array
210                         a.CopyTo (array, 0);
211
212                         return array;
213                 }
214
215                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
216                 {
217                         if (obj == null)
218                                 throw new ArgumentNullException ("obj");
219
220                         if (!inherit)
221                                 return (object[]) GetCustomAttributesBase (obj).Clone ();
222
223                         return GetCustomAttributes (obj, null, inherit);
224                 }
225
226                 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
227                 {
228                         object [] res = GetCustomAttributesBase (obj);
229                         foreach (object attr in res)
230                                 if (attributeType.Equals (attr.GetType ()))
231                                         return true;
232
233                         ICustomAttributeProvider btype;
234                         if (inherit && ((btype = GetBase (obj)) != null))
235                                 return IsDefined (btype, attributeType, inherit);
236
237                         return false;
238                 }
239
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)
244                 {
245                         if (obj == null)
246                                 return null;
247
248                         if (obj is Type)
249                                 return ((Type) obj).BaseType;
250
251                         MethodInfo method = null;
252                         if (obj is MonoProperty)
253                         {
254                                 MonoProperty prop = (MonoProperty) obj;
255                                 method = prop.GetGetMethod (true);
256                                 if (method == null)
257                                         method = prop.GetSetMethod (true);
258                         }
259                         else if (obj is MonoMethod)
260                         {
261                                 method = (MethodInfo) obj;
262                         }
263
264                         /**
265                          * ParameterInfo -> null
266                          * Assembly -> null
267                          * MonoEvent -> null
268                          * MonoField -> null
269                          */
270                         if (method == null || !method.IsVirtual)
271                                 return null;
272
273                         MethodInfo baseMethod = method.GetBaseDefinition ();
274                         if (baseMethod == method)
275                                 return null;
276
277                         return baseMethod;
278                 }
279
280                 private static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
281                 {
282                         if (attributeType == typeof (AttributeUsageAttribute))
283                                 /* Avoid endless recursion */
284                                 return new AttributeUsageAttribute (AttributeTargets.Class);
285
286                         AttributeUsageAttribute usageAttribute = null;
287                         object[] attribs = GetCustomAttributes (attributeType,
288                                 MonoCustomAttrs.AttributeUsageType, false);
289                         if (attribs.Length == 0)
290                         {
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)
294                                 {
295                                         usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
296
297                                 }
298                                 if (usageAttribute != null)
299                                 {
300                                         // return AttributeUsage of base class
301                                         return usageAttribute;
302
303                                 }
304                                 // return default AttributeUsageAttribute if no AttributeUsage 
305                                 // was defined on attribute, or its base class
306                                 return DefaultAttributeUsage;
307                         }
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)
313                         {
314                                 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
315                         }
316
317                         return ((AttributeUsageAttribute) attribs[0]);
318                 }
319
320                 private static readonly Type AttributeUsageType = typeof(AttributeUsageAttribute);
321                 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
322                         new AttributeUsageAttribute (AttributeTargets.All);
323
324                 private class AttributeInfo
325                 {
326                         private AttributeUsageAttribute _usage;
327                         private int _inheritanceLevel;
328
329                         public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
330                         {
331                                 _usage = usage;
332                                 _inheritanceLevel = inheritanceLevel;
333                         }
334
335                         public AttributeUsageAttribute Usage
336                         {
337                                 get
338                                 {
339                                         return _usage;
340                                 }
341                         }
342
343                         public int InheritanceLevel
344                         {
345                                 get
346                                 {
347                                         return _inheritanceLevel;
348                                 }
349                         }
350                 }
351         }
352 }
353