1 // System.MonoCustomAttrs.cs
2 // Hooks into the runtime to get custom attributes for reflection handles
5 // Paolo Molaro (lupus@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
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.
35 using System
.Reflection
;
36 using System
.Collections
;
37 using System
.Runtime
.CompilerServices
;
41 internal class MonoCustomAttrs
43 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
44 internal static extern object[] GetCustomAttributesInternal (ICustomAttributeProvider obj
, bool pseudoAttrs
);
46 internal static object[] GetCustomAttributesBase (ICustomAttributeProvider obj
)
48 object[] attrs
= GetCustomAttributesInternal (obj
, false);
50 #if NET_2_0 || BOOTSTRAP_NET_2_0
51 object[] pseudoAttrs
= null;
53 /* FIXME: Add other types */
55 pseudoAttrs
= ((Type
)obj
).GetPseudoCustomAttributes ();
56 else if (obj
is MonoMethod
)
57 pseudoAttrs
= ((MonoMethod
)obj
).GetPseudoCustomAttributes ();
58 else if (obj
is FieldInfo
)
59 pseudoAttrs
= ((FieldInfo
)obj
).GetPseudoCustomAttributes ();
60 else if (obj
is ParameterInfo
)
61 pseudoAttrs
= ((ParameterInfo
)obj
).GetPseudoCustomAttributes ();
63 if (pseudoAttrs
!= null) {
64 object[] res
= new object [attrs
.Length
+ pseudoAttrs
.Length
];
65 System
.Array
.Copy (attrs
, res
, attrs
.Length
);
66 System
.Array
.Copy (pseudoAttrs
, 0, res
, attrs
.Length
, pseudoAttrs
.Length
);
76 internal static Attribute
GetCustomAttribute (ICustomAttributeProvider obj
,
80 object[] res
= GetCustomAttributes (obj
, attributeType
, inherit
);
85 else if (res
.Length
> 1)
87 string msg
= "'{0}' has more than one attribute of type '{1}";
88 msg
= String
.Format (msg
, obj
, attributeType
);
89 throw new AmbiguousMatchException (msg
);
92 return (Attribute
) res
[0];
95 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj
, Type attributeType
, bool inherit
)
98 throw new ArgumentNullException ("obj");
101 object[] res
= GetCustomAttributesBase (obj
);
103 if (!inherit
&& res
.Length
== 1)
105 if (attributeType
!= null)
107 if (attributeType
.IsAssignableFrom (res
[0].GetType ()))
109 r
= (object[]) Array
.CreateInstance (attributeType
, 1);
114 r
= (object[]) Array
.CreateInstance (attributeType
, 0);
119 r
= (object[]) Array
.CreateInstance (res
[0].GetType (), 1);
125 // if AttributeType is sealed, and Inherited is set to false, then
126 // there's no use in scanning base types
127 if ((attributeType
!= null && attributeType
.IsSealed
) && inherit
)
129 AttributeUsageAttribute usageAttribute
= RetrieveAttributeUsage (
131 if (!usageAttribute
.Inherited
)
137 int initialSize
= res
.Length
< 16 ? res
.Length
: 16;
139 Hashtable attributeInfos
= new Hashtable (initialSize
);
140 ArrayList a
= new ArrayList (initialSize
);
141 ICustomAttributeProvider btype
= obj
;
143 int inheritanceLevel
= 0;
147 foreach (object attr
in res
)
149 AttributeUsageAttribute usage
;
151 Type attrType
= attr
.GetType ();
152 if (attributeType
!= null)
154 if (!attributeType
.IsAssignableFrom (attrType
))
160 AttributeInfo firstAttribute
= (AttributeInfo
) attributeInfos
[attrType
];
161 if (firstAttribute
!= null)
163 usage
= firstAttribute
.Usage
;
167 usage
= RetrieveAttributeUsage (attrType
);
170 // only add attribute to the list of attributes if
171 // - we are on the first inheritance level, or the attribute can be inherited anyway
173 // - multiple attributes of the type are allowed
175 // - this is the first attribute we've discovered
177 // - the attribute is on same inheritance level than the first
178 // attribute that was discovered for this attribute type ))
179 if ((inheritanceLevel
== 0 || usage
.Inherited
) && (usage
.AllowMultiple
||
180 (firstAttribute
== null || (firstAttribute
!= null
181 && firstAttribute
.InheritanceLevel
== inheritanceLevel
))))
186 if (firstAttribute
== null)
188 attributeInfos
.Add (attrType
, new AttributeInfo (usage
, inheritanceLevel
));
192 if ((btype
= GetBase (btype
)) != null)
195 res
= GetCustomAttributesBase (btype
);
197 } while (inherit
&& btype
!= null);
199 object[] array
= null;
200 if (attributeType
== null || attributeType
.IsValueType
)
202 array
= (object[]) Array
.CreateInstance (typeof(Attribute
), a
.Count
);
206 array
= Array
.CreateInstance (attributeType
, a
.Count
) as object[];
209 // copy attributes to array
215 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj
, bool inherit
)
218 throw new ArgumentNullException ("obj");
221 return (object[]) GetCustomAttributesBase (obj
).Clone ();
223 return GetCustomAttributes (obj
, null, inherit
);
226 internal static bool IsDefined (ICustomAttributeProvider obj
, Type attributeType
, bool inherit
)
228 object [] res
= GetCustomAttributesBase (obj
);
229 foreach (object attr
in res
)
230 if (attributeType
.Equals (attr
.GetType ()))
233 ICustomAttributeProvider btype
;
234 if (inherit
&& ((btype
= GetBase (obj
)) != null))
235 return IsDefined (btype
, attributeType
, inherit
);
240 // Handles Type, MonoProperty and MonoMethod.
241 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
242 // but for those we return null here.
243 static ICustomAttributeProvider
GetBase (ICustomAttributeProvider obj
)
249 return ((Type
) obj
).BaseType
;
251 MethodInfo method
= null;
252 if (obj
is MonoProperty
)
254 MonoProperty prop
= (MonoProperty
) obj
;
255 method
= prop
.GetGetMethod (true);
257 method
= prop
.GetSetMethod (true);
259 else if (obj
is MonoMethod
)
261 method
= (MethodInfo
) obj
;
265 * ParameterInfo -> null
270 if (method
== null || !method
.IsVirtual
)
273 MethodInfo baseMethod
= method
.GetBaseDefinition ();
274 if (baseMethod
== method
)
280 private static AttributeUsageAttribute
RetrieveAttributeUsage (Type attributeType
)
282 if (attributeType
== typeof (AttributeUsageAttribute
))
283 /* Avoid endless recursion */
284 return new AttributeUsageAttribute (AttributeTargets
.Class
);
286 AttributeUsageAttribute usageAttribute
= null;
287 object[] attribs
= GetCustomAttributes (attributeType
,
288 MonoCustomAttrs
.AttributeUsageType
, false);
289 if (attribs
.Length
== 0)
291 // if no AttributeUsage was defined on the attribute level, then
292 // try to retrieve if from its base type
293 if (attributeType
.BaseType
!= null)
295 usageAttribute
= RetrieveAttributeUsage (attributeType
.BaseType
);
298 if (usageAttribute
!= null)
300 // return AttributeUsage of base class
301 return usageAttribute
;
304 // return default AttributeUsageAttribute if no AttributeUsage
305 // was defined on attribute, or its base class
306 return DefaultAttributeUsage
;
308 // check if more than one AttributeUsageAttribute has been specified
310 // NOTE: compilers should prevent this, but that doesn't prevent
311 // anyone from using IL ofcourse
312 if (attribs
.Length
> 1)
314 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
317 return ((AttributeUsageAttribute
) attribs
[0]);
320 private static readonly Type AttributeUsageType
= typeof(AttributeUsageAttribute
);
321 private static readonly AttributeUsageAttribute DefaultAttributeUsage
=
322 new AttributeUsageAttribute (AttributeTargets
.All
);
324 private class AttributeInfo
326 private AttributeUsageAttribute _usage
;
327 private int _inheritanceLevel
;
329 public AttributeInfo (AttributeUsageAttribute usage
, int inheritanceLevel
)
332 _inheritanceLevel
= inheritanceLevel
;
335 public AttributeUsageAttribute Usage
343 public int InheritanceLevel
347 return _inheritanceLevel
;