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