4 // Lluis Sanchez Gual <lluis@novell.com>
6 // Copyright (c) 2008 Novell, Inc (http://www.novell.com)
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
28 // #define REFLECTION_INVOKE
31 using System
.Diagnostics
;
32 using System
.Collections
.Generic
;
33 using System
.Reflection
;
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
)
55 case MD
.Languages
.TargetObjectKind
.Array
:
56 case TargetObjectKind
.Fundamental
:
59 case TargetObjectKind
.Struct
:
60 case TargetObjectKind
.GenericInstance
:
61 case TargetObjectKind
.Class
:
62 TargetStructObject co
= obj
as TargetStructObject
;
65 TargetObject res
= co
.GetCurrentObject (ctx
.Thread
);
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
;
76 if (oob
.Type
.CanDereference
)
77 return oob
.GetDereferencedObject (ctx
.Thread
);
88 public static TargetObject
GetProxyObject (EvaluationContext ctx
, TargetObject obj
)
90 TypeDisplayData data
= GetTypeDisplayData (ctx
, obj
.Type
);
91 if (data
.ProxyType
== null)
94 TargetType ttype
= ctx
.Frame
.Language
.LookupType (data
.ProxyType
);
96 int i
= data
.ProxyType
.IndexOf (',');
98 ttype
= ctx
.Frame
.Language
.LookupType (data
.ProxyType
.Substring (0, i
).Trim ());
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;
114 td
= GetTypeDisplayDataInternal (ctx
, type
);
116 catch (Exception ex
) {
117 Console
.WriteLine (ex
);
120 typeDisplayData
[type
.Name
] = td
= TypeDisplayData
.Default
;
124 static TypeDisplayData
GetTypeDisplayDataInternal (EvaluationContext ctx
, TargetType type
)
126 TypeDisplayData data
;
127 if (typeDisplayData
.TryGetValue (type
.Name
, out data
))
130 data
= new TypeDisplayData ();
132 // Attribute inspection disabled until MDB provided a proper api for it
133 /* TargetObject tt = GetTypeOf (ctx, type);
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");
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);
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++) {
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
;
206 public static TargetType
LookupType (EvaluationContext ctx
, string name
)
208 TargetType ttype
= ctx
.Frame
.Language
.LookupType (name
);
210 int i
= name
.IndexOf (',');
212 ttype
= ctx
.Frame
.Language
.LookupType (name
.Substring (0, i
).Trim ());
217 public static string EvaluateDisplayString (EvaluationContext ctx
, TargetStructObject obj
, string exp
)
219 StringBuilder sb
= new StringBuilder ();
221 int i
= exp
.IndexOf ("{");
222 while (i
!= -1 && i
< exp
.Length
) {
223 sb
.Append (exp
.Substring (last
, i
- last
));
225 int j
= exp
.IndexOf ("}", i
);
228 string mem
= exp
.Substring (i
, j
-i
).Trim ();
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
));
236 i
= exp
.IndexOf ("{", last
);
238 sb
.Append (exp
.Substring (last
));
239 return sb
.ToString ();
242 public static string CallToString (EvaluationContext ctx
, TargetStructObject obj
)
245 TargetObject retval
= CallMethod (ctx
, "ToString", obj
);
246 object s
= ((TargetFundamentalObject
) retval
).GetObject (ctx
.Thread
);
247 return s
!= null ? s
.ToString () : "";
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
)
265 foreach (TargetMethodInfo met
in ct
.Constructors
) {
266 if (met
.Type
.ParameterTypes
.Length
== argtypes
.Length
)
267 candidates
.Add (new MemberReference (met
, type
));
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
;
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
);
299 for (int i
= 0; i
< types
.Length
; i
++) {
300 TargetType param_type
= sig
.ParameterTypes
[i
];
302 if (param_type
== types
[i
]) {
307 if (TargetObjectConvert
.ImplicitConversionExists (ctx
, types
[i
], param_type
))
310 error
= String
.Format (
311 "Argument {0}: Cannot implicitly convert `{1}' to `{2}'",
312 i
, types
[i
].Name
, param_type
.Name
);
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;
325 bool repeatedBestCount
= false;
327 foreach (MemberReference method
in candidates
) {
330 TargetFunctionType func
;
331 if (method
.Member
is TargetMethodInfo
)
332 func
= (TargetFunctionType
) ((TargetMethodInfo
) method
.Member
).Type
;
334 func
= (TargetFunctionType
) ((TargetPropertyInfo
) method
.Member
).Getter
;
336 if (!IsApplicable (ctx
, func
, argtypes
, out error
, out matchCount
))
339 if (matchCount
== bestCount
) {
340 repeatedBestCount
= true;
341 } else if (matchCount
> bestCount
) {
343 bestCount
= matchCount
;
344 repeatedBestCount
= false;
349 if (methodName
!= null)
350 throw new EvaluatorException ("Invalid arguments for method `{0}'.", methodName
);
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
);
359 throw new EvaluatorException ("Ambiguous arguments for indexer.", methodName
);
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
]);
398 public static TargetObject
CallMethod (EvaluationContext ctx
, string name
,
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
);
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
);
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
,
447 params TargetObject
[] args
)
449 return CallStaticMethod (ctx
, name
, ctx
.Frame
.Language
.LookupType (typeName
), args
);
452 public static TargetObject
CallStaticMethod (EvaluationContext ctx
, string name
,
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
);
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
);
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
);
514 TargetStructObject starget
= (TargetStructObject
) target
;
515 TargetPropertyInfo prop
= ResolveProperty (ctx
, starget
.Type
, name
, ref indexerArgs
);
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
);
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
);
552 TargetPropertyInfo prop
= ResolveProperty (ctx
, type
, name
, ref indexerArgs
);
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
);
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
;
580 objTarget
= TargetObjectConvert
.Cast (ctx
, objTarget
, frame
.Language
.ObjectType
);
582 int[] idx
= new int [1];
583 for (int n
=0; n
<args
.Length
; 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
);
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
);
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
)
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
);
643 fields
= cls
.GetFields (ctx
.Thread
);
645 properties
= cls
.GetProperties (ctx
.Thread
);
647 methods
= cls
.GetMethods (ctx
.Thread
);
650 TargetClassType ct
= type
as TargetClassType
;
651 if (ct
== null && type
.HasClassType
)
657 properties
= ct
.Properties
;
659 methods
= ct
.Methods
;
663 if (fields
!= null) {
664 foreach (TargetFieldInfo field
in fields
) {
665 if (access
== ReqMemberAccess
.Public
&& field
.Accessibility
!= TargetMemberAccessibility
.Public
)
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
)
676 if (access
== ReqMemberAccess
.Auto
&& prop
.Accessibility
!= TargetMemberAccessibility
.Public
&& prop
.Accessibility
!= TargetMemberAccessibility
.Protected
)
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
)
687 if (access
== ReqMemberAccess
.Auto
&& met
.Accessibility
!= TargetMemberAccessibility
.Public
&& met
.Accessibility
!= TargetMemberAccessibility
.Protected
)
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
));
700 type
= type
.GetParentType (ctx
.Thread
);
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
)
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
);
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");
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
);
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 ('/','+');
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 ('<');
782 StringBuilder sb
= new StringBuilder (typeName
.Substring (0, i
));
787 e
= FindTypeEnd (typeName
, i
);
788 sb
.Append (FixTypeName (typeName
.Substring (i
, e
-i
)));
791 } while (typeName
[e
] == ',');
793 sb
.Remove (sb
.Length
- 1, 1);
795 return sb
.ToString ();
801 static int FindTypeEnd (string str
, int index
)
804 while (index
< str
.Length
) {
805 char c
= str
[index
];
806 if (c
== '[' || c
== '<')
808 if (c
== ']' || c
== '>') {
814 if (c
== ',' && level
== 0)
822 public class MemberReference
824 public readonly TargetMemberInfo Member
;
825 public readonly TargetStructType DeclaringType
;
827 public MemberReference (TargetMemberInfo member
, TargetStructType type
)
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
));
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
))
874 return DebuggerBrowsableState
.Collapsed
;