Merge pull request #487 from mayerwin/patch-1
[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 #if !FULL_AOT_RUNTIME
39 using System.Reflection.Emit;
40 #endif
41
42 using System.Collections.Generic;
43
44 namespace System
45 {
46         internal class MonoCustomAttrs
47         {
48                 static Assembly corlib;
49
50                 /* Treat as user types all corlib types extending System.Type that are not MonoType and TypeBuilder */
51                 static bool IsUserCattrProvider (object obj)
52                 {
53                         Type type = obj as Type;
54 #if !FULL_AOT_RUNTIME
55                         if ((type is MonoType) || (type is TypeBuilder))
56 #else
57                         if (type is MonoType)
58 #endif
59                                 return false;
60                         if ((obj is Type))
61                                 return true;
62                         if (corlib == null)
63                                  corlib = typeof (int).Assembly;
64                         return obj.GetType ().Assembly != corlib;
65                 }
66         
67                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
68                 internal static extern object[] GetCustomAttributesInternal (ICustomAttributeProvider obj, Type attributeType, bool pseudoAttrs);
69
70                 internal static object[] GetPseudoCustomAttributes (ICustomAttributeProvider obj, Type attributeType) {
71                         object[] pseudoAttrs = null;
72
73                         /* FIXME: Add other types */
74                         if (obj is MonoMethod)
75                                 pseudoAttrs = ((MonoMethod)obj).GetPseudoCustomAttributes ();
76                         else if (obj is FieldInfo)
77                                 pseudoAttrs = ((FieldInfo)obj).GetPseudoCustomAttributes ();
78                         else if (obj is ParameterInfo)
79                                 pseudoAttrs = ((ParameterInfo)obj).GetPseudoCustomAttributes ();
80                         else if (obj is Type)
81                                 pseudoAttrs = ((Type)obj).GetPseudoCustomAttributes ();
82
83                         if ((attributeType != null) && (pseudoAttrs != null)) {
84                                 for (int i = 0; i < pseudoAttrs.Length; ++i)
85                                         if (attributeType.IsAssignableFrom (pseudoAttrs [i].GetType ()))
86                                                 if (pseudoAttrs.Length == 1)
87                                                         return pseudoAttrs;
88                                                 else
89                                                         return new object [] { pseudoAttrs [i] };
90                                 return new object [0];
91                         }
92                         else
93                                 return pseudoAttrs;
94                 }
95
96                 internal static object[] GetCustomAttributesBase (ICustomAttributeProvider obj, Type attributeType)
97                 {
98                         object[] attrs;
99                         if (IsUserCattrProvider (obj))
100                                 attrs = obj.GetCustomAttributes (attributeType, true);
101                         else
102                                 attrs = GetCustomAttributesInternal (obj, attributeType, false);
103
104                         object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
105                         if (pseudoAttrs != null) {
106                                 object[] res = new object [attrs.Length + pseudoAttrs.Length];
107                                 System.Array.Copy (attrs, res, attrs.Length);
108                                 System.Array.Copy (pseudoAttrs, 0, res, attrs.Length, pseudoAttrs.Length);
109                                 return res;
110                         }
111                         else
112                                 return attrs;
113                 }
114
115                 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
116                                                                 Type attributeType,
117                                                                 bool inherit)
118                 {
119                         object[] res = GetCustomAttributes (obj, attributeType, inherit);
120                         if (res.Length == 0)
121                         {
122                                 return null;
123                         }
124                         else if (res.Length > 1)
125                         {
126                                 string msg = "'{0}' has more than one attribute of type '{1}";
127                                 msg = String.Format (msg, obj, attributeType);
128                                 throw new AmbiguousMatchException (msg);
129                         }
130
131                         return (Attribute) res[0];
132                 }
133
134                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
135                 {
136                         if (obj == null)
137                                 throw new ArgumentNullException ("obj");
138                         if (attributeType == null)
139                                 throw new ArgumentNullException ("attributeType");      
140
141                         if (attributeType == typeof (MonoCustomAttrs))
142                                 attributeType = null;
143                         
144                         object[] r;
145                         object[] res = GetCustomAttributesBase (obj, attributeType);
146                         // shortcut
147                         if (!inherit && res.Length == 1)
148                         {
149                                 if (res [0] == null)
150                                         throw new CustomAttributeFormatException ("Invalid custom attribute format");
151
152                                 if (attributeType != null)
153                                 {
154                                         if (attributeType.IsAssignableFrom (res[0].GetType ()))
155                                         {
156                                                 r = (object[]) Array.CreateInstance (attributeType, 1);
157                                                 r[0] = res[0];
158                                         }
159                                         else
160                                         {
161                                                 r = (object[]) Array.CreateInstance (attributeType, 0);
162                                         }
163                                 }
164                                 else
165                                 {
166                                         r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
167                                         r[0] = res[0];
168                                 }
169                                 return r;
170                         }
171
172                         // if AttributeType is sealed, and Inherited is set to false, then 
173                         // there's no use in scanning base types 
174                         if ((attributeType != null && attributeType.IsSealed) && inherit)
175                         {
176                                 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
177                                         attributeType);
178                                 if (!usageAttribute.Inherited)
179                                 {
180                                         inherit = false;
181                                 }
182                         }
183
184                         int initialSize = res.Length < 16 ? res.Length : 16;
185
186                         Hashtable attributeInfos = new Hashtable (initialSize);
187                         ArrayList a = new ArrayList (initialSize);
188                         ICustomAttributeProvider btype = obj;
189
190                         int inheritanceLevel = 0;
191
192                         do
193                         {
194                                 foreach (object attr in res)
195                                 {
196                                         AttributeUsageAttribute usage;
197                                         if (attr == null)
198                                                 throw new CustomAttributeFormatException ("Invalid custom attribute format");
199
200                                         Type attrType = attr.GetType ();
201                                         if (attributeType != null)
202                                         {
203                                                 if (!attributeType.IsAssignableFrom (attrType))
204                                                 {
205                                                         continue;
206                                                 }
207                                         }
208
209                                         AttributeInfo firstAttribute = (AttributeInfo) attributeInfos[attrType];
210                                         if (firstAttribute != null)
211                                         {
212                                                 usage = firstAttribute.Usage;
213                                         }
214                                         else
215                                         {
216                                                 usage = RetrieveAttributeUsage (attrType);
217                                         }
218
219                                         // only add attribute to the list of attributes if 
220                                         // - we are on the first inheritance level, or the attribute can be inherited anyway
221                                         // and (
222                                         // - multiple attributes of the type are allowed
223                                         // or (
224                                         // - this is the first attribute we've discovered
225                                         // or
226                                         // - the attribute is on same inheritance level than the first 
227                                         //   attribute that was discovered for this attribute type ))
228                                         if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple || 
229                                                 (firstAttribute == null || (firstAttribute != null 
230                                                         && firstAttribute.InheritanceLevel == inheritanceLevel))))
231                                         {
232                                                 a.Add (attr);
233                                         }
234
235                                         if (firstAttribute == null)
236                                         {
237                                                 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
238                                         }
239                                 }
240
241                                 if ((btype = GetBase (btype)) != null)
242                                 {
243                                         inheritanceLevel++;
244                                         res = GetCustomAttributesBase (btype, attributeType);
245                                 }
246                         } while (inherit && btype != null);
247
248                         object[] array = null;
249                         if (attributeType == null || attributeType.IsValueType)
250                         {
251                                 array = (object[]) Array.CreateInstance (typeof(Attribute), a.Count);
252                         }
253                         else
254                         {
255                                 array = Array.CreateInstance (attributeType, a.Count) as object[];
256                         }
257
258                         // copy attributes to array
259                         a.CopyTo (array, 0);
260
261                         return array;
262                 }
263
264                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
265                 {
266                         if (obj == null)
267                                 throw new ArgumentNullException ("obj");
268
269                         if (!inherit)
270                                 return (object[]) GetCustomAttributesBase (obj, null).Clone ();
271
272                         return GetCustomAttributes (obj, typeof (MonoCustomAttrs), inherit);
273                 }
274
275                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
276                 static extern CustomAttributeData [] GetCustomAttributesDataInternal (ICustomAttributeProvider obj);
277
278                 internal static IList<CustomAttributeData> GetCustomAttributesData (ICustomAttributeProvider obj)
279                 {
280                         if (obj == null)
281                                 throw new ArgumentNullException ("obj");
282
283                         CustomAttributeData [] attrs = GetCustomAttributesDataInternal (obj);
284                         return Array.AsReadOnly<CustomAttributeData> (attrs);
285                 }
286
287                 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
288                 {
289                         if (attributeType == null)
290                                 throw new ArgumentNullException ("attributeType");
291
292                         AttributeUsageAttribute usage = null;
293                         do {
294                                 if (IsUserCattrProvider (obj))
295                                         return obj.IsDefined (attributeType, inherit);
296
297                                 if (IsDefinedInternal (obj, attributeType))
298                                         return true;
299
300                                 object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
301                                 if (pseudoAttrs != null) {
302                                         for (int i = 0; i < pseudoAttrs.Length; ++i)
303                                                 if (attributeType.IsAssignableFrom (pseudoAttrs[i].GetType ()))
304                                                         return true;
305                                 }
306
307                                 if (usage == null) {
308                                         if (!inherit)
309                                                 return false;
310
311                                         usage = RetrieveAttributeUsage (attributeType);
312                                         if (!usage.Inherited)
313                                                 return false;
314                                 }
315
316                                 obj = GetBase (obj);
317                         } while (obj != null);
318
319                         return false;
320                 }
321
322                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
323                 internal static extern bool IsDefinedInternal (ICustomAttributeProvider obj, Type AttributeType);
324
325                 static PropertyInfo GetBasePropertyDefinition (PropertyInfo property)
326                 {
327                         MethodInfo method = property.GetGetMethod (true);
328                         if (method == null || !method.IsVirtual)
329                                 method = property.GetSetMethod (true);
330                         if (method == null || !method.IsVirtual)
331                                 return null;
332
333                         MethodInfo baseMethod = method.GetBaseMethod ();
334                         if (baseMethod != null && baseMethod != method) {
335                                 ParameterInfo[] parameters = property.GetIndexParameters ();
336                                 if (parameters != null && parameters.Length > 0) {
337                                         Type[] paramTypes = new Type[parameters.Length];
338                                         for (int i=0; i < paramTypes.Length; i++)
339                                                 paramTypes[i] = parameters[i].ParameterType;
340                                         return baseMethod.DeclaringType.GetProperty (property.Name, property.PropertyType, 
341                                                                                      paramTypes);
342                                 } else {
343                                         return baseMethod.DeclaringType.GetProperty (property.Name, property.PropertyType);
344                                 }
345                         }
346                         return null;
347
348                 }
349
350                 static EventInfo GetBaseEventDefinition (EventInfo evt)
351                 {
352                         MethodInfo method = evt.GetAddMethod (true);
353                         if (method == null || !method.IsVirtual)
354                                 method = evt.GetRaiseMethod (true);
355                         if (method == null || !method.IsVirtual)
356                                 method = evt.GetRemoveMethod (true);
357                         if (method == null || !method.IsVirtual)
358                                 return null;
359
360                         MethodInfo baseMethod = method.GetBaseMethod ();
361                         if (baseMethod != null && baseMethod != method) {
362                                 BindingFlags flags = method.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
363                                 flags |= method.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
364
365                                 return baseMethod.DeclaringType.GetEvent (evt.Name, flags);
366                         }
367                         return null;
368                 }
369
370                 // Handles Type, MonoProperty and MonoMethod.
371                 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
372                 // but for those we return null here.
373                 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
374                 {
375                         if (obj == null)
376                                 return null;
377
378                         if (obj is Type)
379                                 return ((Type) obj).BaseType;
380
381                         MethodInfo method = null;
382                         if (obj is MonoProperty)
383                                 return GetBasePropertyDefinition ((MonoProperty) obj);
384                         else if (obj is MonoEvent)
385                                 return GetBaseEventDefinition ((MonoEvent)obj);
386                         else if (obj is MonoMethod)
387                                 method = (MethodInfo) obj;
388
389                         /**
390                          * ParameterInfo -> null
391                          * Assembly -> null
392                          * MonoEvent -> null
393                          * MonoField -> null
394                          */
395                         if (method == null || !method.IsVirtual)
396                                 return null;
397
398                         MethodInfo baseMethod = method.GetBaseMethod ();
399                         if (baseMethod == method)
400                                 return null;
401
402                         return baseMethod;
403                 }
404
405                 private static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
406                 {
407                         if (attributeType == typeof (AttributeUsageAttribute))
408                                 /* Avoid endless recursion */
409                                 return new AttributeUsageAttribute (AttributeTargets.Class);
410
411                         AttributeUsageAttribute usageAttribute = null;
412                         object[] attribs = GetCustomAttributes (attributeType, typeof(AttributeUsageAttribute), false);
413                         if (attribs.Length == 0)
414                         {
415                                 // if no AttributeUsage was defined on the attribute level, then
416                                 // try to retrieve if from its base type
417                                 if (attributeType.BaseType != null)
418                                 {
419                                         usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
420
421                                 }
422                                 if (usageAttribute != null)
423                                 {
424                                         // return AttributeUsage of base class
425                                         return usageAttribute;
426
427                                 }
428                                 // return default AttributeUsageAttribute if no AttributeUsage 
429                                 // was defined on attribute, or its base class
430                                 return DefaultAttributeUsage;
431                         }
432                         // check if more than one AttributeUsageAttribute has been specified 
433                         // on the type
434                         // NOTE: compilers should prevent this, but that doesn't prevent
435                         // anyone from using IL ofcourse
436                         if (attribs.Length > 1)
437                         {
438                                 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
439                         }
440
441                         return ((AttributeUsageAttribute) attribs[0]);
442                 }
443
444                 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
445                         new AttributeUsageAttribute (AttributeTargets.All);
446
447                 private class AttributeInfo
448                 {
449                         private AttributeUsageAttribute _usage;
450                         private int _inheritanceLevel;
451
452                         public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
453                         {
454                                 _usage = usage;
455                                 _inheritanceLevel = inheritanceLevel;
456                         }
457
458                         public AttributeUsageAttribute Usage
459                         {
460                                 get
461                                 {
462                                         return _usage;
463                                 }
464                         }
465
466                         public int InheritanceLevel
467                         {
468                                 get
469                                 {
470                                         return _inheritanceLevel;
471                                 }
472                         }
473                 }
474         }
475 }
476