2 using System.Collections.Generic;
3 using System.Reflection;
5 using Mono.Cecil.Metadata;
7 namespace Mono.Debugger.Soft
10 * Represents a type in the remote virtual machine.
11 * It might be better to make this a subclass of Type, but that could be
12 * difficult as some of our methods like GetMethods () return Mirror objects.
14 public class TypeMirror : Mirror
16 MethodMirror[] methods;
19 C.TypeDefinition meta;
20 FieldInfoMirror[] fields;
21 PropertyInfoMirror[] properties;
23 TypeMirror base_type, element_type, gtd;
25 CustomAttributeDataMirror[] cattrs;
27 Dictionary<TypeMirror, InterfaceMappingMirror> iface_map;
29 internal const BindingFlags DefaultBindingFlags =
30 BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
32 internal TypeMirror (VirtualMachine vm, long id) : base (vm, id) {
37 return GetInfo ().name;
41 public string Namespace {
47 public AssemblyMirror Assembly {
50 ass = vm.GetAssembly (GetInfo ().assembly);
56 public ModuleMirror Module {
59 module = vm.GetModule (GetInfo ().module);
65 public int MetadataToken {
67 return GetInfo ().token;
71 public TypeAttributes Attributes {
73 return (TypeAttributes)GetInfo ().attributes;
77 public TypeMirror BaseType {
79 // FIXME: base_type could be null for object/interfaces
80 if (base_type == null) {
81 base_type = vm.GetType (GetInfo ().base_type);
87 public int GetArrayRank () {
90 throw new ArgumentException ("Type must be an array type.");
95 public bool IsAbstract {
97 return (Attributes & TypeAttributes.Abstract) != 0;
101 public bool IsAnsiClass {
103 return (Attributes & TypeAttributes.StringFormatMask)
104 == TypeAttributes.AnsiClass;
108 public bool IsArray {
110 return IsArrayImpl ();
114 public bool IsAutoClass {
116 return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.AutoClass;
120 public bool IsAutoLayout {
122 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.AutoLayout;
126 public bool IsByRef {
128 return IsByRefImpl ();
132 public bool IsClass {
141 public bool IsCOMObject {
143 return IsCOMObjectImpl ();
147 public bool IsContextful {
149 return IsContextfulImpl ();
155 return GetInfo ().is_enum;
159 public bool IsExplicitLayout {
161 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExplicitLayout;
165 public bool IsImport {
167 return (Attributes & TypeAttributes.Import) != 0;
171 public bool IsInterface {
173 return (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
177 public bool IsLayoutSequential {
179 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.SequentialLayout;
183 public bool IsMarshalByRef {
185 return IsMarshalByRefImpl ();
189 public bool IsNestedAssembly {
191 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedAssembly;
195 public bool IsNestedFamANDAssem {
197 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamANDAssem;
201 public bool IsNestedFamily {
203 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily;
207 public bool IsNestedFamORAssem {
209 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem;
213 public bool IsNestedPrivate {
215 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate;
219 public bool IsNestedPublic {
221 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic;
225 public bool IsNotPublic {
227 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic;
231 public bool IsPointer {
233 return IsPointerImpl ();
237 public bool IsPrimitive {
239 return IsPrimitiveImpl ();
243 public bool IsPublic {
245 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public;
249 public bool IsSealed {
251 return (Attributes & TypeAttributes.Sealed) != 0;
255 public bool IsSerializable {
257 if ((Attributes & TypeAttributes.Serializable) != 0)
265 public bool IsSpecialName {
267 return (Attributes & TypeAttributes.SpecialName) != 0;
271 public bool IsUnicodeClass {
273 return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.UnicodeClass;
277 public bool IsValueType {
279 return IsValueTypeImpl ();
283 public bool HasElementType {
285 return HasElementTypeImpl ();
289 // Since protocol version 2.12
290 public bool IsGenericTypeDefinition {
292 vm.CheckProtocolVersion (2, 12);
298 public bool IsGenericType {
300 if (vm.Version.AtLeast (2, 12)) {
301 return GetInfo ().is_generic_type;
303 return Name.IndexOf ('`') != -1;
308 public TypeMirror GetElementType () {
310 if (element_type == null && info.element_type != 0)
311 element_type = vm.GetType (info.element_type);
315 public TypeMirror GetGenericTypeDefinition () {
316 vm.CheckProtocolVersion (2, 12);
320 throw new InvalidOperationException ();
321 gtd = vm.GetType (info.gtd);
326 public string FullName {
328 return GetInfo ().full_name;
332 public string CSharpName {
335 if (GetArrayRank () == 1)
336 return GetElementType ().CSharpName + "[]";
339 for (int i = 0; i < GetArrayRank (); ++i)
341 return GetElementType ().CSharpName + "[" + ranks + "]";
356 // FIXME: Only do this for real corlib types
357 if (Namespace == "System") {
371 public MethodMirror[] GetMethods () {
372 if (methods == null) {
373 long[] ids = vm.conn.Type_GetMethods (id);
374 MethodMirror[] m = new MethodMirror [ids.Length];
375 for (int i = 0; i < ids.Length; ++i) {
376 m [i] = vm.GetMethod (ids [i]);
383 // FIXME: Sync this with Type
384 public MethodMirror GetMethod (string name) {
385 foreach (var m in GetMethods ())
391 public FieldInfoMirror[] GetFields () {
398 long[] ids = vm.conn.Type_GetFields (id, out names, out types, out attrs);
400 FieldInfoMirror[] res = new FieldInfoMirror [ids.Length];
401 for (int i = 0; i < res.Length; ++i)
402 res [i] = new FieldInfoMirror (this, ids [i], names [i], vm.GetType (types [i]), (FieldAttributes)attrs [i]);
408 public FieldInfoMirror GetField (string name) {
410 throw new ArgumentNullException ("name");
411 foreach (var f in GetFields ())
417 public TypeMirror[] GetNestedTypes ()
419 return GetNestedTypes (DefaultBindingFlags);
422 public TypeMirror[] GetNestedTypes (BindingFlags bindingAttr) {
426 // FIXME: bindingAttr
428 var arr = new TypeMirror [info.nested.Length];
429 for (int i = 0; i < arr.Length; ++i)
430 arr [i] = vm.GetType (info.nested [i]);
436 public PropertyInfoMirror[] GetProperties () {
437 return GetProperties (DefaultBindingFlags);
440 public PropertyInfoMirror[] GetProperties (BindingFlags bindingAttr) {
441 if (properties != null)
444 PropInfo[] info = vm.conn.Type_GetProperties (id);
446 PropertyInfoMirror[] res = new PropertyInfoMirror [info.Length];
447 for (int i = 0; i < res.Length; ++i)
448 res [i] = new PropertyInfoMirror (this, info [i].id, info [i].name, vm.GetMethod (info [i].get_method), vm.GetMethod (info [i].set_method), (PropertyAttributes)info [i].attrs);
454 public PropertyInfoMirror GetProperty (string name) {
456 throw new ArgumentNullException ("name");
457 foreach (var p in GetProperties ())
463 public virtual bool IsAssignableFrom (TypeMirror c) {
465 throw new ArgumentNullException ("c");
469 // This is complex so do it in the debuggee
470 return vm.conn.Type_IsAssignableFrom (id, c.Id);
473 public Value GetValue (FieldInfoMirror field) {
474 return GetValues (new FieldInfoMirror [] { field }) [0];
477 public Value[] GetValues (IList<FieldInfoMirror> fields, ThreadMirror thread) {
479 throw new ArgumentNullException ("fields");
480 foreach (FieldInfoMirror f in fields) {
482 throw new ArgumentNullException ("field");
485 long[] ids = new long [fields.Count];
486 for (int i = 0; i < fields.Count; ++i)
487 ids [i] = fields [i].Id;
489 return vm.DecodeValues (vm.conn.Type_GetValues (id, ids, thread != null ? thread.Id : 0));
490 } catch (CommandException ex) {
491 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
492 throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
498 public Value[] GetValues (IList<FieldInfoMirror> fields) {
499 return GetValues (fields, null);
503 * Return the value of the [ThreadStatic] field FIELD on the thread THREAD.
505 public Value GetValue (FieldInfoMirror field, ThreadMirror thread) {
507 throw new ArgumentNullException ("thread");
508 CheckMirror (thread);
509 return GetValues (new FieldInfoMirror [] { field }, thread) [0];
512 public void SetValues (IList<FieldInfoMirror> fields, Value[] values) {
514 throw new ArgumentNullException ("fields");
516 throw new ArgumentNullException ("values");
517 foreach (FieldInfoMirror f in fields) {
519 throw new ArgumentNullException ("field");
522 foreach (Value v in values) {
524 throw new ArgumentNullException ("values");
527 long[] ids = new long [fields.Count];
528 for (int i = 0; i < fields.Count; ++i)
529 ids [i] = fields [i].Id;
531 vm.conn.Type_SetValues (id, ids, vm.EncodeValues (values));
532 } catch (CommandException ex) {
533 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
534 throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
540 public void SetValue (FieldInfoMirror field, Value value) {
541 SetValues (new FieldInfoMirror [] { field }, new Value [] { value });
544 public ObjectMirror GetTypeObject () {
545 return vm.GetObject (vm.conn.Type_GetObject (id));
549 * Return a list of source files without path info, where methods of
550 * this type are defined. Return an empty list if the information is not
552 * This can be used by a debugger to find out which types occur in a
553 * given source file, to filter the list of methods whose locations
554 * have to be checked when placing breakpoints.
556 public string[] GetSourceFiles () {
557 return GetSourceFiles (false);
560 string[] source_files;
561 string[] source_files_full_path;
562 public string[] GetSourceFiles (bool return_full_paths) {
563 string[] res = return_full_paths ? source_files_full_path : source_files;
565 res = vm.conn.Type_GetSourceFiles (id, return_full_paths);
566 if (return_full_paths)
567 source_files_full_path = res;
574 public C.TypeDefinition Metadata {
577 if (Assembly.Metadata == null || MetadataToken == 0)
579 meta = (C.TypeDefinition)Assembly.Metadata.MainModule.LookupToken (MetadataToken);
585 TypeInfo GetInfo () {
587 info = vm.conn.Type_GetInfo (id);
591 protected virtual TypeAttributes GetAttributeFlagsImpl () {
592 return (TypeAttributes)GetInfo ().attributes;
595 protected virtual bool HasElementTypeImpl () {
596 return IsArray || IsByRef || IsPointer;
599 protected virtual bool IsArrayImpl () {
600 return GetInfo ().rank > 0;
603 protected virtual bool IsByRefImpl () {
604 return GetInfo ().is_byref;
607 protected virtual bool IsCOMObjectImpl () {
611 protected virtual bool IsPointerImpl () {
612 return GetInfo ().is_pointer;
615 protected virtual bool IsPrimitiveImpl () {
616 return GetInfo ().is_primitive;
619 protected virtual bool IsValueTypeImpl ()
621 return GetInfo ().is_valuetype;
624 protected virtual bool IsContextfulImpl ()
630 protected virtual bool IsMarshalByRefImpl ()
636 // Same as Enum.GetUnderlyingType ()
637 public TypeMirror EnumUnderlyingType {
640 throw new ArgumentException ("Type is not an enum type.");
641 foreach (FieldInfoMirror f in GetFields ()) {
645 throw new NotImplementedException ();
650 * Creating the custom attributes themselves could modify the behavior of the
651 * debuggee, so we return objects similar to the CustomAttributeData objects
652 * used by the reflection-only functionality on .net.
654 public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
655 return GetCAttrs (null, inherit);
658 public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
659 if (attributeType == null)
660 throw new ArgumentNullException ("attributeType");
661 return GetCAttrs (attributeType, inherit);
664 CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
665 if (cattrs == null && Metadata != null && !Metadata.HasCustomAttributes)
666 cattrs = new CustomAttributeDataMirror [0];
668 // FIXME: Handle inherit
669 if (cattrs == null) {
670 CattrInfo[] info = vm.conn.Type_GetCustomAttributes (id, 0, false);
671 cattrs = CustomAttributeDataMirror.Create (vm, info);
673 var res = new List<CustomAttributeDataMirror> ();
674 foreach (var attr in cattrs)
675 if (type == null || attr.Constructor.DeclaringType == type)
677 return res.ToArray ();
680 public MethodMirror[] GetMethodsByNameFlags (string name, BindingFlags flags, bool ignoreCase) {
681 if (vm.conn.Version.AtLeast (2, 6)) {
682 long[] ids = vm.conn.Type_GetMethodsByNameFlags (id, name, (int)flags, ignoreCase);
683 MethodMirror[] m = new MethodMirror [ids.Length];
684 for (int i = 0; i < ids.Length; ++i)
685 m [i] = vm.GetMethod (ids [i]);
688 if (flags != (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.NonPublic))
689 throw new NotImplementedException ();
690 var res = new List<MethodMirror> ();
691 foreach (MethodMirror m in GetMethods ()) {
692 if ((!ignoreCase && m.Name == name) || (ignoreCase && m.Name.Equals (name, StringComparison.CurrentCultureIgnoreCase)))
695 return res.ToArray ();
699 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
700 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
703 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
704 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
707 [Obsolete ("Use the overload without the 'vm' argument")]
708 public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
709 return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
712 public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
713 return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
716 public Value EndInvokeMethod (IAsyncResult asyncResult) {
717 return ObjectMirror.EndInvokeMethodInternal (asyncResult);
720 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
721 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
724 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
725 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
728 // Since protocol version 2.11
729 public TypeMirror[] GetInterfaces () {
731 ifaces = vm.GetTypes (vm.conn.Type_GetInterfaces (id));
735 // Since protocol version 2.11
736 public InterfaceMappingMirror GetInterfaceMap (TypeMirror interfaceType) {
737 if (interfaceType == null)
738 throw new ArgumentNullException ("interfaceType");
739 if (!interfaceType.IsInterface)
740 throw new ArgumentException ("Argument must be an interface.", "interfaceType");
742 throw new ArgumentException ("'this' type cannot be an interface itself");
744 if (iface_map == null) {
745 // Query the info in bulk
747 var ids = new long [ifaces.Length];
748 for (int i = 0; i < ifaces.Length; ++i)
749 ids [i] = ifaces [i].Id;
751 var ifacemap = vm.conn.Type_GetInterfaceMap (id, ids);
753 var imap = new Dictionary<TypeMirror, InterfaceMappingMirror> ();
754 for (int i = 0; i < ifacemap.Length; ++i) {
755 IfaceMapInfo info = ifacemap [i];
757 MethodMirror[] imethods = new MethodMirror [info.iface_methods.Length];
758 for (int j = 0; j < info.iface_methods.Length; ++j)
759 imethods [j] = vm.GetMethod (info.iface_methods [j]);
761 MethodMirror[] tmethods = new MethodMirror [info.iface_methods.Length];
762 for (int j = 0; j < info.target_methods.Length; ++j)
763 tmethods [j] = vm.GetMethod (info.target_methods [j]);
765 InterfaceMappingMirror map = new InterfaceMappingMirror (vm, this, vm.GetType (info.iface_id), imethods, tmethods);
767 imap [map.InterfaceType] = map;
773 InterfaceMappingMirror res;
774 if (!iface_map.TryGetValue (interfaceType, out res))
775 throw new ArgumentException ("Interface not found", "interfaceType");