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