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