2 using System.Collections.Generic;
3 using System.Reflection;
5 using Mono.Cecil.Metadata;
7 using System.Threading.Tasks;
10 namespace Mono.Debugger.Soft
13 * Represents a type in the remote virtual machine.
14 * It might be better to make this a subclass of Type, but that could be
15 * difficult as some of our methods like GetMethods () return Mirror objects.
17 public class TypeMirror : Mirror
19 MethodMirror[] methods;
22 C.TypeDefinition meta;
23 FieldInfoMirror[] fields;
24 PropertyInfoMirror[] properties;
26 TypeMirror base_type, element_type, gtd;
28 CustomAttributeDataMirror[] cattrs;
30 Dictionary<TypeMirror, InterfaceMappingMirror> iface_map;
31 TypeMirror[] type_args;
32 bool cached_base_type;
35 internal const BindingFlags DefaultBindingFlags =
36 BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
38 internal TypeMirror (VirtualMachine vm, long id) : base (vm, id) {
43 return GetInfo ().name;
47 public string Namespace {
53 public AssemblyMirror Assembly {
56 ass = vm.GetAssembly (GetInfo ().assembly);
62 public ModuleMirror Module {
65 module = vm.GetModule (GetInfo ().module);
71 public int MetadataToken {
73 return GetInfo ().token;
77 public TypeAttributes Attributes {
79 return (TypeAttributes)GetInfo ().attributes;
83 public TypeMirror BaseType {
85 if (!cached_base_type) {
86 base_type = vm.GetType (GetInfo ().base_type);
87 cached_base_type = true;
93 public int GetArrayRank () {
96 throw new ArgumentException ("Type must be an array type.");
101 public bool IsAbstract {
103 return (Attributes & TypeAttributes.Abstract) != 0;
107 public bool IsAnsiClass {
109 return (Attributes & TypeAttributes.StringFormatMask)
110 == TypeAttributes.AnsiClass;
114 public bool IsArray {
116 return IsArrayImpl ();
120 public bool IsAutoClass {
122 return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.AutoClass;
126 public bool IsAutoLayout {
128 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.AutoLayout;
132 public bool IsByRef {
134 return IsByRefImpl ();
138 public bool IsClass {
147 public bool IsCOMObject {
149 return IsCOMObjectImpl ();
153 public bool IsContextful {
155 return IsContextfulImpl ();
161 return GetInfo ().is_enum;
165 public bool IsExplicitLayout {
167 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExplicitLayout;
171 public bool IsImport {
173 return (Attributes & TypeAttributes.Import) != 0;
177 public bool IsInterface {
179 return (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
183 public bool IsLayoutSequential {
185 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.SequentialLayout;
189 public bool IsMarshalByRef {
191 return IsMarshalByRefImpl ();
195 public bool IsNestedAssembly {
197 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedAssembly;
201 public bool IsNestedFamANDAssem {
203 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamANDAssem;
207 public bool IsNestedFamily {
209 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily;
213 public bool IsNestedFamORAssem {
215 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem;
219 public bool IsNestedPrivate {
221 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate;
225 public bool IsNestedPublic {
227 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic;
231 public bool IsNotPublic {
233 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic;
237 public bool IsPointer {
239 return IsPointerImpl ();
243 public bool IsPrimitive {
245 return IsPrimitiveImpl ();
249 public bool IsPublic {
251 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public;
255 public bool IsSealed {
257 return (Attributes & TypeAttributes.Sealed) != 0;
261 public bool IsSerializable {
263 if ((Attributes & TypeAttributes.Serializable) != 0)
271 public bool IsSpecialName {
273 return (Attributes & TypeAttributes.SpecialName) != 0;
277 public bool IsUnicodeClass {
279 return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.UnicodeClass;
283 public bool IsValueType {
285 return IsValueTypeImpl ();
289 public bool HasElementType {
291 return HasElementTypeImpl ();
295 // Since protocol version 2.12
296 public bool IsGenericTypeDefinition {
298 vm.CheckProtocolVersion (2, 12);
304 public bool IsGenericType {
306 if (vm.Version.AtLeast (2, 12)) {
307 return GetInfo ().is_generic_type;
309 return Name.IndexOf ('`') != -1;
314 public TypeMirror GetElementType () {
316 if (element_type == null && info.element_type != 0)
317 element_type = vm.GetType (info.element_type);
321 public TypeMirror GetGenericTypeDefinition () {
322 vm.CheckProtocolVersion (2, 12);
326 throw new InvalidOperationException ();
327 gtd = vm.GetType (info.gtd);
332 // Since protocol version 2.15
333 public TypeMirror[] GetGenericArguments () {
334 vm.CheckProtocolVersion (2, 15);
335 if (type_args == null)
336 type_args = vm.GetTypes (GetInfo ().type_args);
340 public string FullName {
342 return GetInfo ().full_name;
346 public string CSharpName {
349 if (GetArrayRank () == 1)
350 return GetElementType ().CSharpName + "[]";
353 for (int i = 0; i < GetArrayRank (); ++i)
355 return GetElementType ().CSharpName + "[" + ranks + "]";
388 // FIXME: Only do this for real corlib types
389 if (Namespace == "System") {
407 public MethodMirror[] GetMethods () {
408 if (methods == null) {
409 long[] ids = vm.conn.Type_GetMethods (id);
410 MethodMirror[] m = new MethodMirror [ids.Length];
411 for (int i = 0; i < ids.Length; ++i) {
412 m [i] = vm.GetMethod (ids [i]);
419 // FIXME: Sync this with Type
420 public MethodMirror GetMethod (string name) {
421 foreach (var m in GetMethods ())
427 public FieldInfoMirror[] GetFields () {
434 long[] ids = vm.conn.Type_GetFields (id, out names, out types, out attrs);
436 FieldInfoMirror[] res = new FieldInfoMirror [ids.Length];
437 for (int i = 0; i < res.Length; ++i)
438 res [i] = new FieldInfoMirror (this, ids [i], names [i], vm.GetType (types [i]), (FieldAttributes)attrs [i]);
444 public FieldInfoMirror GetField (string name) {
446 throw new ArgumentNullException ("name");
447 foreach (var f in GetFields ())
453 public TypeMirror[] GetNestedTypes ()
455 return GetNestedTypes (DefaultBindingFlags);
458 public TypeMirror[] GetNestedTypes (BindingFlags bindingAttr) {
462 // FIXME: bindingAttr
464 var arr = new TypeMirror [info.nested.Length];
465 for (int i = 0; i < arr.Length; ++i)
466 arr [i] = vm.GetType (info.nested [i]);
472 public PropertyInfoMirror[] GetProperties () {
473 return GetProperties (DefaultBindingFlags);
476 public PropertyInfoMirror[] GetProperties (BindingFlags bindingAttr) {
477 if (properties != null)
480 PropInfo[] info = vm.conn.Type_GetProperties (id);
482 PropertyInfoMirror[] res = new PropertyInfoMirror [info.Length];
483 for (int i = 0; i < res.Length; ++i)
484 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);
490 public PropertyInfoMirror GetProperty (string name) {
492 throw new ArgumentNullException ("name");
493 foreach (var p in GetProperties ())
499 public virtual bool IsAssignableFrom (TypeMirror c) {
501 throw new ArgumentNullException ("c");
505 // This is complex so do it in the debuggee
506 return vm.conn.Type_IsAssignableFrom (id, c.Id);
509 public Value GetValue (FieldInfoMirror field) {
510 return GetValues (new FieldInfoMirror [] { field }) [0];
513 public Value[] GetValues (IList<FieldInfoMirror> fields, ThreadMirror thread) {
515 throw new ArgumentNullException ("fields");
516 foreach (FieldInfoMirror f in fields) {
518 throw new ArgumentNullException ("field");
521 long[] ids = new long [fields.Count];
522 for (int i = 0; i < fields.Count; ++i)
523 ids [i] = fields [i].Id;
525 return vm.DecodeValues (vm.conn.Type_GetValues (id, ids, thread != null ? thread.Id : 0));
526 } catch (CommandException ex) {
527 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
528 throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
534 public Value[] GetValues (IList<FieldInfoMirror> fields) {
535 return GetValues (fields, null);
539 * Return the value of the [ThreadStatic] field FIELD on the thread THREAD.
541 public Value GetValue (FieldInfoMirror field, ThreadMirror thread) {
543 throw new ArgumentNullException ("thread");
544 CheckMirror (thread);
545 return GetValues (new FieldInfoMirror [] { field }, thread) [0];
548 public void SetValues (IList<FieldInfoMirror> fields, Value[] values) {
550 throw new ArgumentNullException ("fields");
552 throw new ArgumentNullException ("values");
553 foreach (FieldInfoMirror f in fields) {
555 throw new ArgumentNullException ("field");
558 foreach (Value v in values) {
560 throw new ArgumentNullException ("values");
563 long[] ids = new long [fields.Count];
564 for (int i = 0; i < fields.Count; ++i)
565 ids [i] = fields [i].Id;
567 vm.conn.Type_SetValues (id, ids, vm.EncodeValues (values));
568 } catch (CommandException ex) {
569 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
570 throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
576 public void SetValue (FieldInfoMirror field, Value value) {
577 SetValues (new FieldInfoMirror [] { field }, new Value [] { value });
580 public ObjectMirror GetTypeObject () {
581 return vm.GetObject (vm.conn.Type_GetObject (id));
585 * Return a list of source files without path info, where methods of
586 * this type are defined. Return an empty list if the information is not
588 * This can be used by a debugger to find out which types occur in a
589 * given source file, to filter the list of methods whose locations
590 * have to be checked when placing breakpoints.
592 public string[] GetSourceFiles () {
593 return GetSourceFiles (false);
596 string[] source_files;
597 string[] source_files_full_path;
598 public string[] GetSourceFiles (bool returnFullPaths) {
599 string[] res = returnFullPaths ? source_files_full_path : source_files;
601 res = vm.conn.Type_GetSourceFiles (id, returnFullPaths);
603 source_files_full_path = res;
610 public C.TypeDefinition Metadata {
613 if (Assembly.Metadata == null || MetadataToken == 0)
615 meta = (C.TypeDefinition)Assembly.Metadata.MainModule.LookupToken (MetadataToken);
621 TypeInfo GetInfo () {
623 info = vm.conn.Type_GetInfo (id);
627 protected virtual TypeAttributes GetAttributeFlagsImpl () {
628 return (TypeAttributes)GetInfo ().attributes;
631 protected virtual bool HasElementTypeImpl () {
632 return IsArray || IsByRef || IsPointer;
635 protected virtual bool IsArrayImpl () {
636 return GetInfo ().rank > 0;
639 protected virtual bool IsByRefImpl () {
640 return GetInfo ().is_byref;
643 protected virtual bool IsCOMObjectImpl () {
647 protected virtual bool IsPointerImpl () {
648 return GetInfo ().is_pointer;
651 protected virtual bool IsPrimitiveImpl () {
652 return GetInfo ().is_primitive;
655 protected virtual bool IsValueTypeImpl ()
657 return GetInfo ().is_valuetype;
660 protected virtual bool IsContextfulImpl ()
666 protected virtual bool IsMarshalByRefImpl ()
672 // Same as Enum.GetUnderlyingType ()
673 public TypeMirror EnumUnderlyingType {
676 throw new ArgumentException ("Type is not an enum type.");
677 foreach (FieldInfoMirror f in GetFields ()) {
681 throw new NotImplementedException ();
686 * Creating the custom attributes themselves could modify the behavior of the
687 * debuggee, so we return objects similar to the CustomAttributeData objects
688 * used by the reflection-only functionality on .net.
690 public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
691 return GetCustomAttrs (null, inherit);
694 public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
695 if (attributeType == null)
696 throw new ArgumentNullException ("attributeType");
697 return GetCustomAttrs (attributeType, inherit);
700 void AppendCustomAttrs (IList<CustomAttributeDataMirror> attrs, TypeMirror type, bool inherit)
702 if (cattrs == null && Metadata != null && !Metadata.HasCustomAttributes)
703 cattrs = new CustomAttributeDataMirror [0];
705 if (cattrs == null) {
706 CattrInfo[] info = vm.conn.Type_GetCustomAttributes (id, 0, false);
707 cattrs = CustomAttributeDataMirror.Create (vm, info);
710 foreach (var attr in cattrs) {
711 if (type == null || attr.Constructor.DeclaringType == type)
715 if (inherit && BaseType != null)
716 BaseType.AppendCustomAttrs (attrs, type, inherit);
719 CustomAttributeDataMirror[] GetCustomAttrs (TypeMirror type, bool inherit) {
720 var attrs = new List<CustomAttributeDataMirror> ();
721 AppendCustomAttrs (attrs, type, inherit);
722 return attrs.ToArray ();
725 public MethodMirror[] GetMethodsByNameFlags (string name, BindingFlags flags, bool ignoreCase) {
726 if (vm.conn.Version.AtLeast (2, 6)) {
727 long[] ids = vm.conn.Type_GetMethodsByNameFlags (id, name, (int)flags, ignoreCase);
728 MethodMirror[] m = new MethodMirror [ids.Length];
729 for (int i = 0; i < ids.Length; ++i)
730 m [i] = vm.GetMethod (ids [i]);
733 if ((flags & BindingFlags.IgnoreCase) != 0) {
734 flags &= ~BindingFlags.IgnoreCase;
738 if (flags == BindingFlags.Default)
739 flags = BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static;
741 MethodAttributes access = (MethodAttributes) 0;
742 bool matchInstance = false;
743 bool matchStatic = false;
745 if ((flags & BindingFlags.NonPublic) != 0) {
746 access |= MethodAttributes.Private;
747 flags &= ~BindingFlags.NonPublic;
749 if ((flags & BindingFlags.Public) != 0) {
750 access |= MethodAttributes.Public;
751 flags &= ~BindingFlags.Public;
753 if ((flags & BindingFlags.Instance) != 0) {
754 flags &= ~BindingFlags.Instance;
755 matchInstance = true;
757 if ((flags & BindingFlags.Static) != 0) {
758 flags &= ~BindingFlags.Static;
762 if ((int) flags != 0)
763 throw new NotImplementedException ();
765 var res = new List<MethodMirror> ();
766 foreach (MethodMirror m in GetMethods ()) {
767 if ((m.Attributes & access) == (MethodAttributes) 0)
770 if (!((matchStatic && m.IsStatic) || (matchInstance && !m.IsStatic)))
773 if ((!ignoreCase && m.Name == name) || (ignoreCase && m.Name.Equals (name, StringComparison.CurrentCultureIgnoreCase)))
776 return res.ToArray ();
780 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
781 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
784 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
785 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
788 [Obsolete ("Use the overload without the 'vm' argument")]
789 public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
790 return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
793 public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
794 return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
797 public Value EndInvokeMethod (IAsyncResult asyncResult) {
798 return ObjectMirror.EndInvokeMethodInternal (asyncResult);
802 public Task<Value> InvokeMethodAsync (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options = InvokeOptions.None) {
803 var tcs = new TaskCompletionSource<Value> ();
804 BeginInvokeMethod (thread, method, arguments, options, iar =>
807 tcs.SetResult (EndInvokeMethod (iar));
808 } catch (OperationCanceledException) {
809 tcs.TrySetCanceled ();
810 } catch (Exception ex) {
811 tcs.TrySetException (ex);
818 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
819 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
822 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
823 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
826 // Since protocol version 2.11
827 public TypeMirror[] GetInterfaces () {
829 ifaces = vm.GetTypes (vm.conn.Type_GetInterfaces (id));
833 // Since protocol version 2.11
834 public InterfaceMappingMirror GetInterfaceMap (TypeMirror interfaceType) {
835 if (interfaceType == null)
836 throw new ArgumentNullException ("interfaceType");
837 if (!interfaceType.IsInterface)
838 throw new ArgumentException ("Argument must be an interface.", "interfaceType");
840 throw new ArgumentException ("'this' type cannot be an interface itself");
842 if (iface_map == null) {
843 // Query the info in bulk
845 var ids = new long [ifaces.Length];
846 for (int i = 0; i < ifaces.Length; ++i)
847 ids [i] = ifaces [i].Id;
849 var ifacemap = vm.conn.Type_GetInterfaceMap (id, ids);
851 var imap = new Dictionary<TypeMirror, InterfaceMappingMirror> ();
852 for (int i = 0; i < ifacemap.Length; ++i) {
853 IfaceMapInfo info = ifacemap [i];
855 MethodMirror[] imethods = new MethodMirror [info.iface_methods.Length];
856 for (int j = 0; j < info.iface_methods.Length; ++j)
857 imethods [j] = vm.GetMethod (info.iface_methods [j]);
859 MethodMirror[] tmethods = new MethodMirror [info.iface_methods.Length];
860 for (int j = 0; j < info.target_methods.Length; ++j)
861 tmethods [j] = vm.GetMethod (info.target_methods [j]);
863 InterfaceMappingMirror map = new InterfaceMappingMirror (vm, this, vm.GetType (info.iface_id), imethods, tmethods);
865 imap [map.InterfaceType] = map;
871 InterfaceMappingMirror res;
872 if (!iface_map.TryGetValue (interfaceType, out res))
873 throw new ArgumentException ("Interface not found", "interfaceType");
877 // Return whenever the type initializer of this type has ran
878 // Since protocol version 2.23
879 public bool IsInitialized {
881 vm.CheckProtocolVersion (2, 23);
883 inited = vm.conn.Type_IsInitialized (id);