[Mono.Debugger.Soft] Implemented MethodMirror.GetCustomAttributes()
[mono.git] / mcs / class / Mono.Debugger.Soft / Mono.Debugger.Soft / MethodMirror.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Reflection;
5 using C = Mono.Cecil;
6 using Mono.Cecil.Metadata;
7
8 namespace Mono.Debugger.Soft
9 {
10         public class MethodMirror : Mirror
11         {
12                 string name;
13                 MethodInfo info;
14                 TypeMirror declaring_type;
15                 DebugInfo debug_info;
16                 C.MethodDefinition meta;
17                 CustomAttributeDataMirror[] cattrs;
18                 ParameterInfoMirror[] param_info;
19                 ParameterInfoMirror ret_param;
20                 LocalVariable[] locals;
21                 IList<Location> locations;
22                 MethodBodyMirror body;
23                 MethodMirror gmd;
24                 TypeMirror[] type_args;
25
26                 internal MethodMirror (VirtualMachine vm, long id) : base (vm, id) {
27                 }
28
29                 public string Name {
30                         get {
31                                 if (name == null)
32                                         name = vm.conn.Method_GetName (id);
33                                 return name;
34                         }
35                 }
36
37                 public TypeMirror DeclaringType {
38                         get {
39                                 if (declaring_type == null)
40                                         declaring_type = vm.GetType (vm.conn.Method_GetDeclaringType (id));
41                                 return declaring_type;
42                         }
43                 }
44
45                 public TypeMirror ReturnType {
46                         get {
47                                 return ReturnParameter.ParameterType;
48                         }
49                 }
50
51                 // FIXME:
52                 public string FullName {
53                         get {
54                                 string type_namespace = DeclaringType.Namespace;
55                                 string type_name = DeclaringType.Name;
56                                 StringBuilder sb = new StringBuilder ();
57                                 sb.Append (ReturnType.Name);
58                                 sb.Append (' ');
59                                 if (type_namespace != String.Empty)
60                                         sb.Append (type_namespace + ".");
61                                 sb.Append(type_name);
62                                 sb.Append(":");
63                                 sb.Append(Name);
64                                 sb.Append(" ");
65                                 sb.Append("(");
66                                 for (var i = 0; i < param_info.Length; i++) {
67                                         sb.Append(param_info[i].ParameterType.Name);
68                                         if (i != param_info.Length - 1)
69                                                 sb.Append(", ");
70                                 }
71                                 sb.Append(")");
72                                 return sb.ToString ();
73                         }
74                 }
75
76                 /*
77                  * Creating the custom attributes themselves could modify the behavior of the
78                  * debuggee, so we return objects similar to the CustomAttributeData objects
79                  * used by the reflection-only functionality on .net.
80                  */
81                 public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
82                         return GetCAttrs (null, inherit);
83                 }
84
85                 public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
86                         if (attributeType == null)
87                                 throw new ArgumentNullException ("attributeType");
88                         return GetCAttrs (attributeType, inherit);
89                 }
90
91                 CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
92                         if (cattrs == null && Metadata != null && !Metadata.HasCustomAttributes)
93                                 cattrs = new CustomAttributeDataMirror [0];
94
95                         // FIXME: Handle inherit
96                         if (cattrs == null) {
97                                 CattrInfo[] info = vm.conn.Type_GetCustomAttributes (id, 0, false);
98                                 cattrs = CustomAttributeDataMirror.Create (vm, info);
99                         }
100                         var res = new List<CustomAttributeDataMirror> ();
101                         foreach (var attr in cattrs)
102                                 if (type == null || attr.Constructor.DeclaringType == type)
103                                         res.Add (attr);
104                         return res.ToArray ();
105                 }
106
107                 MethodInfo GetInfo () {
108                         if (info == null)
109                                 info = vm.conn.Method_GetInfo (id);
110                         
111                         return info;
112                 }
113
114                 public int MetadataToken {
115                         get {
116                                 return GetInfo ().token;
117                         }
118                 }
119
120                 public MethodAttributes Attributes {
121                         get {
122                                 return (MethodAttributes) GetInfo ().attributes;
123                         }
124                 }
125
126                 public bool IsPublic { 
127                         get {
128                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;
129                         }
130                 }
131                 public bool IsPrivate {
132                         get {
133                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
134                         }
135                 }
136                 public bool IsFamily {
137                         get {
138                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family;
139                         }
140                 }
141                 public bool IsAssembly {
142                         get {
143                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly;
144                         }
145                 }
146                 public bool IsFamilyAndAssembly {
147                         get {
148                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem;
149                         }
150                 }
151                 public bool IsFamilyOrAssembly {
152                         get {
153                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem;
154                         }
155                 }
156                 public bool IsStatic {
157                         get {
158                                 return (Attributes & MethodAttributes.Static) != 0;
159                         }
160                 }
161                 public bool IsFinal {
162                         get {
163                                 return (Attributes & MethodAttributes.Final) != 0;
164                         }
165                 }
166                 public bool IsVirtual {
167                         get {
168                                 return (Attributes & MethodAttributes.Virtual) != 0;
169                         }
170                 }
171                 public bool IsHideBySig {
172                         get {
173                                 return (Attributes & MethodAttributes.HideBySig) != 0;
174                         }
175                 }
176                 public bool IsAbstract {
177                         get {
178                                 return (Attributes & MethodAttributes.Abstract) != 0;
179                         }
180                 }
181                 public bool IsSpecialName {
182                         get {
183                                 return (Attributes & MethodAttributes.SpecialName) != 0;
184                         }
185                 }
186
187                 public bool IsConstructor {
188                         get {
189                                 int attr = (int)Attributes;
190                                 return ((attr & (int)MethodAttributes.RTSpecialName) != 0
191                                         && (Name == ".ctor"));
192                         }
193                 }
194
195                 // Since protocol version 2.12
196                 public bool IsGenericMethodDefinition {
197                         get {
198                                 vm.CheckProtocolVersion (2, 12);
199                                 return GetInfo ().is_gmd;
200                         }
201                 }
202
203                 // Since protocol version 2.12
204                 public bool IsGenericMethod {
205                         get {
206                                 vm.CheckProtocolVersion (2, 12);
207                                 return GetInfo ().is_generic_method;
208                         }
209                 }
210
211                 public MethodImplAttributes GetMethodImplementationFlags() {
212                         return (MethodImplAttributes)GetInfo ().iattributes;
213                 }
214
215                 public ParameterInfoMirror[] GetParameters () {
216                         if (param_info == null) {
217                                 var pi = vm.conn.Method_GetParamInfo (id);
218                                 param_info = new ParameterInfoMirror [pi.param_count];
219                                 // Return
220                                 ret_param = new ParameterInfoMirror (this, -1, vm.GetType (pi.ret_type), null, ParameterAttributes.Retval);
221                                 // FIXME: this
222                                 // FIXME: Attributes
223                                 for (int i = 0; i < pi.param_count; ++i) {
224                                         param_info [i] = new ParameterInfoMirror (this, i, vm.GetType (pi.param_types [i]), pi.param_names [i], 0);
225                                 }
226                         }
227
228                         return param_info;
229                 }
230
231                 public ParameterInfoMirror ReturnParameter {
232                         get {
233                                 if (ret_param == null)
234                                         GetParameters ();
235                                 return ret_param;
236                         }
237                 }
238
239                 public LocalVariable[] GetLocals () {
240                         if (locals == null) {
241
242                                 LocalsInfo li = new LocalsInfo ();
243                                 try {
244                                         li = vm.conn.Method_GetLocalsInfo (id);
245                                 } catch (CommandException) {
246                                         throw new ArgumentException ("Method doesn't have a body.");
247                                 }
248                                 // Add the arguments as well
249                                 var pi = vm.conn.Method_GetParamInfo (id);
250
251                                 locals = new LocalVariable [pi.param_count + li.names.Length];
252
253                                 for (int i = 0; i < pi.param_count; ++i)
254                                         locals [i] = new LocalVariable (vm, this, i, pi.param_types [i], pi.param_names [i], -1, -1, true);
255
256                                 for (int i = 0; i < li.names.Length; ++i)
257                                         locals [i + pi.param_count] = new LocalVariable (vm, this, i, li.types [i], li.names [i], li.live_range_start [i], li.live_range_end [i], false);
258                         }
259                         return locals;
260                 }
261
262                 public LocalVariable GetLocal (string name) {
263                         if (name == null)
264                                 throw new ArgumentNullException ("name");
265
266                         GetLocals ();
267
268                         LocalVariable res = null;
269                         for (int i = 0; i < locals.Length; ++i) {
270                                 if (locals [i].Name == name) {
271                                         if (res != null)
272                                                 throw new AmbiguousMatchException ("More that one local has the name '" + name + "'.");
273                                         res = locals [i];
274                                 }
275                         }
276
277                         return res;
278                 }
279
280                 public MethodBodyMirror GetMethodBody () {
281                         if (body == null) {
282                                 MethodBodyInfo info = vm.conn.Method_GetBody (id);
283
284                                 body = new MethodBodyMirror (vm, this, info);
285                         }
286                         return body;
287                 }
288
289                 public MethodMirror GetGenericMethodDefinition () {
290                         vm.CheckProtocolVersion (2, 12);
291                         if (gmd == null) {
292                                 if (info.gmd == 0)
293                                         throw new InvalidOperationException ();
294                                 gmd = vm.GetMethod (info.gmd);
295                         }
296                         return gmd;
297                 }
298
299                 // Since protocol version 2.15
300                 public TypeMirror[] GetGenericArguments () {
301                         vm.CheckProtocolVersion (2, 15);
302                         if (type_args == null)
303                                 type_args = vm.GetTypes (GetInfo ().type_args);
304                         return type_args;
305                 }
306
307                 public IList<int> ILOffsets {
308                         get {
309                                 if (debug_info == null)
310                                         debug_info = vm.conn.Method_GetDebugInfo (id);
311                                 return Array.AsReadOnly (debug_info.il_offsets);
312                         }
313                 }
314
315                 public IList<int> LineNumbers {
316                         get {
317                                 if (debug_info == null)
318                                         debug_info = vm.conn.Method_GetDebugInfo (id);
319                                 return Array.AsReadOnly (debug_info.line_numbers);
320                         }
321                 }
322
323                 public string SourceFile {
324                         get {
325                                 if (debug_info == null)
326                                         debug_info = vm.conn.Method_GetDebugInfo (id);
327                                 return debug_info.source_files.Length > 0 ? debug_info.source_files [0].source_file : null;
328                         }
329                 }
330
331                 public IList<Location> Locations {
332                         get {
333                                 if (locations == null) {
334                                         var il_offsets = ILOffsets;
335                                         var line_numbers = LineNumbers;
336                                         IList<Location> res = new Location [ILOffsets.Count];
337                                         for (int i = 0; i < il_offsets.Count; ++i)
338                                                 res [i] = new Location (vm, this, -1, il_offsets [i], debug_info.source_files [i].source_file, line_numbers [i], debug_info.column_numbers [i], debug_info.source_files [i].hash);
339                                         locations = res;
340                                 }
341                                 return locations;
342                         }
343                 }                               
344
345                 internal int il_offset_to_line_number (int il_offset, out string src_file, out byte[] src_hash, out int column_number) {
346                         if (debug_info == null)
347                                 debug_info = vm.conn.Method_GetDebugInfo (id);
348
349                         // FIXME: Optimize this
350                         src_file = null;
351                         src_hash = null;
352                         column_number = 0;
353                         for (int i = debug_info.il_offsets.Length - 1; i >= 0; --i) {
354                                 if (debug_info.il_offsets [i] <= il_offset) {
355                                         src_file = debug_info.source_files [i].source_file;
356                                         src_hash = debug_info.source_files [i].hash;
357                                         column_number = debug_info.column_numbers [i];
358                                         return debug_info.line_numbers [i];
359                                 }
360                         }
361                         return -1;
362                 }
363
364                 public Location LocationAtILOffset (int il_offset) {
365                         IList<Location> locs = Locations;
366
367                         // FIXME: Optimize this
368                         for (int i = locs.Count - 1; i >= 0; --i) {
369                                 if (locs [i].ILOffset <= il_offset)
370                                         return locs [i];
371                         }
372
373                         return null;
374                 }
375
376                 public C.MethodDefinition Metadata {
377                         get {
378                                 if (meta == null)
379                                         meta = (C.MethodDefinition)DeclaringType.Assembly.Metadata.MainModule.LookupToken (MetadataToken);
380                                 return meta;
381                         }
382                 }
383         }
384 }