2003-02-18 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 object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
35                 {
36                         if (obj == null)
37                                 return (object []) Array.CreateInstance (attributeType, 0);
38
39                         object[] r;
40                         object[] res = from_cache (obj);
41                         // shortcut
42                         if (!inherit && res.Length == 1) {
43                                 if (attributeType.IsAssignableFrom (res[0].GetType ())) {
44                                         r = (object []) Array.CreateInstance (attributeType, 1);
45                                         r [0] = res [0];
46                                 } else {
47                                         r = (object []) Array.CreateInstance (attributeType, 0);
48                                 }
49                                 return r;
50                         }
51
52                         ArrayList a = new ArrayList ();
53                         ICustomAttributeProvider btype = obj;
54                         do {
55                                 foreach (object attr in res)
56                                         if (attributeType.IsAssignableFrom (attr.GetType ()))
57                                                 a.Add (attr);
58
59                                 if ((btype = GetBase (btype)) != null)
60                                         res = from_cache (btype);
61                         } while (inherit && btype != null);
62
63                         return (object []) a.ToArray (attributeType);
64                 }
65
66                 internal static object [] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
67                 {
68                         if (obj == null)
69                                 return new object [0]; //FIXME: Should i throw an exception here?
70
71                         if (!inherit)
72                                 return (object []) from_cache (obj).Clone ();
73
74                         ArrayList a = new ArrayList ();
75                         ICustomAttributeProvider btype = obj;
76                         a.AddRange (from_cache (btype));
77                         while ((btype = GetBase (btype)) != null)
78                                 a.AddRange (from_cache (btype));
79
80                         return (object []) a.ToArray (typeof (Attribute));
81                 }
82
83                 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
84                 {
85                         object[] res = from_cache (obj);
86                         foreach (object attr in res) {
87                                 if (attributeType.Equals (attr.GetType ()))
88                                         return true;
89                         }
90
91                         ICustomAttributeProvider btype = GetBase (obj);
92                         if (inherit && (btype != null))
93                                 return IsDefined (btype, attributeType, inherit);
94
95                         return false;
96                 }
97
98                 // Handles Type, MonoProperty and MonoMethod.
99                 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
100                 // but for those we return null here.
101                 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
102                 {
103                         if (obj == null)
104                                 return null;
105
106                         if (obj is Type)
107                                 return ((Type) obj).BaseType;
108
109                         MethodInfo method = null;
110                         if (obj is MonoProperty) {
111                                 MonoProperty prop = (MonoProperty) obj;
112                                 method = prop.GetGetMethod ();
113                                 if (method == null)
114                                         method = prop.GetSetMethod ();
115                         } else if (obj is MonoMethod) {
116                                 method = (MethodInfo) obj; 
117                         }
118
119                         /**
120                          * ParameterInfo -> null
121                          * Assembly -> null
122                          * MonoEvent -> null
123                          * MonoField -> null
124                          */
125                         if (method == null || !method.IsVirtual)
126                                 return null;
127
128                         MethodInfo baseMethod = method.GetBaseDefinition ();
129                         if (baseMethod == method)
130                                 return null;
131
132                         return baseMethod;
133                 }
134         }
135 }
136