* Makefile.am:
[monodevelop.git] / extras / MonoDevelop.Debugger.Mdb / Mono.Debugging.Server.Mdb / ObjectUtil.cs
bloba5369241b6c8820288266b8cffed787803cfcb7f
1 // ObjectUtil.cs
2 //
3 // Author:
4 // Lluis Sanchez Gual <lluis@novell.com>
5 //
6 // Copyright (c) 2008 Novell, Inc (http://www.novell.com)
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 // THE SOFTWARE.
28 // #define REFLECTION_INVOKE
30 using System;
31 using System.Diagnostics;
32 using System.Collections.Generic;
33 using System.Reflection;
34 using System.Text;
35 using MD = Mono.Debugger;
36 using SR = System.Reflection;
37 using Mono.Debugger.Languages;
38 using Mono.Debugging.Client;
39 using Mono.Debugging.Backend;
41 namespace DebuggerServer
43 public static class ObjectUtil
45 static Dictionary<string,TypeDisplayData> typeDisplayData = new Dictionary<string,TypeDisplayData> ();
46 static Dictionary<TargetType,TargetType> proxyTypes = new Dictionary<TargetType,TargetType> ();
48 public static TargetObject GetRealObject (EvaluationContext ctx, TargetObject obj)
50 if (obj == null)
51 return null;
53 try {
54 switch (obj.Kind) {
55 case MD.Languages.TargetObjectKind.Array:
56 case TargetObjectKind.Fundamental:
57 return obj;
59 case TargetObjectKind.Struct:
60 case TargetObjectKind.GenericInstance:
61 case TargetObjectKind.Class:
62 TargetStructObject co = obj as TargetStructObject;
63 if (co == null)
64 return null;
65 TargetObject res = co.GetCurrentObject (ctx.Thread);
66 return res ?? obj;
68 case TargetObjectKind.Enum:
69 TargetEnumObject eob = (TargetEnumObject) obj;
70 return eob.GetValue (ctx.Thread);
72 case TargetObjectKind.Object:
73 TargetObjectObject oob = obj as TargetObjectObject;
74 if (oob == null)
75 return null;
76 if (oob.Type.CanDereference)
77 return oob.GetDereferencedObject (ctx.Thread);
78 else
79 return oob;
82 catch {
83 // Ignore
85 return obj;
88 public static TargetObject GetProxyObject (EvaluationContext ctx, TargetObject obj)
90 TypeDisplayData data = GetTypeDisplayData (ctx, obj.Type);
91 if (data.ProxyType == null)
92 return obj;
94 TargetType ttype = ctx.Frame.Language.LookupType (data.ProxyType);
95 if (ttype == null) {
96 int i = data.ProxyType.IndexOf (',');
97 if (i != -1)
98 ttype = ctx.Frame.Language.LookupType (data.ProxyType.Substring (0, i).Trim ());
100 if (ttype == null)
101 throw new EvaluatorException ("Unknown type '{0}'", data.ProxyType);
103 TargetObject proxy = CreateObject (ctx, ttype, obj);
104 return GetRealObject (ctx, proxy);
107 public static TypeDisplayData GetTypeDisplayData (EvaluationContext ctx, TargetType type)
109 if (type.Name == null)
110 return TypeDisplayData.Default;
112 TypeDisplayData td = null;
113 try {
114 td = GetTypeDisplayDataInternal (ctx, type);
116 catch (Exception ex) {
117 Console.WriteLine (ex);
119 if (td == null)
120 typeDisplayData [type.Name] = td = TypeDisplayData.Default;
121 return td;
124 static TypeDisplayData GetTypeDisplayDataInternal (EvaluationContext ctx, TargetType type)
126 TypeDisplayData data;
127 if (typeDisplayData.TryGetValue (type.Name, out data))
128 return data;
130 data = new TypeDisplayData ();
132 // Attribute inspection disabled until MDB provided a proper api for it
133 /* TargetObject tt = GetTypeOf (ctx, type);
134 if (tt == null) {
135 typeDisplayData [type.Name] = data;
136 throw new Exception ("Could not get type of " + type.Name);
138 TargetObject inherit = ctx.Frame.Language.CreateInstance (ctx.Thread, true);
140 data.IsProxyType = proxyTypes.ContainsKey (type);
142 // Look for DebuggerTypeProxyAttribute
143 TargetStructObject attType = GetTypeOf (ctx, "System.Diagnostics.DebuggerTypeProxyAttribute");
144 if (attType == null)
145 return null;
147 TargetObject at = CallStaticMethod (ctx, "GetCustomAttribute", "System.Attribute", tt, attType, inherit);
148 // HACK: The first call doesn't work the first time for generic types. So we do it again.
149 at = CallStaticMethod (ctx, "GetCustomAttribute", "System.Attribute", tt, attType, inherit);
150 at = GetRealObject (ctx, at);
152 if (at != null && !(at.HasAddress && at.GetAddress (ctx.Thread).IsNull)) {
153 TargetFundamentalObject pname = GetPropertyValue (ctx, "ProxyTypeName", at) as TargetFundamentalObject;
154 string ptname = (string) pname.GetObject (ctx.Thread);
155 TargetType ptype = LookupType (ctx, ptname);
156 if (ptype != null) {
157 data.ProxyType = ptname;
158 proxyTypes [ptype] = ptype;
162 // Look for DebuggerDisplayAttribute
163 attType = GetTypeOf (ctx, "System.Diagnostics.DebuggerDisplayAttribute");
164 at = CallStaticMethod (ctx, "GetCustomAttribute", "System.Attribute", tt, attType, inherit);
165 at = GetRealObject (ctx, at);
167 if (at != null && !(at.HasAddress && at.GetAddress (ctx.Thread).IsNull)) {
168 TargetFundamentalObject pname = GetPropertyValue (ctx, "Value", at) as TargetFundamentalObject;
169 data.ValueDisplayString = (string) pname.GetObject (ctx.Thread);
170 pname = GetPropertyValue (ctx, "Type", at) as TargetFundamentalObject;
171 data.TypeDisplayString = (string) pname.GetObject (ctx.Thread);
172 pname = GetPropertyValue (ctx, "Name", at) as TargetFundamentalObject;
173 data.NameDisplayString = (string) pname.GetObject (ctx.Thread);
176 // Now check fields and properties
178 Dictionary<string,DebuggerBrowsableState> members = new Dictionary<string,DebuggerBrowsableState> ();
179 attType = GetTypeOf (ctx, "System.Diagnostics.DebuggerBrowsableAttribute");
180 TargetObject flags = ctx.Frame.Language.CreateInstance (ctx.Thread, (int) (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance));
181 TargetObject fields = CallMethod (ctx, "GetFields", tt, flags);
182 TargetObject properties = CallMethod (ctx, "GetProperties", tt, flags);
183 foreach (TargetArrayObject array in new TargetObject [] { fields, properties }) {
184 int len = array.GetArrayBounds (ctx.Thread).Length;
185 int[] idx = new int [1];
186 for (int n=0; n<len; n++) {
187 idx [0] = n;
188 TargetObject member = array.GetElement (ctx.Thread, idx);
189 at = CallStaticMethod (ctx, "GetCustomAttribute", "System.Attribute", member, attType, inherit);
190 if (at != null && !(at.HasAddress && at.GetAddress (ctx.Thread).IsNull)) {
191 TargetFundamentalObject mname = (TargetFundamentalObject) GetPropertyValue (ctx, "Name", member);
192 TargetEnumObject ob = (TargetEnumObject) GetPropertyValue (ctx, "State", at);
193 TargetFundamentalObject fob = (TargetFundamentalObject) ob.GetValue (ctx.Thread);
194 int val = (int) fob.GetObject (ctx.Thread);
195 members [mname.GetObject (ctx.Thread).ToString ()] = (DebuggerBrowsableState) val;
199 if (members.Count > 0)
200 data.MemberData = members;
202 typeDisplayData [type.Name] = data;
203 return data;
206 public static TargetType LookupType (EvaluationContext ctx, string name)
208 TargetType ttype = ctx.Frame.Language.LookupType (name);
209 if (ttype == null) {
210 int i = name.IndexOf (',');
211 if (i != -1)
212 ttype = ctx.Frame.Language.LookupType (name.Substring (0, i).Trim ());
214 return ttype;
217 public static string EvaluateDisplayString (EvaluationContext ctx, TargetStructObject obj, string exp)
219 StringBuilder sb = new StringBuilder ();
220 int last = 0;
221 int i = exp.IndexOf ("{");
222 while (i != -1 && i < exp.Length) {
223 sb.Append (exp.Substring (last, i - last));
224 i++;
225 int j = exp.IndexOf ("}", i);
226 if (j == -1)
227 return exp;
228 string mem = exp.Substring (i, j-i).Trim ();
229 if (mem.Length == 0)
230 return exp;
232 MemberReference mi = ObjectUtil.FindMember (ctx, obj.Type, mem, false, true, true, true, ReqMemberAccess.All);
233 TargetObject val = mi.GetValue (ctx, obj);
234 sb.Append (Server.Instance.Evaluator.TargetObjectToString (ctx, val));
235 last = j + 1;
236 i = exp.IndexOf ("{", last);
238 sb.Append (exp.Substring (last));
239 return sb.ToString ();
242 public static string CallToString (EvaluationContext ctx, TargetStructObject obj)
244 try {
245 TargetObject retval = CallMethod (ctx, "ToString", obj);
246 object s = ((TargetFundamentalObject) retval).GetObject (ctx.Thread);
247 return s != null ? s.ToString () : "";
248 } catch {
249 // Ignore
252 return null;
256 public static MemberReference OverloadResolve (EvaluationContext ctx, string methodName, TargetStructType type, TargetType[] argtypes, bool allowInstance, bool allowStatic)
258 List<MemberReference> candidates = new List<MemberReference> ();
260 if (methodName == ".ctor") {
261 TargetClassType ct = type as TargetClassType;
262 if (ct == null && type.HasClassType)
263 ct = type.ClassType;
265 foreach (TargetMethodInfo met in ct.Constructors) {
266 if (met.Type.ParameterTypes.Length == argtypes.Length)
267 candidates.Add (new MemberReference (met, type));
270 else {
271 foreach (MemberReference mem in ObjectUtil.GetTypeMembers (ctx, type, false, false, false, true, ReqMemberAccess.All)) {
272 TargetMethodInfo met = (TargetMethodInfo) mem.Member;
273 if (met.Name == methodName && met.Type.ParameterTypes.Length == argtypes.Length && (met.IsStatic && allowStatic || !met.IsStatic && allowInstance))
274 candidates.Add (mem);
278 if (candidates.Count == 1) {
279 TargetFunctionType func = (TargetFunctionType) ((TargetMethodInfo) candidates [0].Member).Type;
280 string error;
281 int matchCount;
282 if (IsApplicable (ctx, func, argtypes, out error, out matchCount))
283 return candidates [0];
285 throw new EvaluatorException ("Invalid arguments for method `{0}': {1}", methodName, error);
288 if (candidates.Count == 0)
289 throw new EvaluatorException ("Method `{0}' not found in type `{1}'.", methodName, type.Name);
291 return OverloadResolve (ctx, methodName, argtypes, candidates);
294 static bool IsApplicable (EvaluationContext ctx, TargetFunctionType method, TargetType[] types, out string error, out int matchCount)
296 TargetMethodSignature sig = method.GetSignature (ctx.Thread);
297 matchCount = 0;
299 for (int i = 0; i < types.Length; i++) {
300 TargetType param_type = sig.ParameterTypes [i];
302 if (param_type == types [i]) {
303 matchCount++;
304 continue;
307 if (TargetObjectConvert.ImplicitConversionExists (ctx, types [i], param_type))
308 continue;
310 error = String.Format (
311 "Argument {0}: Cannot implicitly convert `{1}' to `{2}'",
312 i, types [i].Name, param_type.Name);
313 return false;
316 error = null;
317 return true;
320 static MemberReference OverloadResolve (EvaluationContext ctx, string methodName, TargetType[] argtypes, List<MemberReference> candidates)
322 // Ok, no we need to find an exact match.
323 MemberReference match = null;
324 int bestCount = -1;
325 bool repeatedBestCount = false;
327 foreach (MemberReference method in candidates) {
328 string error;
329 int matchCount;
330 TargetFunctionType func;
331 if (method.Member is TargetMethodInfo)
332 func = (TargetFunctionType) ((TargetMethodInfo) method.Member).Type;
333 else
334 func = (TargetFunctionType) ((TargetPropertyInfo) method.Member).Getter;
336 if (!IsApplicable (ctx, func, argtypes, out error, out matchCount))
337 continue;
339 if (matchCount == bestCount) {
340 repeatedBestCount = true;
341 } else if (matchCount > bestCount) {
342 match = method;
343 bestCount = matchCount;
344 repeatedBestCount = false;
348 if (match == null) {
349 if (methodName != null)
350 throw new EvaluatorException ("Invalid arguments for method `{0}'.", methodName);
351 else
352 throw new EvaluatorException ("Invalid arguments for indexer.");
355 if (repeatedBestCount) {
356 if (methodName != null)
357 throw new EvaluatorException ("Ambiguous method `{0}'; need to use full name", methodName);
358 else
359 throw new EvaluatorException ("Ambiguous arguments for indexer.", methodName);
362 return match;
365 static TargetPropertyInfo ResolveProperty (EvaluationContext ctx, TargetType type, string name, ref TargetObject[] indexerArgs)
367 if (indexerArgs.Length == 0) {
368 MemberReference mr = FindMember (ctx, type, name, false, false, true, false, ReqMemberAccess.All);
369 return mr != null ? mr.Member as TargetPropertyInfo : null;
372 // It is an indexer. Find the best overload.
374 TargetType[] types = new TargetType [indexerArgs.Length];
375 for (int n=0; n<indexerArgs.Length; n++)
376 types [n] = indexerArgs [n].Type;
378 List<MemberReference> candidates = new List<MemberReference> ();
379 foreach (MemberReference mem in GetTypeMembers (ctx, type, false, false, true, false, ReqMemberAccess.All)) {
380 TargetPropertyInfo prop = mem.Member as TargetPropertyInfo;
381 if (prop != null && prop.Getter.ParameterTypes.Length == indexerArgs.Length)
382 candidates.Add (mem);
384 MemberReference memr = OverloadResolve (ctx, null, types, candidates);
385 TargetPropertyInfo tprop = (TargetPropertyInfo) memr.Member;
386 TargetMethodSignature sig = tprop.Getter.GetSignature (ctx.Thread);
388 TargetObject[] objs = new TargetObject [indexerArgs.Length];
389 for (int i = 0; i < indexerArgs.Length; i++) {
390 objs [i] = TargetObjectConvert.ImplicitConversionRequired (ctx, indexerArgs[i], sig.ParameterTypes [i]);
393 indexerArgs = objs;
394 return tprop;
398 public static TargetObject CallMethod (EvaluationContext ctx, string name,
399 TargetObject target,
400 params TargetObject[] args)
402 #if REFLECTION_INVOKE
403 if (target is TargetGenericInstanceObject || !(target is TargetStructObject)) {
404 // Calling methods on generic objects is suprisingly not supported
405 // by the debugger. As a workaround we do the call using reflection.
407 if (name != "ToString" || args.Length != 0) {
408 GetTypeOf (ctx, "System.Convert");
409 TargetType cc = ctx.Frame.Language.LookupType ("System.Convert");
410 SR.BindingFlags sf = SR.BindingFlags.InvokeMethod | SR.BindingFlags.Static | SR.BindingFlags.FlattenHierarchy | SR.BindingFlags.Public | SR.BindingFlags.NonPublic;
411 CallMethodWithReflection (ctx, sf, "ToString", cc, null, target);
414 SR.BindingFlags f = SR.BindingFlags.InvokeMethod | SR.BindingFlags.Instance | SR.BindingFlags.Public | SR.BindingFlags.NonPublic;
415 return CallMethodWithReflection (ctx, f, name, target.Type, target, args);
417 #endif
418 TargetType[] types = new TargetType [args.Length];
419 for (int n=0; n<types.Length; n++)
420 types [n] = args [n].Type;
422 TargetStructObject starget = (TargetStructObject) target;
423 MemberReference mem = OverloadResolve (ctx, name, starget.Type, types, true, false);
424 TargetFunctionType function = (TargetFunctionType) ((TargetMethodInfo) mem.Member).Type;
426 while (target.Type != mem.DeclaringType) {
427 TargetStructObject par = starget.GetParentObject (ctx.Thread);
428 if (par != null)
429 target = par;
430 else
431 break;
434 TargetMethodSignature sig = function.GetSignature (ctx.Thread);
436 TargetObject[] objs = new TargetObject [args.Length];
437 for (int i = 0; i < args.Length; i++) {
438 objs [i] = TargetObjectConvert.ImplicitConversionRequired (
439 ctx, args [i], sig.ParameterTypes [i]);
442 return Server.Instance.RuntimeInvoke (ctx, function, starget, objs);
445 public static TargetObject CallStaticMethod (EvaluationContext ctx, string name,
446 string typeName,
447 params TargetObject[] args)
449 return CallStaticMethod (ctx, name, ctx.Frame.Language.LookupType (typeName), args);
452 public static TargetObject CallStaticMethod (EvaluationContext ctx, string name,
453 TargetType type,
454 params TargetObject[] args)
456 #if REFLECTION_INVOKE
457 if (type is TargetGenericInstanceType || !(type is TargetStructType)) {
458 // Calling methods on generic objects is suprisingly not supported
459 // by the debugger. As a workaround we do the call using reflection.
461 SR.BindingFlags f = SR.BindingFlags.InvokeMethod | SR.BindingFlags.Static | SR.BindingFlags.Public | SR.BindingFlags.NonPublic;
462 return CallMethodWithReflection (ctx, f, name, type, null, args);
464 #endif
465 TargetType[] types = new TargetType [args.Length];
466 for (int n=0; n<types.Length; n++)
467 types [n] = args [n].Type;
469 MemberReference mem = OverloadResolve (ctx, name, (TargetStructType) type, types, false, true);
470 TargetFunctionType function = (TargetFunctionType) ((TargetMethodInfo) mem.Member).Type;
472 TargetMethodSignature sig = function.GetSignature (ctx.Thread);
474 TargetObject[] objs = new TargetObject [args.Length];
475 for (int i = 0; i < args.Length; i++) {
476 objs [i] = TargetObjectConvert.ImplicitConversionRequired (ctx, args [i], sig.ParameterTypes [i]);
479 return Server.Instance.RuntimeInvoke (ctx, function, null, objs);
482 public static void SetPropertyValue (EvaluationContext ctx, string name, TargetObject target, TargetObject value, params TargetObject[] indexerArgs)
484 #if REFLECTION_INVOKE
485 if (target is TargetGenericInstanceObject || !(target is TargetStructObject)) {
486 // Accessing properties on generic objects is suprisingly not supported
487 // by the debugger. As a workaround we do the call using reflection.
488 TargetObject[] args = new TargetObject [indexerArgs.Length + 1];
489 Array.Copy (indexerArgs, args, indexerArgs.Length);
490 args [args.Length - 1] = value;
491 SR.BindingFlags f = SR.BindingFlags.SetProperty | SR.BindingFlags.Instance | SR.BindingFlags.Public | SR.BindingFlags.NonPublic;
492 CallMethodWithReflection (ctx, f, name, target.Type, target, args);
493 return;
495 #endif
496 TargetStructObject starget = (TargetStructObject) target;
497 TargetPropertyInfo prop = ResolveProperty (ctx, starget.Type, name, ref indexerArgs);
498 TargetObject[] sargs = new TargetObject [indexerArgs.Length + 1];
499 Array.Copy (indexerArgs, sargs, indexerArgs.Length);
500 sargs [sargs.Length - 1] = value;
501 Server.Instance.RuntimeInvoke (ctx, prop.Setter, starget, sargs);
504 public static TargetObject GetPropertyValue (EvaluationContext ctx, string name, TargetObject target, params TargetObject[] indexerArgs)
506 #if REFLECTION_INVOKE
507 if (target is TargetGenericInstanceObject || !(target is TargetStructObject)) {
508 // Accessing properties on generic objects is suprisingly not supported
509 // by the debugger. As a workaround we do the call using reflection.
510 SR.BindingFlags f = SR.BindingFlags.GetProperty | SR.BindingFlags.Instance | SR.BindingFlags.Public | SR.BindingFlags.NonPublic;
511 return CallMethodWithReflection (ctx, f, name, target.Type, target, indexerArgs);
513 #endif
514 TargetStructObject starget = (TargetStructObject) target;
515 TargetPropertyInfo prop = ResolveProperty (ctx, starget.Type, name, ref indexerArgs);
516 if (prop.IsStatic)
517 throw new EvaluatorException ("Property is static and can't be accessed using an object instance.");
518 return Server.Instance.RuntimeInvoke (ctx, prop.Getter, starget, indexerArgs);
521 public static void SetStaticPropertyValue (EvaluationContext ctx, string name, TargetType type, TargetObject value, params TargetObject[] indexerArgs)
523 #if REFLECTION_INVOKE
524 if (type is TargetGenericInstanceType || !(type is TargetStructType)) {
525 // Accessing properties on generic objects is suprisingly not supported
526 // by the debugger. As a workaround we do the call using reflection.
527 TargetObject[] args = new TargetObject [indexerArgs.Length + 1];
528 Array.Copy (indexerArgs, args, indexerArgs.Length);
529 args [args.Length - 1] = value;
530 SR.BindingFlags f = SR.BindingFlags.SetProperty | SR.BindingFlags.Static | SR.BindingFlags.FlattenHierarchy | SR.BindingFlags.Public | SR.BindingFlags.NonPublic;
531 CallMethodWithReflection (ctx, f, name, type, null, args);
532 return;
534 #endif
535 TargetPropertyInfo prop = ResolveProperty (ctx, type, name, ref indexerArgs);
536 TargetObject[] sargs = new TargetObject [indexerArgs.Length + 1];
537 Array.Copy (indexerArgs, sargs, indexerArgs.Length);
538 sargs [sargs.Length - 1] = value;
539 Server.Instance.RuntimeInvoke (ctx, prop.Setter, null, sargs);
542 public static TargetObject GetStaticPropertyValue (EvaluationContext ctx, string name, TargetType type, params TargetObject[] indexerArgs)
544 #if REFLECTION_INVOKE
545 if (type is TargetGenericInstanceType || !(type is TargetStructType)) {
546 // Accessing properties on generic objects is suprisingly not supported
547 // by the debugger. As a workaround we do the call using reflection.
548 SR.BindingFlags f = SR.BindingFlags.GetProperty | SR.BindingFlags.Static | SR.BindingFlags.FlattenHierarchy | SR.BindingFlags.Public | SR.BindingFlags.NonPublic;
549 return CallMethodWithReflection (ctx, f, name, type, null, indexerArgs);
551 #endif
552 TargetPropertyInfo prop = ResolveProperty (ctx, type, name, ref indexerArgs);
553 if (!prop.IsStatic)
554 throw new EvaluatorException ("Property is not static.");
555 return Server.Instance.RuntimeInvoke (ctx, prop.Getter, null, indexerArgs);
558 internal static TargetObject CallMethodWithReflection (EvaluationContext ctx, SR.BindingFlags flags, string name,
559 TargetType type, TargetObject target,
560 params TargetObject[] args)
562 MD.StackFrame frame = ctx.Frame;
563 string typeName = type.Name;
565 TargetStructObject tt = GetTypeOf (ctx, type);
566 if (tt == null)
567 throw new InvalidOperationException ("Type not found: " + typeName);
568 TargetObject objName = frame.Language.CreateInstance (ctx.Thread, name);
569 TargetObject objFlags = frame.Language.CreateInstance (ctx.Thread, (int)flags);
570 TargetObject objBinder = frame.Language.CreateNullObject (ctx.Thread, frame.Language.LookupType ("System.Reflection.Binder"));
571 TargetObject objTarget = target ?? frame.Language.CreateNullObject (ctx.Thread, frame.Language.ObjectType);
573 TargetType at = frame.Language.LookupType ("System.Array");
574 TargetObject len = frame.Language.CreateInstance (ctx.Thread, args.Length);
575 TargetObject ot = ObjectUtil.GetTypeOf (ctx, "System.Object");
576 TargetObject arrayob = ObjectUtil.CallStaticMethod (ctx, "CreateInstance", at, ot, len);
577 TargetArrayObject array = ObjectUtil.GetRealObject (ctx, arrayob) as TargetArrayObject;
579 if (target != null)
580 objTarget = TargetObjectConvert.Cast (ctx, objTarget, frame.Language.ObjectType);
582 int[] idx = new int [1];
583 for (int n=0; n<args.Length; n++) {
584 idx [0] = n;
585 TargetObject objObj = TargetObjectConvert.Cast (ctx, args[n], frame.Language.ObjectType);
586 array.SetElement (ctx.Thread, idx, objObj);
588 TargetObject res = CallMethod (ctx, "InvokeMember", tt, objName, objFlags, objBinder, objTarget, array);
589 return res;
592 public static TargetObject CreateObject (EvaluationContext ctx, TargetType type, params TargetObject[] args)
594 SR.BindingFlags flags = SR.BindingFlags.CreateInstance | SR.BindingFlags.Public | SR.BindingFlags.Instance | SR.BindingFlags.Static;
595 TargetObject res = CallMethodWithReflection (ctx, flags, "", type, null, args);
596 return GetRealObject (ctx, res);
599 public static MemberReference FindMethod (EvaluationContext ctx, TargetType type, string name, bool findStatic, ReqMemberAccess access, params string[] argTypes)
601 foreach (MemberReference mem in GetTypeMembers (ctx, type, findStatic, false, false, true, access)) {
602 if (mem.Member.Name == name && mem.Member.IsStatic == findStatic) {
603 TargetMethodInfo met = (TargetMethodInfo) mem.Member;
604 if (met.Type.ParameterTypes.Length == argTypes.Length) {
605 bool allMatch = true;
606 for (int n=0; n<argTypes.Length && allMatch; n++)
607 allMatch = argTypes [n] == FixTypeName (met.Type.ParameterTypes [n].Name);
608 if (allMatch)
609 return mem;
613 return null;
616 public static MemberReference FindMember (EvaluationContext ctx, TargetType type, string name, bool staticOnly, bool includeFields, bool includeProps, bool includeMethods, ReqMemberAccess access)
618 foreach (MemberReference mem in GetTypeMembers (ctx, type, staticOnly, includeFields, includeProps, includeMethods, access)) {
619 if (mem.Member.Name == name)
620 return mem;
622 return null;
625 public static IEnumerable<MemberReference> GetTypeMembers (EvaluationContext ctx, TargetType t, bool staticOnly, bool includeFields, bool includeProps, bool includeMethods, ReqMemberAccess access)
627 // Don't use yield in this method because the whole list of members
628 // must be retrieved before we can do anything with them.
629 List<MemberReference> members = new List<MemberReference> ();
631 TargetStructType type = t as TargetStructType;
632 Dictionary<string,string> foundMethods = new Dictionary<string,string> ();
634 while (type != null) {
636 TargetFieldInfo[] fields = null;
637 TargetPropertyInfo[] properties = null;
638 TargetMethodInfo[] methods = null;
640 TargetClass cls = type.GetClass (ctx.Thread);
641 if (cls != null) {
642 if (includeFields)
643 fields = cls.GetFields (ctx.Thread);
644 if (includeProps)
645 properties = cls.GetProperties (ctx.Thread);
646 if (includeMethods)
647 methods = cls.GetMethods (ctx.Thread);
649 else {
650 TargetClassType ct = type as TargetClassType;
651 if (ct == null && type.HasClassType)
652 ct = type.ClassType;
653 if (ct != null) {
654 if (includeFields)
655 fields = ct.Fields;
656 if (includeProps)
657 properties = ct.Properties;
658 if (includeMethods)
659 methods = ct.Methods;
663 if (fields != null) {
664 foreach (TargetFieldInfo field in fields) {
665 if (access == ReqMemberAccess.Public && field.Accessibility != TargetMemberAccessibility.Public)
666 continue;
667 if (field.IsStatic || !staticOnly)
668 members.Add (new MemberReference (field, type));
672 if (properties != null) {
673 foreach (TargetPropertyInfo prop in properties) {
674 if (access == ReqMemberAccess.Public && prop.Accessibility != TargetMemberAccessibility.Public)
675 continue;
676 if (access == ReqMemberAccess.Auto && prop.Accessibility != TargetMemberAccessibility.Public && prop.Accessibility != TargetMemberAccessibility.Protected)
677 continue;
678 if (prop.IsStatic || !staticOnly)
679 members.Add (new MemberReference (prop, type));
683 if (methods != null) {
684 foreach (TargetMethodInfo met in methods) {
685 if (access == ReqMemberAccess.Public && met.Accessibility != TargetMemberAccessibility.Public)
686 continue;
687 if (access == ReqMemberAccess.Auto && met.Accessibility != TargetMemberAccessibility.Public && met.Accessibility != TargetMemberAccessibility.Protected)
688 continue;
689 if (met.IsStatic || !staticOnly) {
690 string sig = GetSignature (met);
691 if (!foundMethods.ContainsKey (sig)) {
692 foundMethods [sig] = sig;
693 members.Add (new MemberReference (met, type));
699 if (type.HasParent)
700 type = type.GetParentType (ctx.Thread);
701 else
702 break;
704 return members;
707 static string GetSignature (TargetMethodInfo met)
709 StringBuilder sb = new StringBuilder (met.Name);
710 foreach (TargetType t in met.Type.ParameterTypes)
711 sb.Append (' ').Append (t.Name);
712 return sb.ToString ();
715 public static ObjectValueFlags GetAccessibility (TargetMemberAccessibility ma)
717 switch (ma) {
718 case TargetMemberAccessibility.Internal: return ObjectValueFlags.Internal;
719 case TargetMemberAccessibility.Protected: return ObjectValueFlags.Protected;
720 case TargetMemberAccessibility.Public: return ObjectValueFlags.Public;
721 default: return ObjectValueFlags.Private;
725 public static TargetStructObject GetTypeOf (EvaluationContext ctx, TargetType ttype)
727 if (ttype.HasClassType && ttype.ClassType.Module != null)
728 return GetTypeOf (ctx, FixTypeName (ttype.Name) + ", " + ttype.ClassType.Module.FullName);
729 else
730 return GetTypeOf (ctx, FixTypeName (ttype.Name));
733 public static TargetStructObject GetTypeOf (EvaluationContext ctx, string typeName)
735 TargetType tt = ctx.Frame.Language.LookupType ("System.Type");
736 if (tt == null)
737 return null;
739 TargetObject tn = ctx.Frame.Language.CreateInstance (ctx.Thread, FixTypeName (typeName));
740 TargetObject res = CallStaticMethod (ctx, "GetType", tt, tn);
741 return (TargetStructObject) GetRealObject (ctx, res);
744 public static bool IsInstanceOfType (EvaluationContext ctx, string typeName, TargetObject obj)
746 TargetStructObject tt = GetTypeOf (ctx, typeName);
747 if (tt == null)
748 return false;
749 TargetObject to = TargetObjectConvert.Cast (ctx, obj, ctx.Frame.Language.ObjectType);
750 TargetFundamentalObject res = CallMethod (ctx, "IsInstanceOfType", tt, to) as TargetFundamentalObject;
751 return (bool) res.GetObject (ctx.Thread);
754 public static string FixTypeName (string typeName)
756 // Required since the debugger uses C# type aliases for fundamental types,
757 // which is silly, but looks like it won't be fixed any time soon.
759 typeName = typeName.Replace ('/','+');
761 switch (typeName) {
762 case "short": return "System.Int16";
763 case "ushort": return "System.UInt16";
764 case "int": return "System.Int32";
765 case "uint": return "System.UInt32";
766 case "long": return "System.Int64";
767 case "ulong": return "System.UInt64";
768 case "float": return "System.Single";
769 case "double": return "System.Double";
770 case "char": return "System.Char";
771 case "byte": return "System.Byte";
772 case "sbyte": return "System.SByte";
773 case "object": return "System.Object";
774 case "string": return "System.String";
775 case "bool": return "System.Boolean";
776 case "void": return "System.Void";
777 case "decimal": return "System.Decimal";
780 int i = typeName.IndexOf ('<');
781 if (i != -1) {
782 StringBuilder sb = new StringBuilder (typeName.Substring (0, i));
783 sb.Append ('[');
784 i++;
785 int e;
786 do {
787 e = FindTypeEnd (typeName, i);
788 sb.Append (FixTypeName (typeName.Substring (i, e-i)));
789 sb.Append (',');
790 i = e + 1;
791 } while (typeName [e] == ',');
793 sb.Remove (sb.Length - 1, 1);
794 sb.Append (']');
795 return sb.ToString ();
798 return typeName;
801 static int FindTypeEnd (string str, int index)
803 int level = 0;
804 while (index < str.Length) {
805 char c = str [index];
806 if (c == '[' || c == '<')
807 level++;
808 if (c == ']' || c == '>') {
809 if (level == 0)
810 return index;
811 else
812 level--;
814 if (c == ',' && level == 0)
815 return index;
816 index++;
818 return index;
822 public class MemberReference
824 public readonly TargetMemberInfo Member;
825 public readonly TargetStructType DeclaringType;
827 public MemberReference (TargetMemberInfo member, TargetStructType type)
829 Member = member;
830 DeclaringType = type;
833 public TargetObject GetValue (EvaluationContext ctx, TargetStructObject thisObj)
835 if (Member is TargetPropertyInfo) {
836 TargetPropertyInfo prop = (TargetPropertyInfo) Member;
837 return ObjectUtil.GetRealObject (ctx, Server.Instance.RuntimeInvoke (ctx, prop.Getter, thisObj));
839 else if (Member is TargetFieldInfo) {
840 TargetFieldInfo field = (TargetFieldInfo) Member;
841 if (field.HasConstValue)
842 return ctx.Frame.Language.CreateInstance (ctx.Thread, field.ConstValue);
843 TargetClass cls = DeclaringType.GetClass (ctx.Thread);
844 return ObjectUtil.GetRealObject (ctx, cls.GetField (ctx.Thread, thisObj, field));
846 else {
847 TargetMethodInfo met = (TargetMethodInfo) Member;
848 return ObjectUtil.GetRealObject (ctx, Server.Instance.RuntimeInvoke (ctx, met.Type, thisObj));
853 public class TypeDisplayData
855 public string ProxyType;
856 public string ValueDisplayString;
857 public string TypeDisplayString;
858 public string NameDisplayString;
859 public bool IsProxyType;
861 public static readonly TypeDisplayData Default = new TypeDisplayData ();
863 public Dictionary<string,DebuggerBrowsableState> MemberData;
865 public DebuggerBrowsableState GetMemberBrowsableState (string name)
867 if (MemberData == null)
868 return DebuggerBrowsableState.Collapsed;
870 DebuggerBrowsableState state;
871 if (MemberData.TryGetValue (name, out state))
872 return state;
873 else
874 return DebuggerBrowsableState.Collapsed;