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