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;
28 TypeMirror[] type_args;
31 internal const BindingFlags DefaultBindingFlags =
32 BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
34 internal TypeMirror (VirtualMachine vm, long id) : base (vm, id) {
39 return GetInfo ().name;
43 public string Namespace {
49 public AssemblyMirror Assembly {
52 ass = vm.GetAssembly (GetInfo ().assembly);
58 public ModuleMirror Module {
61 module = vm.GetModule (GetInfo ().module);
67 public int MetadataToken {
69 return GetInfo ().token;
73 public TypeAttributes Attributes {
75 return (TypeAttributes)GetInfo ().attributes;
79 public TypeMirror BaseType {
81 // FIXME: base_type could be null for object/interfaces
82 if (base_type == null) {
83 base_type = vm.GetType (GetInfo ().base_type);
89 public int GetArrayRank () {
92 throw new ArgumentException ("Type must be an array type.");
97 public bool IsAbstract {
99 return (Attributes & TypeAttributes.Abstract) != 0;
103 public bool IsAnsiClass {
105 return (Attributes & TypeAttributes.StringFormatMask)
106 == TypeAttributes.AnsiClass;
110 public bool IsArray {
112 return IsArrayImpl ();
116 public bool IsAutoClass {
118 return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.AutoClass;
122 public bool IsAutoLayout {
124 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.AutoLayout;
128 public bool IsByRef {
130 return IsByRefImpl ();
134 public bool IsClass {
143 public bool IsCOMObject {
145 return IsCOMObjectImpl ();
149 public bool IsContextful {
151 return IsContextfulImpl ();
157 return GetInfo ().is_enum;
161 public bool IsExplicitLayout {
163 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExplicitLayout;
167 public bool IsImport {
169 return (Attributes & TypeAttributes.Import) != 0;
173 public bool IsInterface {
175 return (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
179 public bool IsLayoutSequential {
181 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.SequentialLayout;
185 public bool IsMarshalByRef {
187 return IsMarshalByRefImpl ();
191 public bool IsNestedAssembly {
193 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedAssembly;
197 public bool IsNestedFamANDAssem {
199 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamANDAssem;
203 public bool IsNestedFamily {
205 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily;
209 public bool IsNestedFamORAssem {
211 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem;
215 public bool IsNestedPrivate {
217 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate;
221 public bool IsNestedPublic {
223 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic;
227 public bool IsNotPublic {
229 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic;
233 public bool IsPointer {
235 return IsPointerImpl ();
239 public bool IsPrimitive {
241 return IsPrimitiveImpl ();
245 public bool IsPublic {
247 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public;
251 public bool IsSealed {
253 return (Attributes & TypeAttributes.Sealed) != 0;
257 public bool IsSerializable {
259 if ((Attributes & TypeAttributes.Serializable) != 0)
267 public bool IsSpecialName {
269 return (Attributes & TypeAttributes.SpecialName) != 0;
273 public bool IsUnicodeClass {
275 return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.UnicodeClass;
279 public bool IsValueType {
281 return IsValueTypeImpl ();
285 public bool HasElementType {
287 return HasElementTypeImpl ();
291 // Since protocol version 2.12
292 public bool IsGenericTypeDefinition {
294 vm.CheckProtocolVersion (2, 12);
300 public bool IsGenericType {
302 if (vm.Version.AtLeast (2, 12)) {
303 return GetInfo ().is_generic_type;
305 return Name.IndexOf ('`') != -1;
310 public TypeMirror GetElementType () {
312 if (element_type == null && info.element_type != 0)
313 element_type = vm.GetType (info.element_type);
317 public TypeMirror GetGenericTypeDefinition () {
318 vm.CheckProtocolVersion (2, 12);
322 throw new InvalidOperationException ();
323 gtd = vm.GetType (info.gtd);
328 // Since protocol version 2.15
329 public TypeMirror[] GetGenericArguments () {
330 vm.CheckProtocolVersion (2, 15);
331 if (type_args == null)
332 type_args = vm.GetTypes (GetInfo ().type_args);
336 public string FullName {
338 return GetInfo ().full_name;
342 public string CSharpName {
345 if (GetArrayRank () == 1)
346 return GetElementType ().CSharpName + "[]";
349 for (int i = 0; i < GetArrayRank (); ++i)
351 return GetElementType ().CSharpName + "[" + ranks + "]";
384 // FIXME: Only do this for real corlib types
385 if (Namespace == "System") {
403 public MethodMirror[] GetMethods () {
404 if (methods == null) {
405 long[] ids = vm.conn.Type_GetMethods (id);
406 MethodMirror[] m = new MethodMirror [ids.Length];
407 for (int i = 0; i < ids.Length; ++i) {
408 m [i] = vm.GetMethod (ids [i]);
415 // FIXME: Sync this with Type
416 public MethodMirror GetMethod (string name) {
417 foreach (var m in GetMethods ())
423 public FieldInfoMirror[] GetFields () {
430 long[] ids = vm.conn.Type_GetFields (id, out names, out types, out attrs);
432 FieldInfoMirror[] res = new FieldInfoMirror [ids.Length];
433 for (int i = 0; i < res.Length; ++i)
434 res [i] = new FieldInfoMirror (this, ids [i], names [i], vm.GetType (types [i]), (FieldAttributes)attrs [i]);
440 public FieldInfoMirror GetField (string name) {
442 throw new ArgumentNullException ("name");
443 foreach (var f in GetFields ())
449 public TypeMirror[] GetNestedTypes ()
451 return GetNestedTypes (DefaultBindingFlags);
454 public TypeMirror[] GetNestedTypes (BindingFlags bindingAttr) {
458 // FIXME: bindingAttr
460 var arr = new TypeMirror [info.nested.Length];
461 for (int i = 0; i < arr.Length; ++i)
462 arr [i] = vm.GetType (info.nested [i]);
468 public PropertyInfoMirror[] GetProperties () {
469 return GetProperties (DefaultBindingFlags);
472 public PropertyInfoMirror[] GetProperties (BindingFlags bindingAttr) {
473 if (properties != null)
476 PropInfo[] info = vm.conn.Type_GetProperties (id);
478 PropertyInfoMirror[] res = new PropertyInfoMirror [info.Length];
479 for (int i = 0; i < res.Length; ++i)
480 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);
486 public PropertyInfoMirror GetProperty (string name) {
488 throw new ArgumentNullException ("name");
489 foreach (var p in GetProperties ())
495 public virtual bool IsAssignableFrom (TypeMirror c) {
497 throw new ArgumentNullException ("c");
501 // This is complex so do it in the debuggee
502 return vm.conn.Type_IsAssignableFrom (id, c.Id);
505 public Value GetValue (FieldInfoMirror field) {
506 return GetValues (new FieldInfoMirror [] { field }) [0];
509 public Value[] GetValues (IList<FieldInfoMirror> fields, ThreadMirror thread) {
511 throw new ArgumentNullException ("fields");
512 foreach (FieldInfoMirror f in fields) {
514 throw new ArgumentNullException ("field");
517 long[] ids = new long [fields.Count];
518 for (int i = 0; i < fields.Count; ++i)
519 ids [i] = fields [i].Id;
521 return vm.DecodeValues (vm.conn.Type_GetValues (id, ids, thread != null ? thread.Id : 0));
522 } catch (CommandException ex) {
523 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
524 throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
530 public Value[] GetValues (IList<FieldInfoMirror> fields) {
531 return GetValues (fields, null);
535 * Return the value of the [ThreadStatic] field FIELD on the thread THREAD.
537 public Value GetValue (FieldInfoMirror field, ThreadMirror thread) {
539 throw new ArgumentNullException ("thread");
540 CheckMirror (thread);
541 return GetValues (new FieldInfoMirror [] { field }, thread) [0];
544 public void SetValues (IList<FieldInfoMirror> fields, Value[] values) {
546 throw new ArgumentNullException ("fields");
548 throw new ArgumentNullException ("values");
549 foreach (FieldInfoMirror f in fields) {
551 throw new ArgumentNullException ("field");
554 foreach (Value v in values) {
556 throw new ArgumentNullException ("values");
559 long[] ids = new long [fields.Count];
560 for (int i = 0; i < fields.Count; ++i)
561 ids [i] = fields [i].Id;
563 vm.conn.Type_SetValues (id, ids, vm.EncodeValues (values));
564 } catch (CommandException ex) {
565 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
566 throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
572 public void SetValue (FieldInfoMirror field, Value value) {
573 SetValues (new FieldInfoMirror [] { field }, new Value [] { value });
576 public ObjectMirror GetTypeObject () {
577 return vm.GetObject (vm.conn.Type_GetObject (id));
581 * Return a list of source files without path info, where methods of
582 * this type are defined. Return an empty list if the information is not
584 * This can be used by a debugger to find out which types occur in a
585 * given source file, to filter the list of methods whose locations
586 * have to be checked when placing breakpoints.
588 public string[] GetSourceFiles () {
589 return GetSourceFiles (false);
592 string[] source_files;
593 string[] source_files_full_path;
594 public string[] GetSourceFiles (bool return_full_paths) {
595 string[] res = return_full_paths ? source_files_full_path : source_files;
597 res = vm.conn.Type_GetSourceFiles (id, return_full_paths);
598 if (return_full_paths)
599 source_files_full_path = res;
606 public C.TypeDefinition Metadata {
609 if (Assembly.Metadata == null || MetadataToken == 0)
611 meta = (C.TypeDefinition)Assembly.Metadata.MainModule.LookupToken (MetadataToken);
617 TypeInfo GetInfo () {
619 info = vm.conn.Type_GetInfo (id);
623 protected virtual TypeAttributes GetAttributeFlagsImpl () {
624 return (TypeAttributes)GetInfo ().attributes;
627 protected virtual bool HasElementTypeImpl () {
628 return IsArray || IsByRef || IsPointer;
631 protected virtual bool IsArrayImpl () {
632 return GetInfo ().rank > 0;
635 protected virtual bool IsByRefImpl () {
636 return GetInfo ().is_byref;
639 protected virtual bool IsCOMObjectImpl () {
643 protected virtual bool IsPointerImpl () {
644 return GetInfo ().is_pointer;
647 protected virtual bool IsPrimitiveImpl () {
648 return GetInfo ().is_primitive;
651 protected virtual bool IsValueTypeImpl ()
653 return GetInfo ().is_valuetype;
656 protected virtual bool IsContextfulImpl ()
662 protected virtual bool IsMarshalByRefImpl ()
668 // Same as Enum.GetUnderlyingType ()
669 public TypeMirror EnumUnderlyingType {
672 throw new ArgumentException ("Type is not an enum type.");
673 foreach (FieldInfoMirror f in GetFields ()) {
677 throw new NotImplementedException ();
682 * Creating the custom attributes themselves could modify the behavior of the
683 * debuggee, so we return objects similar to the CustomAttributeData objects
684 * used by the reflection-only functionality on .net.
686 public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
687 return GetCAttrs (null, inherit);
690 public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
691 if (attributeType == null)
692 throw new ArgumentNullException ("attributeType");
693 return GetCAttrs (attributeType, inherit);
696 CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
697 if (cattrs == null && Metadata != null && !Metadata.HasCustomAttributes)
698 cattrs = new CustomAttributeDataMirror [0];
700 // FIXME: Handle inherit
701 if (cattrs == null) {
702 CattrInfo[] info = vm.conn.Type_GetCustomAttributes (id, 0, false);
703 cattrs = CustomAttributeDataMirror.Create (vm, info);
705 var res = new List<CustomAttributeDataMirror> ();
706 foreach (var attr in cattrs)
707 if (type == null || attr.Constructor.DeclaringType == type)
709 return res.ToArray ();
712 public MethodMirror[] GetMethodsByNameFlags (string name, BindingFlags flags, bool ignoreCase) {
713 if (vm.conn.Version.AtLeast (2, 6)) {
714 long[] ids = vm.conn.Type_GetMethodsByNameFlags (id, name, (int)flags, ignoreCase);
715 MethodMirror[] m = new MethodMirror [ids.Length];
716 for (int i = 0; i < ids.Length; ++i)
717 m [i] = vm.GetMethod (ids [i]);
720 if ((flags & BindingFlags.IgnoreCase) != 0) {
721 flags &= ~BindingFlags.IgnoreCase;
725 if (flags == BindingFlags.Default)
726 flags = BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static;
728 MethodAttributes access = (MethodAttributes) 0;
729 bool matchInstance = false;
730 bool matchStatic = false;
732 if ((flags & BindingFlags.NonPublic) != 0) {
733 access |= MethodAttributes.Private;
734 flags &= ~BindingFlags.NonPublic;
736 if ((flags & BindingFlags.Public) != 0) {
737 access |= MethodAttributes.Public;
738 flags &= ~BindingFlags.Public;
740 if ((flags & BindingFlags.Instance) != 0) {
741 flags &= ~BindingFlags.Instance;
742 matchInstance = true;
744 if ((flags & BindingFlags.Static) != 0) {
745 flags &= ~BindingFlags.Static;
749 if ((int) flags != 0)
750 throw new NotImplementedException ();
752 var res = new List<MethodMirror> ();
753 foreach (MethodMirror m in GetMethods ()) {
754 if ((m.Attributes & access) == (MethodAttributes) 0)
757 if (!((matchStatic && m.IsStatic) || (matchInstance && !m.IsStatic)))
760 if ((!ignoreCase && m.Name == name) || (ignoreCase && m.Name.Equals (name, StringComparison.CurrentCultureIgnoreCase)))
763 return res.ToArray ();
767 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
768 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
771 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
772 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
775 [Obsolete ("Use the overload without the 'vm' argument")]
776 public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
777 return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
780 public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
781 return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
784 public Value EndInvokeMethod (IAsyncResult asyncResult) {
785 return ObjectMirror.EndInvokeMethodInternal (asyncResult);
788 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
789 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
792 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
793 return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
796 // Since protocol version 2.11
797 public TypeMirror[] GetInterfaces () {
799 ifaces = vm.GetTypes (vm.conn.Type_GetInterfaces (id));
803 // Since protocol version 2.11
804 public InterfaceMappingMirror GetInterfaceMap (TypeMirror interfaceType) {
805 if (interfaceType == null)
806 throw new ArgumentNullException ("interfaceType");
807 if (!interfaceType.IsInterface)
808 throw new ArgumentException ("Argument must be an interface.", "interfaceType");
810 throw new ArgumentException ("'this' type cannot be an interface itself");
812 if (iface_map == null) {
813 // Query the info in bulk
815 var ids = new long [ifaces.Length];
816 for (int i = 0; i < ifaces.Length; ++i)
817 ids [i] = ifaces [i].Id;
819 var ifacemap = vm.conn.Type_GetInterfaceMap (id, ids);
821 var imap = new Dictionary<TypeMirror, InterfaceMappingMirror> ();
822 for (int i = 0; i < ifacemap.Length; ++i) {
823 IfaceMapInfo info = ifacemap [i];
825 MethodMirror[] imethods = new MethodMirror [info.iface_methods.Length];
826 for (int j = 0; j < info.iface_methods.Length; ++j)
827 imethods [j] = vm.GetMethod (info.iface_methods [j]);
829 MethodMirror[] tmethods = new MethodMirror [info.iface_methods.Length];
830 for (int j = 0; j < info.target_methods.Length; ++j)
831 tmethods [j] = vm.GetMethod (info.target_methods [j]);
833 InterfaceMappingMirror map = new InterfaceMappingMirror (vm, this, vm.GetType (info.iface_id), imethods, tmethods);
835 imap [map.InterfaceType] = map;
841 InterfaceMappingMirror res;
842 if (!iface_map.TryGetValue (interfaceType, out res))
843 throw new ArgumentException ("Interface not found", "interfaceType");
847 // Return whenever the type initializer of this type has ran
848 // Since protocol version 2.23
849 public bool IsInitialized {
851 vm.CheckProtocolVersion (2, 23);
853 inited = vm.conn.Type_IsInitialized (id);