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