Implement TypeMirror/MethodMirror GetGenericArguments () method. Fixes #3482.
[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                 ParameterInfoMirror[] param_info;
18                 ParameterInfoMirror ret_param;
19                 LocalVariable[] locals;
20                 IList<Location> locations;
21                 MethodBodyMirror body;
22                 MethodMirror gmd;
23                 TypeMirror[] type_args;
24
25                 internal MethodMirror (VirtualMachine vm, long id) : base (vm, id) {
26                 }
27
28                 public string Name {
29                         get {
30                                 if (name == null)
31                                         name = vm.conn.Method_GetName (id);
32                                 return name;
33                         }
34                 }
35
36                 public TypeMirror DeclaringType {
37                         get {
38                                 if (declaring_type == null)
39                                         declaring_type = vm.GetType (vm.conn.Method_GetDeclaringType (id));
40                                 return declaring_type;
41                         }
42                 }
43
44                 public TypeMirror ReturnType {
45                         get {
46                                 return ReturnParameter.ParameterType;
47                         }
48                 }
49
50                 // FIXME:
51                 public string FullName {
52                         get {
53                                 string type_namespace = DeclaringType.Namespace;
54                                 string type_name = DeclaringType.Name;
55                                 StringBuilder sb = new StringBuilder ();
56                                 sb.Append (ReturnType.Name);
57                                 sb.Append (' ');
58                                 if (type_namespace != String.Empty)
59                                         sb.Append (type_namespace + ".");
60                                 sb.Append(type_name);
61                                 sb.Append(":");
62                                 sb.Append(Name);
63                                 sb.Append(" ");
64                                 sb.Append("(");
65                                 for (var i = 0; i < param_info.Length; i++) {
66                                         sb.Append(param_info[i].ParameterType.Name);
67                                         if (i != param_info.Length - 1)
68                                                 sb.Append(", ");
69                                 }
70                                 sb.Append(")");
71                                 return sb.ToString ();
72                         }
73                 }
74
75                 MethodInfo GetInfo () {
76                         if (info == null)
77                                 info = vm.conn.Method_GetInfo (id);
78                         
79                         return info;
80                 }
81
82                 public int MetadataToken {
83                         get {
84                                 return GetInfo ().token;
85                         }
86                 }
87
88                 public MethodAttributes Attributes {
89                         get {
90                                 return (MethodAttributes) GetInfo ().attributes;
91                         }
92                 }
93
94                 public bool IsPublic { 
95                         get {
96                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;
97                         }
98                 }
99                 public bool IsPrivate {
100                         get {
101                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
102                         }
103                 }
104                 public bool IsFamily {
105                         get {
106                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family;
107                         }
108                 }
109                 public bool IsAssembly {
110                         get {
111                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly;
112                         }
113                 }
114                 public bool IsFamilyAndAssembly {
115                         get {
116                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem;
117                         }
118                 }
119                 public bool IsFamilyOrAssembly {
120                         get {
121                                 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem;
122                         }
123                 }
124                 public bool IsStatic {
125                         get {
126                                 return (Attributes & MethodAttributes.Static) != 0;
127                         }
128                 }
129                 public bool IsFinal {
130                         get {
131                                 return (Attributes & MethodAttributes.Final) != 0;
132                         }
133                 }
134                 public bool IsVirtual {
135                         get {
136                                 return (Attributes & MethodAttributes.Virtual) != 0;
137                         }
138                 }
139                 public bool IsHideBySig {
140                         get {
141                                 return (Attributes & MethodAttributes.HideBySig) != 0;
142                         }
143                 }
144                 public bool IsAbstract {
145                         get {
146                                 return (Attributes & MethodAttributes.Abstract) != 0;
147                         }
148                 }
149                 public bool IsSpecialName {
150                         get {
151                                 return (Attributes & MethodAttributes.SpecialName) != 0;
152                         }
153                 }
154
155                 public bool IsConstructor {
156                         get {
157                                 int attr = (int)Attributes;
158                                 return ((attr & (int)MethodAttributes.RTSpecialName) != 0
159                                         && (Name == ".ctor"));
160                         }
161                 }
162
163                 // Since protocol version 2.12
164                 public bool IsGenericMethodDefinition {
165                         get {
166                                 vm.CheckProtocolVersion (2, 12);
167                                 return GetInfo ().is_gmd;
168                         }
169                 }
170
171                 public bool IsGenericMethod {
172                         get {
173                                 if (vm.Version.AtLeast (2, 12)) {
174                                         return GetInfo ().is_generic_method;
175                                 } else {
176                                         return Name.IndexOf ('`') != -1;
177                                 }
178                         }
179                 }
180
181                 public ParameterInfoMirror[] GetParameters () {
182                         if (param_info == null) {
183                                 var pi = vm.conn.Method_GetParamInfo (id);
184                                 param_info = new ParameterInfoMirror [pi.param_count];
185                                 // Return
186                                 ret_param = new ParameterInfoMirror (this, -1, vm.GetType (pi.ret_type), null, ParameterAttributes.Retval);
187                                 // FIXME: this
188                                 // FIXME: Attributes
189                                 for (int i = 0; i < pi.param_count; ++i) {
190                                         param_info [i] = new ParameterInfoMirror (this, i, vm.GetType (pi.param_types [i]), pi.param_names [i], 0);
191                                 }
192                         }
193
194                         return param_info;
195                 }
196
197                 public ParameterInfoMirror ReturnParameter {
198                         get {
199                                 if (ret_param == null)
200                                         GetParameters ();
201                                 return ret_param;
202                         }
203                 }
204
205                 public LocalVariable[] GetLocals () {
206                         if (locals == null) {
207                                 var li = vm.conn.Method_GetLocalsInfo (id);
208                                 // Add the arguments as well
209                                 var pi = vm.conn.Method_GetParamInfo (id);
210
211                                 locals = new LocalVariable [pi.param_count + li.names.Length];
212
213                                 for (int i = 0; i < pi.param_count; ++i)
214                                         locals [i] = new LocalVariable (vm, this, i, pi.param_types [i], pi.param_names [i], -1, -1, true);
215
216                                 for (int i = 0; i < li.names.Length; ++i)
217                                         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);
218                         }
219                         return locals;
220                 }
221
222                 public LocalVariable GetLocal (string name) {
223                         if (name == null)
224                                 throw new ArgumentNullException ("name");
225
226                         GetLocals ();
227
228                         LocalVariable res = null;
229                         for (int i = 0; i < locals.Length; ++i) {
230                                 if (locals [i].Name == name) {
231                                         if (res != null)
232                                                 throw new AmbiguousMatchException ("More that one local has the name '" + name + "'.");
233                                         res = locals [i];
234                                 }
235                         }
236
237                         return res;
238                 }
239
240                 public MethodBodyMirror GetMethodBody () {
241                         if (body == null) {
242                                 MethodBodyInfo info = vm.conn.Method_GetBody (id);
243
244                                 body = new MethodBodyMirror (vm, this, info.il);
245                         }
246                         return body;
247                 }
248
249                 public MethodMirror GetGenericMethodDefinition () {
250                         vm.CheckProtocolVersion (2, 12);
251                         if (gmd == null) {
252                                 if (info.gmd == 0)
253                                         throw new InvalidOperationException ();
254                                 gmd = vm.GetMethod (info.gmd);
255                         }
256                         return gmd;
257                 }
258
259                 // Since protocol version 2.15
260                 public TypeMirror[] GetGenericArguments () {
261                         vm.CheckProtocolVersion (2, 15);
262                         if (type_args == null)
263                                 type_args = vm.GetTypes (GetInfo ().type_args);
264                         return type_args;
265                 }
266
267                 public IList<int> ILOffsets {
268                         get {
269                                 if (debug_info == null)
270                                         debug_info = vm.conn.Method_GetDebugInfo (id);
271                                 return Array.AsReadOnly (debug_info.il_offsets);
272                         }
273                 }
274
275                 public IList<int> LineNumbers {
276                         get {
277                                 if (debug_info == null)
278                                         debug_info = vm.conn.Method_GetDebugInfo (id);
279                                 return Array.AsReadOnly (debug_info.line_numbers);
280                         }
281                 }
282
283                 public string SourceFile {
284                         get {
285                                 if (debug_info == null)
286                                         debug_info = vm.conn.Method_GetDebugInfo (id);
287                                 return debug_info.source_files.Length > 0 ? debug_info.source_files [0].source_file : null;
288                         }
289                 }
290
291                 public IList<Location> Locations {
292                         get {
293                                 if (locations == null) {
294                                         var il_offsets = ILOffsets;
295                                         var line_numbers = LineNumbers;
296                                         IList<Location> res = new Location [ILOffsets.Count];
297                                         for (int i = 0; i < il_offsets.Count; ++i)
298                                                 res [i] = new Location (vm, this, -1, il_offsets [i], debug_info.source_files [i].source_file, line_numbers [i], 0, debug_info.source_files [i].hash);
299                                         locations = res;
300                                 }
301                                 return locations;
302                         }
303                 }                               
304
305                 internal int il_offset_to_line_number (int il_offset, out string src_file, out byte[] src_hash) {
306                         if (debug_info == null)
307                                 debug_info = vm.conn.Method_GetDebugInfo (id);
308
309                         // FIXME: Optimize this
310                         src_file = null;
311                         src_hash = null;
312                         for (int i = debug_info.il_offsets.Length - 1; i >= 0; --i) {
313                                 if (debug_info.il_offsets [i] <= il_offset) {
314                                         src_file = debug_info.source_files [i].source_file;
315                                         src_hash = debug_info.source_files [i].hash;
316                                         return debug_info.line_numbers [i];
317                                 }
318                         }
319                         return -1;
320                 }
321
322                 public Location LocationAtILOffset (int il_offset) {
323                         IList<Location> locs = Locations;
324
325                         // FIXME: Optimize this
326                         for (int i = locs.Count - 1; i >= 0; --i) {
327                                 if (locs [i].ILOffset <= il_offset)
328                                         return locs [i];
329                         }
330
331                         return null;
332                 }
333
334                 public C.MethodDefinition Metadata {
335                         get {
336                                 if (meta == null)
337                                         meta = (C.MethodDefinition)DeclaringType.Assembly.Metadata.MainModule.LookupToken (MetadataToken);
338                                 return meta;
339                         }
340                 }
341         }
342 }