[corlib] Type from reference sources
[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 MonoType and TypeBuilder */
53                 static bool IsUserCattrProvider (object obj)
54                 {
55                         Type type = obj as Type;
56 #if !FULL_AOT_RUNTIME
57                         if ((type is MonoType) || (type is TypeBuilder))
58 #else
59                         if (type is MonoType)
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 Attribute GetCustomAttribute (ICustomAttributeProvider obj,
148                                                                 Type attributeType,
149                                                                 bool inherit)
150                 {
151                         object[] res = GetCustomAttributes (obj, attributeType, inherit);
152                         if (res.Length == 0)
153                         {
154                                 return null;
155                         }
156                         else if (res.Length > 1)
157                         {
158                                 string msg = "'{0}' has more than one attribute of type '{1}";
159                                 msg = String.Format (msg, obj, attributeType);
160                                 throw new AmbiguousMatchException (msg);
161                         }
162
163                         return (Attribute) res[0];
164                 }
165
166                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
167                 {
168                         if (obj == null)
169                                 throw new ArgumentNullException ("obj");
170                         if (attributeType == null)
171                                 throw new ArgumentNullException ("attributeType");      
172
173                         if (attributeType == typeof (MonoCustomAttrs))
174                                 attributeType = null;
175                         
176                         object[] r;
177                         object[] res = GetCustomAttributesBase (obj, attributeType, false);
178                         // shortcut
179                         if (!inherit && res.Length == 1) {
180                                 if (res [0] == null)
181                                         throw new CustomAttributeFormatException ("Invalid custom attribute format");
182
183                                 if (attributeType != null) {
184                                         if (attributeType.IsAssignableFrom (res[0].GetType ())) {
185                                                 r = (object[]) Array.CreateInstance (attributeType, 1);
186                                                 r[0] = res[0];
187                                         } else {
188                                                 r = (object[]) Array.CreateInstance (attributeType, 0);
189                                         }
190                                 } else {
191                                         r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
192                                         r[0] = res[0];
193                                 }
194                                 return r;
195                         }
196
197                         if (inherit && GetBase (obj) == null)
198                                 inherit = false;
199
200                         // if AttributeType is sealed, and Inherited is set to false, then 
201                         // there's no use in scanning base types 
202                         if ((attributeType != null && attributeType.IsSealed) && inherit) {
203                                 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
204                                         attributeType);
205                                 if (!usageAttribute.Inherited)
206                                         inherit = false;
207                         }
208
209                         var initialSize = Math.Max (res.Length, 16);
210                         List<Object> a = null;
211                         ICustomAttributeProvider btype = obj;
212                         object[] array;
213
214                         /* Non-inherit case */
215                         if (!inherit) {
216                                 if (attributeType == null) {
217                                         foreach (object attr in res) {
218                                                 if (attr == null)
219                                                         throw new CustomAttributeFormatException ("Invalid custom attribute format");
220                                         }
221                                         var result = new Attribute [res.Length];
222                                         res.CopyTo (result, 0);
223                                         return result;
224                                 }
225
226                                 a = new List<object> (initialSize);
227                                 foreach (object attr in res) {
228                                         if (attr == null)
229                                                 throw new CustomAttributeFormatException ("Invalid custom attribute format");
230
231                                         Type attrType = attr.GetType ();
232                                         if (attributeType != null && !attributeType.IsAssignableFrom (attrType))
233                                                 continue;
234                                         a.Add (attr);
235                                 }
236
237                                 if (attributeType == null || attributeType.IsValueType)
238                                         array = new Attribute [a.Count];
239                                 else
240                                         array = Array.CreateInstance (attributeType, a.Count) as object[];
241                                 a.CopyTo (array, 0);
242                                 return array;
243                         }
244
245                         /* Inherit case */
246                         var attributeInfos = new Dictionary<Type, AttributeInfo> (initialSize);
247                         int inheritanceLevel = 0;
248                         a = new List<object> (initialSize);
249
250                         do {
251                                 foreach (object attr in res) {
252                                         AttributeUsageAttribute usage;
253                                         if (attr == null)
254                                                 throw new CustomAttributeFormatException ("Invalid custom attribute format");
255
256                                         Type attrType = attr.GetType ();
257                                         if (attributeType != null) {
258                                                 if (!attributeType.IsAssignableFrom (attrType))
259                                                         continue;
260                                         }
261
262                                         AttributeInfo firstAttribute;
263                                         if (attributeInfos.TryGetValue (attrType, out firstAttribute))
264                                                 usage = firstAttribute.Usage;
265                                         else
266                                                 usage = RetrieveAttributeUsage (attrType);
267
268                                         // only add attribute to the list of attributes if 
269                                         // - we are on the first inheritance level, or the attribute can be inherited anyway
270                                         // and (
271                                         // - multiple attributes of the type are allowed
272                                         // or (
273                                         // - this is the first attribute we've discovered
274                                         // or
275                                         // - the attribute is on same inheritance level than the first 
276                                         //   attribute that was discovered for this attribute type ))
277                                         if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple || 
278                                                 (firstAttribute == null || (firstAttribute != null 
279                                                         && firstAttribute.InheritanceLevel == inheritanceLevel))))
280                                                 a.Add (attr);
281
282                                         if (firstAttribute == null)
283                                                 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
284                                 }
285
286                                 if ((btype = GetBase (btype)) != null) {
287                                         inheritanceLevel++;
288                                         res = GetCustomAttributesBase (btype, attributeType, true);
289                                 }
290                         } while (inherit && btype != null);
291
292                         if (attributeType == null || attributeType.IsValueType)
293                                 array = new Attribute [a.Count];
294                         else
295                                 array = Array.CreateInstance (attributeType, a.Count) as object[];
296
297                         // copy attributes to array
298                         a.CopyTo (array, 0);
299
300                         return array;
301                 }
302
303                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
304                 {
305                         if (obj == null)
306                                 throw new ArgumentNullException ("obj");
307
308                         if (!inherit)
309                                 return (object[]) GetCustomAttributesBase (obj, null, false).Clone ();
310
311                         return GetCustomAttributes (obj, typeof (MonoCustomAttrs), inherit);
312                 }
313
314                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
315                 static extern CustomAttributeData [] GetCustomAttributesDataInternal (ICustomAttributeProvider obj);
316
317                 internal static IList<CustomAttributeData> GetCustomAttributesData (ICustomAttributeProvider obj)
318                 {
319                         if (obj == null)
320                                 throw new ArgumentNullException ("obj");
321
322                         CustomAttributeData [] attrs = GetCustomAttributesDataInternal (obj);
323                         return Array.AsReadOnly<CustomAttributeData> (attrs);
324                 }
325
326                 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
327                 {
328                         if (attributeType == null)
329                                 throw new ArgumentNullException ("attributeType");
330
331                         AttributeUsageAttribute usage = null;
332                         do {
333                                 if (IsUserCattrProvider (obj))
334                                         return obj.IsDefined (attributeType, inherit);
335
336                                 if (IsDefinedInternal (obj, attributeType))
337                                         return true;
338
339                                 object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
340                                 if (pseudoAttrs != null) {
341                                         for (int i = 0; i < pseudoAttrs.Length; ++i)
342                                                 if (attributeType.IsAssignableFrom (pseudoAttrs[i].GetType ()))
343                                                         return true;
344                                 }
345
346                                 if (usage == null) {
347                                         if (!inherit)
348                                                 return false;
349
350                                         usage = RetrieveAttributeUsage (attributeType);
351                                         if (!usage.Inherited)
352                                                 return false;
353                                 }
354
355                                 obj = GetBase (obj);
356                         } while (obj != null);
357
358                         return false;
359                 }
360
361                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
362                 internal static extern bool IsDefinedInternal (ICustomAttributeProvider obj, Type AttributeType);
363
364                 static PropertyInfo GetBasePropertyDefinition (MonoProperty property)
365                 {
366                         MethodInfo method = property.GetGetMethod (true);
367                         if (method == null || !method.IsVirtual)
368                                 method = property.GetSetMethod (true);
369                         if (method == null || !method.IsVirtual)
370                                 return null;
371
372                         MethodInfo baseMethod = method.GetBaseMethod ();
373                         if (baseMethod != null && baseMethod != method) {
374                                 ParameterInfo[] parameters = property.GetIndexParameters ();
375                                 if (parameters != null && parameters.Length > 0) {
376                                         Type[] paramTypes = new Type[parameters.Length];
377                                         for (int i=0; i < paramTypes.Length; i++)
378                                                 paramTypes[i] = parameters[i].ParameterType;
379                                         return baseMethod.DeclaringType.GetProperty (property.Name, property.PropertyType, 
380                                                                                      paramTypes);
381                                 } else {
382                                         return baseMethod.DeclaringType.GetProperty (property.Name, property.PropertyType);
383                                 }
384                         }
385                         return null;
386
387                 }
388
389                 static EventInfo GetBaseEventDefinition (MonoEvent evt)
390                 {
391                         MethodInfo method = evt.GetAddMethod (true);
392                         if (method == null || !method.IsVirtual)
393                                 method = evt.GetRaiseMethod (true);
394                         if (method == null || !method.IsVirtual)
395                                 method = evt.GetRemoveMethod (true);
396                         if (method == null || !method.IsVirtual)
397                                 return null;
398
399                         MethodInfo baseMethod = method.GetBaseMethod ();
400                         if (baseMethod != null && baseMethod != method) {
401                                 BindingFlags flags = method.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
402                                 flags |= method.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
403
404                                 return baseMethod.DeclaringType.GetEvent (evt.Name, flags);
405                         }
406                         return null;
407                 }
408
409                 // Handles Type, MonoProperty and MonoMethod.
410                 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
411                 // but for those we return null here.
412                 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
413                 {
414                         if (obj == null)
415                                 return null;
416
417                         if (obj is Type)
418                                 return ((Type) obj).BaseType;
419
420                         MethodInfo method = null;
421                         if (obj is MonoProperty)
422                                 return GetBasePropertyDefinition ((MonoProperty) obj);
423                         else if (obj is MonoEvent)
424                                 return GetBaseEventDefinition ((MonoEvent)obj);
425                         else if (obj is MonoMethod)
426                                 method = (MethodInfo) obj;
427
428                         /**
429                          * ParameterInfo -> null
430                          * Assembly -> null
431                          * MonoEvent -> null
432                          * MonoField -> null
433                          */
434                         if (method == null || !method.IsVirtual)
435                                 return null;
436
437                         MethodInfo baseMethod = method.GetBaseMethod ();
438                         if (baseMethod == method)
439                                 return null;
440
441                         return baseMethod;
442                 }
443
444                 private static AttributeUsageAttribute RetrieveAttributeUsageNoCache (Type attributeType)
445                 {
446                         if (attributeType == typeof (AttributeUsageAttribute))
447                                 /* Avoid endless recursion */
448                                 return new AttributeUsageAttribute (AttributeTargets.Class);
449
450                         AttributeUsageAttribute usageAttribute = null;
451                         object[] attribs = GetCustomAttributes (attributeType, typeof(AttributeUsageAttribute), false);
452                         if (attribs.Length == 0)
453                         {
454                                 // if no AttributeUsage was defined on the attribute level, then
455                                 // try to retrieve if from its base type
456                                 if (attributeType.BaseType != null)
457                                 {
458                                         usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
459
460                                 }
461                                 if (usageAttribute != null)
462                                 {
463                                         // return AttributeUsage of base class
464                                         return usageAttribute;
465
466                                 }
467                                 // return default AttributeUsageAttribute if no AttributeUsage 
468                                 // was defined on attribute, or its base class
469                                 return DefaultAttributeUsage;
470                         }
471                         // check if more than one AttributeUsageAttribute has been specified 
472                         // on the type
473                         // NOTE: compilers should prevent this, but that doesn't prevent
474                         // anyone from using IL ofcourse
475                         if (attribs.Length > 1)
476                         {
477                                 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
478                         }
479
480                         return ((AttributeUsageAttribute) attribs[0]);
481                 }
482
483                 static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
484                 {
485                         AttributeUsageAttribute usageAttribute = null;
486                         /* Usage a thread-local cache to speed this up, since it is called a lot from GetCustomAttributes () */
487                         if (usage_cache == null)
488                                 usage_cache = new Dictionary<Type, AttributeUsageAttribute> ();
489                         if (usage_cache.TryGetValue (attributeType, out usageAttribute))
490                                 return usageAttribute;
491                         usageAttribute = RetrieveAttributeUsageNoCache (attributeType);
492                         usage_cache [attributeType] = usageAttribute;
493                         return usageAttribute;
494                 }
495
496                 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
497                         new AttributeUsageAttribute (AttributeTargets.All);
498
499                 private class AttributeInfo
500                 {
501                         private AttributeUsageAttribute _usage;
502                         private int _inheritanceLevel;
503
504                         public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
505                         {
506                                 _usage = usage;
507                                 _inheritanceLevel = inheritanceLevel;
508                         }
509
510                         public AttributeUsageAttribute Usage
511                         {
512                                 get
513                                 {
514                                         return _usage;
515                                 }
516                         }
517
518                         public int InheritanceLevel
519                         {
520                                 get
521                                 {
522                                         return _inheritanceLevel;
523                                 }
524                         }
525                 }
526         }
527 }
528