Merge pull request #3066 from alexanderkyte/pedump_sgen
[mono.git] / mcs / class / corlib / System / MonoCustomAttrs.cs
1 //
2 // MonoCustomAttrs.cs: 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 //      Marek Safar (marek.safar@gmail.com)
8 //
9 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Reflection;
35 using System.Collections;
36 using System.Runtime.CompilerServices;
37 using System.Runtime.InteropServices;
38 #if !FULL_AOT_RUNTIME
39 using System.Reflection.Emit;
40 #endif
41
42 using System.Collections.Generic;
43
44 namespace System
45 {
46         static class MonoCustomAttrs
47         {
48                 static Assembly corlib;
49                 [ThreadStatic]
50                 static Dictionary<Type, AttributeUsageAttribute> usage_cache;
51
52                 /* Treat as user types all corlib types extending System.Type that are not RuntimeType and TypeBuilder */
53                 static bool IsUserCattrProvider (object obj)
54                 {
55                         Type type = obj as Type;
56 #if !FULL_AOT_RUNTIME
57                         if ((type is RuntimeType) || (type is TypeBuilder))
58 #else
59                         if (type is RuntimeType)
60 #endif
61                                 return false;
62                         if ((obj is Type))
63                                 return true;
64                         if (corlib == null)
65                                  corlib = typeof (int).Assembly;
66                         return obj.GetType ().Assembly != corlib;
67                 }
68         
69                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
70                 internal static extern object[] GetCustomAttributesInternal (ICustomAttributeProvider obj, Type attributeType, bool pseudoAttrs);
71
72                 internal static object[] GetPseudoCustomAttributes (ICustomAttributeProvider obj, Type attributeType) {
73                         object[] pseudoAttrs = null;
74
75                         /* FIXME: Add other types */
76                         if (obj is MonoMethod)
77                                 pseudoAttrs = ((MonoMethod)obj).GetPseudoCustomAttributes ();
78                         else if (obj is FieldInfo)
79                                 pseudoAttrs = ((FieldInfo)obj).GetPseudoCustomAttributes ();
80                         else if (obj is ParameterInfo)
81                                 pseudoAttrs = ((ParameterInfo)obj).GetPseudoCustomAttributes ();
82                         else if (obj is Type)
83                                 pseudoAttrs = GetPseudoCustomAttributes (((Type)obj));
84
85                         if ((attributeType != null) && (pseudoAttrs != null)) {
86                                 for (int i = 0; i < pseudoAttrs.Length; ++i)
87                                         if (attributeType.IsAssignableFrom (pseudoAttrs [i].GetType ()))
88                                                 if (pseudoAttrs.Length == 1)
89                                                         return pseudoAttrs;
90                                                 else
91                                                         return new object [] { pseudoAttrs [i] };
92                                 return EmptyArray<object>.Value;
93                         }
94
95                         return pseudoAttrs;
96                 }
97
98                 static object[] GetPseudoCustomAttributes (Type type)
99                 {
100                         int count = 0;
101                         var Attributes = type.Attributes;
102
103                         /* IsSerializable returns true for delegates/enums as well */
104                         if ((Attributes & TypeAttributes.Serializable) != 0)
105                                 count ++;
106                         if ((Attributes & TypeAttributes.Import) != 0)
107                                 count ++;
108
109                         if (count == 0)
110                                 return null;
111                         object[] attrs = new object [count];
112                         count = 0;
113
114                         if ((Attributes & TypeAttributes.Serializable) != 0)
115                                 attrs [count ++] = new SerializableAttribute ();
116                         if ((Attributes & TypeAttributes.Import) != 0)
117                                 attrs [count ++] = new ComImportAttribute ();
118
119                         return attrs;
120                 }
121
122                 internal static object[] GetCustomAttributesBase (ICustomAttributeProvider obj, Type attributeType, bool inheritedOnly)
123                 {
124                         object[] attrs;
125                         if (IsUserCattrProvider (obj))
126                                 attrs = obj.GetCustomAttributes (attributeType, true);
127                         else
128                                 attrs = GetCustomAttributesInternal (obj, attributeType, false);
129
130                         //
131                         // All pseudo custom attributes are Inherited = false hence we can avoid
132                         // building attributes array which would be discarded by inherited checks
133                         //
134                         if (!inheritedOnly) {
135                                 object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
136                                 if (pseudoAttrs != null) {
137                                         object[] res = new object [attrs.Length + pseudoAttrs.Length];
138                                         System.Array.Copy (attrs, res, attrs.Length);
139                                         System.Array.Copy (pseudoAttrs, 0, res, attrs.Length, pseudoAttrs.Length);
140                                         return res;
141                                 }
142                         }
143
144                         return attrs;
145                 }
146
147                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
148                 {
149                         if (obj == null)
150                                 throw new ArgumentNullException ("obj");
151                         if (attributeType == null)
152                                 throw new ArgumentNullException ("attributeType");      
153
154                         if (attributeType == typeof (MonoCustomAttrs))
155                                 attributeType = null;
156                         
157                         object[] r;
158                         object[] res = GetCustomAttributesBase (obj, attributeType, false);
159                         // shortcut
160                         if (!inherit && res.Length == 1) {
161                                 if (res [0] == null)
162                                         throw new CustomAttributeFormatException ("Invalid custom attribute format");
163
164                                 if (attributeType != null) {
165                                         if (attributeType.IsAssignableFrom (res[0].GetType ())) {
166                                                 r = (object[]) Array.CreateInstance (attributeType, 1);
167                                                 r[0] = res[0];
168                                         } else {
169                                                 r = (object[]) Array.CreateInstance (attributeType, 0);
170                                         }
171                                 } else {
172                                         r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
173                                         r[0] = res[0];
174                                 }
175                                 return r;
176                         }
177
178                         if (inherit && GetBase (obj) == null)
179                                 inherit = false;
180
181                         // if AttributeType is sealed, and Inherited is set to false, then 
182                         // there's no use in scanning base types 
183                         if ((attributeType != null && attributeType.IsSealed) && inherit) {
184                                 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
185                                         attributeType);
186                                 if (!usageAttribute.Inherited)
187                                         inherit = false;
188                         }
189
190                         var initialSize = Math.Max (res.Length, 16);
191                         List<Object> a = null;
192                         ICustomAttributeProvider btype = obj;
193                         object[] array;
194
195                         /* Non-inherit case */
196                         if (!inherit) {
197                                 if (attributeType == null) {
198                                         foreach (object attr in res) {
199                                                 if (attr == null)
200                                                         throw new CustomAttributeFormatException ("Invalid custom attribute format");
201                                         }
202                                         var result = new Attribute [res.Length];
203                                         res.CopyTo (result, 0);
204                                         return result;
205                                 }
206
207                                 a = new List<object> (initialSize);
208                                 foreach (object attr in res) {
209                                         if (attr == null)
210                                                 throw new CustomAttributeFormatException ("Invalid custom attribute format");
211
212                                         Type attrType = attr.GetType ();
213                                         if (attributeType != null && !attributeType.IsAssignableFrom (attrType))
214                                                 continue;
215                                         a.Add (attr);
216                                 }
217
218                                 if (attributeType == null || attributeType.IsValueType)
219                                         array = new Attribute [a.Count];
220                                 else
221                                         array = Array.CreateInstance (attributeType, a.Count) as object[];
222                                 a.CopyTo (array, 0);
223                                 return array;
224                         }
225
226                         /* Inherit case */
227                         var attributeInfos = new Dictionary<Type, AttributeInfo> (initialSize);
228                         int inheritanceLevel = 0;
229                         a = new List<object> (initialSize);
230
231                         do {
232                                 foreach (object attr in res) {
233                                         AttributeUsageAttribute usage;
234                                         if (attr == null)
235                                                 throw new CustomAttributeFormatException ("Invalid custom attribute format");
236
237                                         Type attrType = attr.GetType ();
238                                         if (attributeType != null) {
239                                                 if (!attributeType.IsAssignableFrom (attrType))
240                                                         continue;
241                                         }
242
243                                         AttributeInfo firstAttribute;
244                                         if (attributeInfos.TryGetValue (attrType, out firstAttribute))
245                                                 usage = firstAttribute.Usage;
246                                         else
247                                                 usage = RetrieveAttributeUsage (attrType);
248
249                                         // only add attribute to the list of attributes if 
250                                         // - we are on the first inheritance level, or the attribute can be inherited anyway
251                                         // and (
252                                         // - multiple attributes of the type are allowed
253                                         // or (
254                                         // - this is the first attribute we've discovered
255                                         // or
256                                         // - the attribute is on same inheritance level than the first 
257                                         //   attribute that was discovered for this attribute type ))
258                                         if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple || 
259                                                 (firstAttribute == null || (firstAttribute != null 
260                                                         && firstAttribute.InheritanceLevel == inheritanceLevel))))
261                                                 a.Add (attr);
262
263                                         if (firstAttribute == null)
264                                                 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
265                                 }
266
267                                 if ((btype = GetBase (btype)) != null) {
268                                         inheritanceLevel++;
269                                         res = GetCustomAttributesBase (btype, attributeType, true);
270                                 }
271                         } while (inherit && btype != null);
272
273                         if (attributeType == null || attributeType.IsValueType)
274                                 array = new Attribute [a.Count];
275                         else
276                                 array = Array.CreateInstance (attributeType, a.Count) as object[];
277
278                         // copy attributes to array
279                         a.CopyTo (array, 0);
280
281                         return array;
282                 }
283
284                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
285                 {
286                         if (obj == null)
287                                 throw new ArgumentNullException ("obj");
288
289                         if (!inherit)
290                                 return (object[]) GetCustomAttributesBase (obj, null, false).Clone ();
291
292                         return GetCustomAttributes (obj, typeof (MonoCustomAttrs), inherit);
293                 }
294
295                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
296                 static extern CustomAttributeData [] GetCustomAttributesDataInternal (ICustomAttributeProvider obj);
297
298                 internal static IList<CustomAttributeData> GetCustomAttributesData (ICustomAttributeProvider obj)
299                 {
300                         if (obj == null)
301                                 throw new ArgumentNullException ("obj");
302
303                         CustomAttributeData [] attrs = GetCustomAttributesDataInternal (obj);
304                         return Array.AsReadOnly<CustomAttributeData> (attrs);
305                 }
306
307                 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
308                 {
309                         if (attributeType == null)
310                                 throw new ArgumentNullException ("attributeType");
311
312                         AttributeUsageAttribute usage = null;
313                         do {
314                                 if (IsUserCattrProvider (obj))
315                                         return obj.IsDefined (attributeType, inherit);
316
317                                 if (IsDefinedInternal (obj, attributeType))
318                                         return true;
319
320                                 object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
321                                 if (pseudoAttrs != null) {
322                                         for (int i = 0; i < pseudoAttrs.Length; ++i)
323                                                 if (attributeType.IsAssignableFrom (pseudoAttrs[i].GetType ()))
324                                                         return true;
325                                 }
326
327                                 if (usage == null) {
328                                         if (!inherit)
329                                                 return false;
330
331                                         usage = RetrieveAttributeUsage (attributeType);
332                                         if (!usage.Inherited)
333                                                 return false;
334                                 }
335
336                                 obj = GetBase (obj);
337                         } while (obj != null);
338
339                         return false;
340                 }
341
342                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
343                 internal static extern bool IsDefinedInternal (ICustomAttributeProvider obj, Type AttributeType);
344
345                 static PropertyInfo GetBasePropertyDefinition (MonoProperty property)
346                 {
347                         MethodInfo method = property.GetGetMethod (true);
348                         if (method == null || !method.IsVirtual)
349                                 method = property.GetSetMethod (true);
350                         if (method == null || !method.IsVirtual)
351                                 return null;
352
353                         MethodInfo baseMethod = method.GetBaseMethod ();
354                         if (baseMethod != null && baseMethod != method) {
355                                 ParameterInfo[] parameters = property.GetIndexParameters ();
356                                 if (parameters != null && parameters.Length > 0) {
357                                         Type[] paramTypes = new Type[parameters.Length];
358                                         for (int i=0; i < paramTypes.Length; i++)
359                                                 paramTypes[i] = parameters[i].ParameterType;
360                                         return baseMethod.DeclaringType.GetProperty (property.Name, property.PropertyType, 
361                                                                                      paramTypes);
362                                 } else {
363                                         return baseMethod.DeclaringType.GetProperty (property.Name, property.PropertyType);
364                                 }
365                         }
366                         return null;
367
368                 }
369
370                 static EventInfo GetBaseEventDefinition (MonoEvent evt)
371                 {
372                         MethodInfo method = evt.GetAddMethod (true);
373                         if (method == null || !method.IsVirtual)
374                                 method = evt.GetRaiseMethod (true);
375                         if (method == null || !method.IsVirtual)
376                                 method = evt.GetRemoveMethod (true);
377                         if (method == null || !method.IsVirtual)
378                                 return null;
379
380                         MethodInfo baseMethod = method.GetBaseMethod ();
381                         if (baseMethod != null && baseMethod != method) {
382                                 BindingFlags flags = method.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
383                                 flags |= method.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
384
385                                 return baseMethod.DeclaringType.GetEvent (evt.Name, flags);
386                         }
387                         return null;
388                 }
389
390                 // Handles Type, MonoProperty and MonoMethod.
391                 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
392                 // but for those we return null here.
393                 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
394                 {
395                         if (obj == null)
396                                 return null;
397
398                         if (obj is Type)
399                                 return ((Type) obj).BaseType;
400
401                         MethodInfo method = null;
402                         if (obj is MonoProperty)
403                                 return GetBasePropertyDefinition ((MonoProperty) obj);
404                         else if (obj is MonoEvent)
405                                 return GetBaseEventDefinition ((MonoEvent)obj);
406                         else if (obj is MonoMethod)
407                                 method = (MethodInfo) obj;
408
409                         /**
410                          * ParameterInfo -> null
411                          * Assembly -> null
412                          * MonoEvent -> null
413                          * MonoField -> null
414                          */
415                         if (method == null || !method.IsVirtual)
416                                 return null;
417
418                         MethodInfo baseMethod = method.GetBaseMethod ();
419                         if (baseMethod == method)
420                                 return null;
421
422                         return baseMethod;
423                 }
424
425                 private static AttributeUsageAttribute RetrieveAttributeUsageNoCache (Type attributeType)
426                 {
427                         if (attributeType == typeof (AttributeUsageAttribute))
428                                 /* Avoid endless recursion */
429                                 return new AttributeUsageAttribute (AttributeTargets.Class);
430
431                         AttributeUsageAttribute usageAttribute = null;
432                         object[] attribs = GetCustomAttributes (attributeType, typeof(AttributeUsageAttribute), false);
433                         if (attribs.Length == 0)
434                         {
435                                 // if no AttributeUsage was defined on the attribute level, then
436                                 // try to retrieve if from its base type
437                                 if (attributeType.BaseType != null)
438                                 {
439                                         usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
440
441                                 }
442                                 if (usageAttribute != null)
443                                 {
444                                         // return AttributeUsage of base class
445                                         return usageAttribute;
446
447                                 }
448                                 // return default AttributeUsageAttribute if no AttributeUsage 
449                                 // was defined on attribute, or its base class
450                                 return DefaultAttributeUsage;
451                         }
452                         // check if more than one AttributeUsageAttribute has been specified 
453                         // on the type
454                         // NOTE: compilers should prevent this, but that doesn't prevent
455                         // anyone from using IL ofcourse
456                         if (attribs.Length > 1)
457                         {
458                                 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
459                         }
460
461                         return ((AttributeUsageAttribute) attribs[0]);
462                 }
463
464                 static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
465                 {
466                         AttributeUsageAttribute usageAttribute = null;
467                         /* Usage a thread-local cache to speed this up, since it is called a lot from GetCustomAttributes () */
468                         if (usage_cache == null)
469                                 usage_cache = new Dictionary<Type, AttributeUsageAttribute> ();
470                         if (usage_cache.TryGetValue (attributeType, out usageAttribute))
471                                 return usageAttribute;
472                         usageAttribute = RetrieveAttributeUsageNoCache (attributeType);
473                         usage_cache [attributeType] = usageAttribute;
474                         return usageAttribute;
475                 }
476
477                 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
478                         new AttributeUsageAttribute (AttributeTargets.All);
479
480                 private class AttributeInfo
481                 {
482                         private AttributeUsageAttribute _usage;
483                         private int _inheritanceLevel;
484
485                         public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
486                         {
487                                 _usage = usage;
488                                 _inheritanceLevel = inheritanceLevel;
489                         }
490
491                         public AttributeUsageAttribute Usage
492                         {
493                                 get
494                                 {
495                                         return _usage;
496                                 }
497                         }
498
499                         public int InheritanceLevel
500                         {
501                                 get
502                                 {
503                                         return _inheritanceLevel;
504                                 }
505                         }
506                 }
507         }
508 }
509