2 using System.Collections.Generic;
5 using System.Reflection;
7 using Mono.Cecil.Metadata;
9 namespace Mono.Debugger.Soft
11 public class MethodMirror : Mirror
15 TypeMirror declaring_type;
17 C.MethodDefinition meta;
18 CustomAttributeDataMirror[] cattrs;
19 ParameterInfoMirror[] param_info;
20 ParameterInfoMirror ret_param;
21 LocalVariable[] locals;
23 IList<Location> locations;
24 MethodBodyMirror body;
26 TypeMirror[] type_args;
28 internal MethodMirror (VirtualMachine vm, long id) : base (vm, id) {
34 name = vm.conn.Method_GetName (id);
39 public TypeMirror DeclaringType {
41 if (declaring_type == null)
42 declaring_type = vm.GetType (vm.conn.Method_GetDeclaringType (id));
43 return declaring_type;
47 public TypeMirror ReturnType {
49 return ReturnParameter.ParameterType;
54 public string FullName {
56 string type_namespace = DeclaringType.Namespace;
57 string type_name = DeclaringType.Name;
58 StringBuilder sb = new StringBuilder ();
59 sb.Append (ReturnType.Name);
61 if (type_namespace != String.Empty)
62 sb.Append (type_namespace).Append (".");
68 for (var i = 0; i < param_info.Length; i++) {
69 sb.Append(param_info[i].ParameterType.Name);
70 if (i != param_info.Length - 1)
74 return sb.ToString ();
79 * Creating the custom attributes themselves could modify the behavior of the
80 * debuggee, so we return objects similar to the CustomAttributeData objects
81 * used by the reflection-only functionality on .net.
82 * Since protocol version 2.21
84 public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
85 return GetCAttrs (null, inherit);
88 /* Since protocol version 2.21 */
89 public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
90 if (attributeType == null)
91 throw new ArgumentNullException ("attributeType");
92 return GetCAttrs (attributeType, inherit);
95 CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
96 if (cattrs == null && meta != null && !Metadata.HasCustomAttributes)
97 cattrs = new CustomAttributeDataMirror [0];
99 // FIXME: Handle inherit
100 if (cattrs == null) {
101 CattrInfo[] info = vm.conn.Method_GetCustomAttributes (id, 0, false);
102 cattrs = CustomAttributeDataMirror.Create (vm, info);
104 var res = new List<CustomAttributeDataMirror> ();
105 foreach (var attr in cattrs)
106 if (type == null || attr.Constructor.DeclaringType == type)
108 return res.ToArray ();
111 MethodInfo GetInfo () {
113 info = vm.conn.Method_GetInfo (id);
118 public int MetadataToken {
120 return GetInfo ().token;
124 public MethodAttributes Attributes {
126 return (MethodAttributes) GetInfo ().attributes;
130 public bool IsPublic {
132 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;
135 public bool IsPrivate {
137 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
140 public bool IsFamily {
142 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family;
145 public bool IsAssembly {
147 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly;
150 public bool IsFamilyAndAssembly {
152 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem;
155 public bool IsFamilyOrAssembly {
157 return (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem;
160 public bool IsStatic {
162 return (Attributes & MethodAttributes.Static) != 0;
165 public bool IsFinal {
167 return (Attributes & MethodAttributes.Final) != 0;
170 public bool IsVirtual {
172 return (Attributes & MethodAttributes.Virtual) != 0;
175 public bool IsHideBySig {
177 return (Attributes & MethodAttributes.HideBySig) != 0;
180 public bool IsAbstract {
182 return (Attributes & MethodAttributes.Abstract) != 0;
185 public bool IsSpecialName {
187 return (Attributes & MethodAttributes.SpecialName) != 0;
191 public bool IsConstructor {
193 int attr = (int)Attributes;
194 return ((attr & (int)MethodAttributes.RTSpecialName) != 0
195 && (Name == ".ctor"));
199 // Since protocol version 2.12
200 public bool IsGenericMethodDefinition {
202 vm.CheckProtocolVersion (2, 12);
203 return GetInfo ().is_gmd;
207 // Since protocol version 2.12
208 public bool IsGenericMethod {
210 vm.CheckProtocolVersion (2, 12);
211 return GetInfo ().is_generic_method;
215 public MethodImplAttributes GetMethodImplementationFlags() {
216 return (MethodImplAttributes)GetInfo ().iattributes;
219 public ParameterInfoMirror[] GetParameters () {
220 if (param_info == null) {
221 var pi = vm.conn.Method_GetParamInfo (id);
222 param_info = new ParameterInfoMirror [pi.param_count];
224 ret_param = new ParameterInfoMirror (this, -1, vm.GetType (pi.ret_type), null, ParameterAttributes.Retval);
227 for (int i = 0; i < pi.param_count; ++i) {
228 param_info [i] = new ParameterInfoMirror (this, i, vm.GetType (pi.param_types [i]), pi.param_names [i], 0);
235 public ParameterInfoMirror ReturnParameter {
237 if (ret_param == null)
243 public LocalScope [] GetScopes () {
244 vm.CheckProtocolVersion (2, 43);
249 public LocalVariable[] GetLocals () {
250 if (locals == null) {
251 LocalsInfo li = new LocalsInfo ();
253 li = vm.conn.Method_GetLocalsInfo (id);
254 } catch (CommandException) {
255 throw new AbsentInformationException ();
258 // Add the arguments as well
259 var pi = GetParameters ();
261 locals = new LocalVariable [pi.Length + li.names.Length];
263 for (int i = 0; i < pi.Length; ++i)
264 locals [i] = new LocalVariable (vm, this, i, pi[i].ParameterType.Id, pi[i].Name, -1, -1, true);
266 for (int i = 0; i < li.names.Length; ++i)
267 locals [i + pi.Length] = new LocalVariable (vm, this, i, li.types [i], li.names [i], li.live_range_start [i], li.live_range_end [i], false);
269 if (vm.Version.AtLeast (2, 43)) {
270 scopes = new LocalScope [li.scopes_start.Length];
271 for (int i = 0; i < scopes.Length; ++i)
272 scopes [i] = new LocalScope (vm, this, li.scopes_start [i], li.scopes_end [i]);
278 public LocalVariable GetLocal (string name) {
280 throw new ArgumentNullException ("name");
284 LocalVariable res = null;
285 for (int i = 0; i < locals.Length; ++i) {
286 if (locals [i].Name == name) {
288 throw new AmbiguousMatchException ("More that one local has the name '" + name + "'.");
296 public MethodBodyMirror GetMethodBody () {
298 MethodBodyInfo info = vm.conn.Method_GetBody (id);
300 body = new MethodBodyMirror (vm, this, info);
305 public MethodMirror GetGenericMethodDefinition () {
306 vm.CheckProtocolVersion (2, 12);
309 throw new InvalidOperationException ();
310 gmd = vm.GetMethod (info.gmd);
315 // Since protocol version 2.15
316 public TypeMirror[] GetGenericArguments () {
317 vm.CheckProtocolVersion (2, 15);
318 if (type_args == null)
319 type_args = vm.GetTypes (GetInfo ().type_args);
323 // Since protocol version 2.24
324 public MethodMirror MakeGenericMethod (TypeMirror[] args) {
326 throw new ArgumentNullException ("args");
327 foreach (var a in args)
329 throw new ArgumentNullException ("args");
331 if (!IsGenericMethodDefinition)
332 throw new InvalidOperationException ("not a generic method definition");
334 if (GetGenericArguments ().Length != args.Length)
335 throw new ArgumentException ("Incorrect length");
337 vm.CheckProtocolVersion (2, 24);
340 id = vm.conn.Method_MakeGenericMethod (Id, args.Select (t => t.Id).ToArray ());
341 } catch (CommandException) {
342 throw new InvalidOperationException ();
344 return vm.GetMethod (id);
347 public IList<int> ILOffsets {
349 if (debug_info == null)
350 debug_info = vm.conn.Method_GetDebugInfo (id);
351 return Array.AsReadOnly (debug_info.il_offsets);
355 public IList<int> LineNumbers {
357 if (debug_info == null)
358 debug_info = vm.conn.Method_GetDebugInfo (id);
359 return Array.AsReadOnly (debug_info.line_numbers);
363 public string SourceFile {
365 if (debug_info == null)
366 debug_info = vm.conn.Method_GetDebugInfo (id);
367 return debug_info.source_files.Length > 0 ? debug_info.source_files [0].source_file : null;
371 public IList<Location> Locations {
373 if (locations == null) {
374 var il_offsets = ILOffsets;
375 var line_numbers = LineNumbers;
376 IList<Location> res = new Location [ILOffsets.Count];
377 for (int i = 0; i < il_offsets.Count; ++i)
378 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.end_line_numbers [i], debug_info.end_column_numbers [i], debug_info.source_files [i].hash);
385 internal int il_offset_to_line_number (int il_offset, out string src_file, out byte[] src_hash, out int column_number, out int end_line_number, out int end_column_number) {
386 if (debug_info == null)
387 debug_info = vm.conn.Method_GetDebugInfo (id);
389 // FIXME: Optimize this
393 end_line_number = -1;
394 end_column_number = -1;
395 for (int i = debug_info.il_offsets.Length - 1; i >= 0; --i) {
396 if (debug_info.il_offsets [i] <= il_offset) {
397 src_file = debug_info.source_files [i].source_file;
398 src_hash = debug_info.source_files [i].hash;
399 column_number = debug_info.column_numbers [i];
400 end_line_number = debug_info.end_line_numbers [i];
401 end_column_number = debug_info.end_column_numbers [i];
402 return debug_info.line_numbers [i];
408 public Location LocationAtILOffset (int il_offset) {
409 IList<Location> locs = Locations;
411 // FIXME: Optimize this
412 for (int i = locs.Count - 1; i >= 0; --i) {
413 if (locs [i].ILOffset <= il_offset)
420 public C.MethodDefinition Metadata {
423 meta = (C.MethodDefinition)DeclaringType.Assembly.Metadata.MainModule.LookupToken (MetadataToken);
429 // Evaluate the method on the client using an IL interpreter.
430 // Only supports a subset of IL instructions. Doesn't change
432 // Returns the result of the evaluation, or null for methods
433 // which return void.
434 // Throws a NotSupportedException if the method body contains
435 // unsupported IL instructions, or if evaluating the method
436 // would change debuggee state.
438 public Value Evaluate (Value this_val, Value[] args) {
439 var interp = new ILInterpreter (this);
441 return interp.Evaluate (this_val, args);