This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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
39 namespace System
40 {
41         internal class MonoCustomAttrs
42         {
43                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
44                 internal static extern object[] GetCustomAttributes (ICustomAttributeProvider obj);
45
46                 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
47                                                                 Type attributeType,
48                                                                 bool inherit)
49                 {
50                         object[] res = GetCustomAttributes (obj, attributeType, inherit);
51                         if (res.Length == 0)
52                         {
53                                 return null;
54                         }
55                         else if (res.Length > 1)
56                         {
57                                 string msg = "'{0}' has more than one attribute of type '{1}";
58                                 msg = String.Format (msg, obj, attributeType);
59                                 throw new AmbiguousMatchException (msg);
60                         }
61
62                         return (Attribute) res[0];
63                 }
64
65                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
66                 {
67                         if (obj == null)
68                                 throw new ArgumentNullException ("obj");
69
70                         object[] r;
71                         object[] res = GetCustomAttributes (obj);
72                         // shortcut
73                         if (!inherit && res.Length == 1)
74                         {
75                                 if (attributeType != null)
76                                 {
77                                         if (attributeType.IsAssignableFrom (res[0].GetType ()))
78                                         {
79                                                 r = (object[]) Array.CreateInstance (attributeType, 1);
80                                                 r[0] = res[0];
81                                         }
82                                         else
83                                         {
84                                                 r = (object[]) Array.CreateInstance (attributeType, 0);
85                                         }
86                                 }
87                                 else
88                                 {
89                                         r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
90                                         r[0] = res[0];
91                                 }
92                                 return r;
93                         }
94
95                         // if AttributeType is sealed, and Inherited is set to false, then 
96                         // there's no use in scanning base types 
97                         if ((attributeType != null && attributeType.IsSealed) && !inherit)
98                         {
99                                 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
100                                         attributeType);
101                                 if (!usageAttribute.Inherited)
102                                 {
103                                         inherit = false;
104                                 }
105                         }
106
107                         int initialSize = res.Length < 16 ? res.Length : 16;
108
109                         Hashtable attributeInfos = new Hashtable (initialSize);
110                         ArrayList a = new ArrayList (initialSize);
111                         ICustomAttributeProvider btype = obj;
112
113                         int inheritanceLevel = 0;
114
115                         do
116                         {
117                                 foreach (object attr in res)
118                                 {
119                                         AttributeUsageAttribute usage;
120
121                                         Type attrType = attr.GetType ();
122                                         if (attributeType != null)
123                                         {
124                                                 if (!attributeType.IsAssignableFrom (attrType))
125                                                 {
126                                                         continue;
127                                                 }
128                                         }
129
130                                         AttributeInfo firstAttribute = (AttributeInfo) attributeInfos[attrType];
131                                         if (firstAttribute != null)
132                                         {
133                                                 usage = firstAttribute.Usage;
134                                         }
135                                         else
136                                         {
137                                                 usage = RetrieveAttributeUsage (attrType);
138                                         }
139
140                                         // only add attribute to the list of attributes if 
141                                         // - we are on the first inheritance level, or the attribute can be inherited anyway
142                                         // and (
143                                         // - multiple attributes of the type are allowed
144                                         // or (
145                                         // - this is the first attribute we've discovered
146                                         // or
147                                         // - the attribute is on same inheritance level than the first 
148                                         //   attribute that was discovered for this attribute type ))
149                                         if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple || 
150                                                 (firstAttribute == null || (firstAttribute != null 
151                                                         && firstAttribute.InheritanceLevel == inheritanceLevel))))
152                                         {
153                                                 a.Add (attr);
154                                         }
155
156                                         if (firstAttribute == null)
157                                         {
158                                                 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
159                                         }
160                                 }
161
162                                 if ((btype = GetBase (btype)) != null)
163                                 {
164                                         inheritanceLevel++;
165                                         res = GetCustomAttributes (btype);
166                                 }
167                         } while (inherit && btype != null);
168
169                         object[] array = null;
170                         if (attributeType == null || attributeType.IsValueType)
171                         {
172                                 array = (object[]) Array.CreateInstance (typeof(Attribute), a.Count);
173                         }
174                         else
175                         {
176                                 array = Array.CreateInstance (attributeType, a.Count) as object[];
177                         }
178
179                         // copy attributes to array
180                         a.CopyTo (array, 0);
181
182                         return array;
183                 }
184
185                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
186                 {
187                         if (obj == null)
188                                 throw new ArgumentNullException ("obj");
189
190                         if (!inherit)
191                                 return (object[]) GetCustomAttributes (obj).Clone ();
192
193                         return GetCustomAttributes (obj, null, inherit);
194                 }
195
196                 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
197                 {
198                         object[] res = GetCustomAttributes (obj);
199                         foreach (object attr in res)
200                         {
201                                 if (attributeType.Equals (attr.GetType ()))
202                                         return true;
203                         }
204
205                         ICustomAttributeProvider btype = GetBase (obj);
206                         if (inherit && (btype != null))
207                                 return IsDefined (btype, attributeType, inherit);
208
209                         return false;
210                 }
211
212                 // Handles Type, MonoProperty and MonoMethod.
213                 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
214                 // but for those we return null here.
215                 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
216                 {
217                         if (obj == null)
218                                 return null;
219
220                         if (obj is Type)
221                                 return ((Type) obj).BaseType;
222
223                         MethodInfo method = null;
224                         if (obj is MonoProperty)
225                         {
226                                 MonoProperty prop = (MonoProperty) obj;
227                                 method = prop.GetGetMethod (true);
228                                 if (method == null)
229                                         method = prop.GetSetMethod (true);
230                         }
231                         else if (obj is MonoMethod)
232                         {
233                                 method = (MethodInfo) obj;
234                         }
235
236                         /**
237                          * ParameterInfo -> null
238                          * Assembly -> null
239                          * MonoEvent -> null
240                          * MonoField -> null
241                          */
242                         if (method == null || !method.IsVirtual)
243                                 return null;
244
245                         MethodInfo baseMethod = method.GetBaseDefinition ();
246                         if (baseMethod == method)
247                                 return null;
248
249                         return baseMethod;
250                 }
251
252                 private static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
253                 {
254                         AttributeUsageAttribute usageAttribute = null;
255                         object[] attribs = GetCustomAttributes (attributeType,
256                                 MonoCustomAttrs.AttributeUsageType, false);
257                         if (attribs.Length == 0)
258                         {
259                                 // if no AttributeUsage was defined on the attribute level, then
260                                 // try to retrieve if from its base type
261                                 if (attributeType.BaseType != null)
262                                 {
263                                         usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
264
265                                 }
266                                 if (usageAttribute != null)
267                                 {
268                                         // return AttributeUsage of base class
269                                         return usageAttribute;
270
271                                 }
272                                 // return default AttributeUsageAttribute if no AttributeUsage 
273                                 // was defined on attribute, or its base class
274                                 return DefaultAttributeUsage;
275                         }
276                         // check if more than one AttributeUsageAttribute has been specified 
277                         // on the type
278                         // NOTE: compilers should prevent this, but that doesn't prevent
279                         // anyone from using IL ofcourse
280                         if (attribs.Length > 1)
281                         {
282                                 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
283                         }
284
285                         return ((AttributeUsageAttribute) attribs[0]);
286                 }
287
288                 private static readonly Type AttributeUsageType = typeof(AttributeUsageAttribute);
289                 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
290                         new AttributeUsageAttribute (AttributeTargets.All);
291
292                 private class AttributeInfo
293                 {
294                         private AttributeUsageAttribute _usage;
295                         private int _inheritanceLevel;
296
297                         public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
298                         {
299                                 _usage = usage;
300                                 _inheritanceLevel = inheritanceLevel;
301                         }
302
303                         public AttributeUsageAttribute Usage
304                         {
305                                 get
306                                 {
307                                         return _usage;
308                                 }
309                         }
310
311                         public int InheritanceLevel
312                         {
313                                 get
314                                 {
315                                         return _inheritanceLevel;
316                                 }
317                         }
318                 }
319         }
320 }
321