2003-02-24 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[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         internal class MonoCustomAttrs {
18
19                 static Hashtable handle_to_attrs = new Hashtable ();
20
21                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
22                 internal static extern object[] GetCustomAttributes (ICustomAttributeProvider obj);
23
24                 private static object[] from_cache (ICustomAttributeProvider obj)
25                 {
26                         object[] res = (object []) handle_to_attrs [obj];
27                         if (res != null)
28                                 return res;
29                         res = GetCustomAttributes (obj);
30                         handle_to_attrs.Add (obj, res);
31                         return res;
32                 }
33
34                 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
35                                                               Type attributeType,
36                                                               bool inherit)
37                 {
38                         if (obj == null)
39                                 throw new ArgumentNullException ("attribute_type"); // argument name in the caller
40
41                         object[] res = from_cache (obj);
42                         ICustomAttributeProvider btype = obj;
43                         Attribute result = null;
44
45                         do {
46                                 foreach (object attr in res) {
47                                         if (!attributeType.IsAssignableFrom (attr.GetType ()))
48                                                 continue;
49
50                                         if (result != null) {
51                                                 string msg = "'{0}' has more than one attribute of type '{1}";
52                                                 msg = String.Format (msg, obj, attributeType);
53                                                 throw new AmbiguousMatchException (msg);
54                                         }
55                                         result = (Attribute) attr;
56                                 }
57
58                                 if (inherit && (btype = GetBase (btype)) != null)
59                                         res = from_cache (btype);
60
61                         // Stop when encounters the first one for a given provider.
62                         } while (inherit && result == null && btype != null);
63
64                         return result;
65                 }
66
67                 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
68                 {
69                         if (obj == null)
70                                 return (object []) Array.CreateInstance (attributeType, 0);
71
72                         object[] r;
73                         object[] res = from_cache (obj);
74                         // shortcut
75                         if (!inherit && res.Length == 1) {
76                                 if (attributeType.IsAssignableFrom (res[0].GetType ())) {
77                                         r = (object []) Array.CreateInstance (attributeType, 1);
78                                         r [0] = res [0];
79                                 } else {
80                                         r = (object []) Array.CreateInstance (attributeType, 0);
81                                 }
82                                 return r;
83                         }
84
85                         ArrayList a = new ArrayList ();
86                         ICustomAttributeProvider btype = obj;
87                         do {
88                                 foreach (object attr in res)
89                                         if (attributeType.IsAssignableFrom (attr.GetType ()))
90                                                 a.Add (attr);
91
92                                 if ((btype = GetBase (btype)) != null)
93                                         res = from_cache (btype);
94                         } while (inherit && btype != null);
95
96                         return (object []) a.ToArray (attributeType);
97                 }
98
99                 internal static object [] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
100                 {
101                         if (obj == null)
102                                 return new object [0]; //FIXME: Should i throw an exception here?
103
104                         if (!inherit)
105                                 return (object []) from_cache (obj).Clone ();
106
107                         ArrayList a = new ArrayList ();
108                         ICustomAttributeProvider btype = obj;
109                         a.AddRange (from_cache (btype));
110                         while ((btype = GetBase (btype)) != null)
111                                 a.AddRange (from_cache (btype));
112
113                         return (object []) a.ToArray (typeof (Attribute));
114                 }
115
116                 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
117                 {
118                         object[] res = from_cache (obj);
119                         foreach (object attr in res) {
120                                 if (attributeType.Equals (attr.GetType ()))
121                                         return true;
122                         }
123
124                         ICustomAttributeProvider btype = GetBase (obj);
125                         if (inherit && (btype != null))
126                                 return IsDefined (btype, attributeType, inherit);
127
128                         return false;
129                 }
130
131                 // Handles Type, MonoProperty and MonoMethod.
132                 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
133                 // but for those we return null here.
134                 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
135                 {
136                         if (obj == null)
137                                 return null;
138
139                         if (obj is Type)
140                                 return ((Type) obj).BaseType;
141
142                         MethodInfo method = null;
143                         if (obj is MonoProperty) {
144                                 MonoProperty prop = (MonoProperty) obj;
145                                 method = prop.GetGetMethod ();
146                                 if (method == null)
147                                         method = prop.GetSetMethod ();
148                         } else if (obj is MonoMethod) {
149                                 method = (MethodInfo) obj; 
150                         }
151
152                         /**
153                          * ParameterInfo -> null
154                          * Assembly -> null
155                          * MonoEvent -> null
156                          * MonoField -> null
157                          */
158                         if (method == null || !method.IsVirtual)
159                                 return null;
160
161                         MethodInfo baseMethod = method.GetBaseDefinition ();
162                         if (baseMethod == method)
163                                 return null;
164
165                         return baseMethod;
166                 }
167         }
168 }
169