Added tests for Task.WhenAll w/ empty list
[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                  * Since protocol version 2.21
81                  */
82                 public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
83                         return GetCAttrs (null, inherit);
84                 }
85
86                 /* Since protocol version 2.21 */
87                 public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
88                         if (attributeType == null)
89                                 throw new ArgumentNullException ("attributeType");
90                         return GetCAttrs (attributeType, inherit);
91                 }
92
93                 CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
94                         if (cattrs == null && meta != null && !Metadata.HasCustomAttributes)
95                                 cattrs = new CustomAttributeDataMirror [0];
96
97                         // FIXME: Handle inherit
98                         if (cattrs == null) {
99                                 CattrInfo[] info = vm.conn.Method_GetCustomAttributes (id, 0, false);
100                                 cattrs = CustomAttributeDataMirror.Create (vm, info);
101                         }
102                         var res = new List<CustomAttributeDataMirror> ();
103                         foreach (var attr in cattrs)
104                                 if (type == null || attr.Constructor.DeclaringType == type)
105                                         res.Add (attr);
106                         return res.ToArray ();
107                 }
108
109                 MethodInfo GetInfo () {
110                         if (info == null)
111                                 info = vm.conn.Method_GetInfo (id);
112                         
113                         return info;
114                 }
115
116                 public int MetadataToken {
117                         get {
118                                 return GetInfo ().token;
119                         }
120                 }
121
122                 public MethodAttributes Attributes {
123                         get {
124                                 return (MethodAttributes) GetInfo ().attributes;
125                         }
126                 }
127
128                 public bool IsPublic { 
129                         get {
130                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;
131                         }
132                 }
133                 public bool IsPrivate {
134                         get {
135                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
136                         }
137                 }
138                 public bool IsFamily {
139                         get {
140                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family;
141                         }
142                 }
143                 public bool IsAssembly {
144                         get {
145                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly;
146                         }
147                 }
148                 public bool IsFamilyAndAssembly {
149                         get {
150                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem;
151                         }
152                 }
153                 public bool IsFamilyOrAssembly {
154                         get {
155                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem;
156                         }
157                 }
158                 public bool IsStatic {
159                         get {
160                                 return (Attributes & MethodAttributes.Static) != 0;
161                         }
162                 }
163                 public bool IsFinal {
164                         get {
165                                 return (Attributes & MethodAttributes.Final) != 0;
166                         }
167                 }
168                 public bool IsVirtual {
169                         get {
170                                 return (Attributes & MethodAttributes.Virtual) != 0;
171                         }
172                 }
173                 public bool IsHideBySig {
174                         get {
175                                 return (Attributes & MethodAttributes.HideBySig) != 0;
176                         }
177                 }
178                 public bool IsAbstract {
179                         get {
180                                 return (Attributes & MethodAttributes.Abstract) != 0;
181                         }
182                 }
183                 public bool IsSpecialName {
184                         get {
185                                 return (Attributes & MethodAttributes.SpecialName) != 0;
186                         }
187                 }
188
189                 public bool IsConstructor {
190                         get {
191                                 int attr = (int)Attributes;
192                                 return ((attr & (int)MethodAttributes.RTSpecialName) != 0
193                                         && (Name == ".ctor"));
194                         }
195                 }
196
197                 // Since protocol version 2.12
198                 public bool IsGenericMethodDefinition {
199                         get {
200                                 vm.CheckProtocolVersion (2, 12);
201                                 return GetInfo ().is_gmd;
202                         }
203                 }
204
205                 // Since protocol version 2.12
206                 public bool IsGenericMethod {
207                         get {
208                                 vm.CheckProtocolVersion (2, 12);
209                                 return GetInfo ().is_generic_method;
210                         }
211                 }
212
213                 public MethodImplAttributes GetMethodImplementationFlags() {
214                         return (MethodImplAttributes)GetInfo ().iattributes;
215                 }
216
217                 public ParameterInfoMirror[] GetParameters () {
218                         if (param_info == null) {
219                                 var pi = vm.conn.Method_GetParamInfo (id);
220                                 param_info = new ParameterInfoMirror [pi.param_count];
221                                 // Return
222                                 ret_param = new ParameterInfoMirror (this, -1, vm.GetType (pi.ret_type), null, ParameterAttributes.Retval);
223                                 // FIXME: this
224                                 // FIXME: Attributes
225                                 for (int i = 0; i < pi.param_count; ++i) {
226                                         param_info [i] = new ParameterInfoMirror (this, i, vm.GetType (pi.param_types [i]), pi.param_names [i], 0);
227                                 }
228                         }
229
230                         return param_info;
231                 }
232
233                 public ParameterInfoMirror ReturnParameter {
234                         get {
235                                 if (ret_param == null)
236                                         GetParameters ();
237                                 return ret_param;
238                         }
239                 }
240
241                 public LocalVariable[] GetLocals () {
242                         if (locals == null) {
243                                 LocalsInfo li = new LocalsInfo ();
244                                 try {
245                                         li = vm.conn.Method_GetLocalsInfo (id);
246                                 } catch (CommandException) {
247                                         throw new AbsentInformationException ();
248                                 }
249
250                                 // Add the arguments as well
251                                 var pi = vm.conn.Method_GetParamInfo (id);
252
253                                 locals = new LocalVariable [pi.param_count + li.names.Length];
254
255                                 for (int i = 0; i < pi.param_count; ++i)
256                                         locals [i] = new LocalVariable (vm, this, i, pi.param_types [i], pi.param_names [i], -1, -1, true);
257
258                                 for (int i = 0; i < li.names.Length; ++i)
259                                         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);
260                         }
261                         return locals;
262                 }
263
264                 public LocalVariable GetLocal (string name) {
265                         if (name == null)
266                                 throw new ArgumentNullException ("name");
267
268                         GetLocals ();
269
270                         LocalVariable res = null;
271                         for (int i = 0; i < locals.Length; ++i) {
272                                 if (locals [i].Name == name) {
273                                         if (res != null)
274                                                 throw new AmbiguousMatchException ("More that one local has the name '" + name + "'.");
275                                         res = locals [i];
276                                 }
277                         }
278
279                         return res;
280                 }
281
282                 public MethodBodyMirror GetMethodBody () {
283                         if (body == null) {
284                                 MethodBodyInfo info = vm.conn.Method_GetBody (id);
285
286                                 body = new MethodBodyMirror (vm, this, info);
287                         }
288                         return body;
289                 }
290
291                 public MethodMirror GetGenericMethodDefinition () {
292                         vm.CheckProtocolVersion (2, 12);
293                         if (gmd == null) {
294                                 if (info.gmd == 0)
295                                         throw new InvalidOperationException ();
296                                 gmd = vm.GetMethod (info.gmd);
297                         }
298                         return gmd;
299                 }
300
301                 // Since protocol version 2.15
302                 public TypeMirror[] GetGenericArguments () {
303                         vm.CheckProtocolVersion (2, 15);
304                         if (type_args == null)
305                                 type_args = vm.GetTypes (GetInfo ().type_args);
306                         return type_args;
307                 }
308
309                 public IList<int> ILOffsets {
310                         get {
311                                 if (debug_info == null)
312                                         debug_info = vm.conn.Method_GetDebugInfo (id);
313                                 return Array.AsReadOnly (debug_info.il_offsets);
314                         }
315                 }
316
317                 public IList<int> LineNumbers {
318                         get {
319                                 if (debug_info == null)
320                                         debug_info = vm.conn.Method_GetDebugInfo (id);
321                                 return Array.AsReadOnly (debug_info.line_numbers);
322                         }
323                 }
324
325                 public string SourceFile {
326                         get {
327                                 if (debug_info == null)
328                                         debug_info = vm.conn.Method_GetDebugInfo (id);
329                                 return debug_info.source_files.Length > 0 ? debug_info.source_files [0].source_file : null;
330                         }
331                 }
332
333                 public IList<Location> Locations {
334                         get {
335                                 if (locations == null) {
336                                         var il_offsets = ILOffsets;
337                                         var line_numbers = LineNumbers;
338                                         IList<Location> res = new Location [ILOffsets.Count];
339                                         for (int i = 0; i < il_offsets.Count; ++i)
340                                                 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);
341                                         locations = res;
342                                 }
343                                 return locations;
344                         }
345                 }                               
346
347                 internal int il_offset_to_line_number (int il_offset, out string src_file, out byte[] src_hash, out int column_number) {
348                         if (debug_info == null)
349                                 debug_info = vm.conn.Method_GetDebugInfo (id);
350
351                         // FIXME: Optimize this
352                         src_file = null;
353                         src_hash = null;
354                         column_number = 0;
355                         for (int i = debug_info.il_offsets.Length - 1; i >= 0; --i) {
356                                 if (debug_info.il_offsets [i] <= il_offset) {
357                                         src_file = debug_info.source_files [i].source_file;
358                                         src_hash = debug_info.source_files [i].hash;
359                                         column_number = debug_info.column_numbers [i];
360                                         return debug_info.line_numbers [i];
361                                 }
362                         }
363                         return -1;
364                 }
365
366                 public Location LocationAtILOffset (int il_offset) {
367                         IList<Location> locs = Locations;
368
369                         // FIXME: Optimize this
370                         for (int i = locs.Count - 1; i >= 0; --i) {
371                                 if (locs [i].ILOffset <= il_offset)
372                                         return locs [i];
373                         }
374
375                         return null;
376                 }
377
378                 public C.MethodDefinition Metadata {
379                         get {
380                                 if (meta == null)
381                                         meta = (C.MethodDefinition)DeclaringType.Assembly.Metadata.MainModule.LookupToken (MetadataToken);
382                                 return meta;
383                         }
384                 }
385         }
386 }