BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[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                 // Since protocol version 2.12
172                 public bool IsGenericMethod {
173                         get {
174                                 vm.CheckProtocolVersion (2, 12);
175                                 return GetInfo ().is_generic_method;
176                         }
177                 }
178
179                 public MethodImplAttributes GetMethodImplementationFlags() {
180                         return (MethodImplAttributes)GetInfo ().iattributes;
181                 }
182
183                 public ParameterInfoMirror[] GetParameters () {
184                         if (param_info == null) {
185                                 var pi = vm.conn.Method_GetParamInfo (id);
186                                 param_info = new ParameterInfoMirror [pi.param_count];
187                                 // Return
188                                 ret_param = new ParameterInfoMirror (this, -1, vm.GetType (pi.ret_type), null, ParameterAttributes.Retval);
189                                 // FIXME: this
190                                 // FIXME: Attributes
191                                 for (int i = 0; i < pi.param_count; ++i) {
192                                         param_info [i] = new ParameterInfoMirror (this, i, vm.GetType (pi.param_types [i]), pi.param_names [i], 0);
193                                 }
194                         }
195
196                         return param_info;
197                 }
198
199                 public ParameterInfoMirror ReturnParameter {
200                         get {
201                                 if (ret_param == null)
202                                         GetParameters ();
203                                 return ret_param;
204                         }
205                 }
206
207                 public LocalVariable[] GetLocals () {
208                         if (locals == null) {
209
210                                 LocalsInfo li = new LocalsInfo ();
211                                 try {
212                                         li = vm.conn.Method_GetLocalsInfo (id);
213                                 } catch (CommandException) {
214                                         throw new ArgumentException ("Method doesn't have a body.");
215                                 }
216                                 // Add the arguments as well
217                                 var pi = vm.conn.Method_GetParamInfo (id);
218
219                                 locals = new LocalVariable [pi.param_count + li.names.Length];
220
221                                 for (int i = 0; i < pi.param_count; ++i)
222                                         locals [i] = new LocalVariable (vm, this, i, pi.param_types [i], pi.param_names [i], -1, -1, true);
223
224                                 for (int i = 0; i < li.names.Length; ++i)
225                                         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);
226                         }
227                         return locals;
228                 }
229
230                 public LocalVariable GetLocal (string name) {
231                         if (name == null)
232                                 throw new ArgumentNullException ("name");
233
234                         GetLocals ();
235
236                         LocalVariable res = null;
237                         for (int i = 0; i < locals.Length; ++i) {
238                                 if (locals [i].Name == name) {
239                                         if (res != null)
240                                                 throw new AmbiguousMatchException ("More that one local has the name '" + name + "'.");
241                                         res = locals [i];
242                                 }
243                         }
244
245                         return res;
246                 }
247
248                 public MethodBodyMirror GetMethodBody () {
249                         if (body == null) {
250                                 MethodBodyInfo info = vm.conn.Method_GetBody (id);
251
252                                 body = new MethodBodyMirror (vm, this, info.il);
253                         }
254                         return body;
255                 }
256
257                 public MethodMirror GetGenericMethodDefinition () {
258                         vm.CheckProtocolVersion (2, 12);
259                         if (gmd == null) {
260                                 if (info.gmd == 0)
261                                         throw new InvalidOperationException ();
262                                 gmd = vm.GetMethod (info.gmd);
263                         }
264                         return gmd;
265                 }
266
267                 // Since protocol version 2.15
268                 public TypeMirror[] GetGenericArguments () {
269                         vm.CheckProtocolVersion (2, 15);
270                         if (type_args == null)
271                                 type_args = vm.GetTypes (GetInfo ().type_args);
272                         return type_args;
273                 }
274
275                 public IList<int> ILOffsets {
276                         get {
277                                 if (debug_info == null)
278                                         debug_info = vm.conn.Method_GetDebugInfo (id);
279                                 return Array.AsReadOnly (debug_info.il_offsets);
280                         }
281                 }
282
283                 public IList<int> LineNumbers {
284                         get {
285                                 if (debug_info == null)
286                                         debug_info = vm.conn.Method_GetDebugInfo (id);
287                                 return Array.AsReadOnly (debug_info.line_numbers);
288                         }
289                 }
290
291                 public string SourceFile {
292                         get {
293                                 if (debug_info == null)
294                                         debug_info = vm.conn.Method_GetDebugInfo (id);
295                                 return debug_info.source_files.Length > 0 ? debug_info.source_files [0].source_file : null;
296                         }
297                 }
298
299                 public IList<Location> Locations {
300                         get {
301                                 if (locations == null) {
302                                         var il_offsets = ILOffsets;
303                                         var line_numbers = LineNumbers;
304                                         IList<Location> res = new Location [ILOffsets.Count];
305                                         for (int i = 0; i < il_offsets.Count; ++i)
306                                                 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);
307                                         locations = res;
308                                 }
309                                 return locations;
310                         }
311                 }                               
312
313                 internal int il_offset_to_line_number (int il_offset, out string src_file, out byte[] src_hash) {
314                         if (debug_info == null)
315                                 debug_info = vm.conn.Method_GetDebugInfo (id);
316
317                         // FIXME: Optimize this
318                         src_file = null;
319                         src_hash = null;
320                         for (int i = debug_info.il_offsets.Length - 1; i >= 0; --i) {
321                                 if (debug_info.il_offsets [i] <= il_offset) {
322                                         src_file = debug_info.source_files [i].source_file;
323                                         src_hash = debug_info.source_files [i].hash;
324                                         return debug_info.line_numbers [i];
325                                 }
326                         }
327                         return -1;
328                 }
329
330                 public Location LocationAtILOffset (int il_offset) {
331                         IList<Location> locs = Locations;
332
333                         // FIXME: Optimize this
334                         for (int i = locs.Count - 1; i >= 0; --i) {
335                                 if (locs [i].ILOffset <= il_offset)
336                                         return locs [i];
337                         }
338
339                         return null;
340                 }
341
342                 public C.MethodDefinition Metadata {
343                         get {
344                                 if (meta == null)
345                                         meta = (C.MethodDefinition)DeclaringType.Assembly.Metadata.MainModule.LookupToken (MetadataToken);
346                                 return meta;
347                         }
348                 }
349         }
350 }