Replace SIZEOF_REGISTER with sizeof(mgreg_t) for consistency with sizeof(gpointer)
[mono.git] / mcs / class / Mono.Debugger.Soft / Mono.Debugger.Soft / TypeMirror.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Reflection;
4 using C = Mono.Cecil;
5 using Mono.Cecil.Metadata;
6
7 namespace Mono.Debugger.Soft
8 {
9         /*
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.
13          */
14         public class TypeMirror : Mirror
15         {
16                 MethodMirror[] methods;
17                 AssemblyMirror ass;
18                 ModuleMirror module;
19                 C.TypeDefinition meta;
20                 FieldInfoMirror[] fields;
21                 PropertyInfoMirror[] properties;
22                 TypeInfo info;
23                 TypeMirror base_type, element_type;
24                 TypeMirror[] nested;
25                 CustomAttributeDataMirror[] cattrs;
26
27                 internal const BindingFlags DefaultBindingFlags =
28                 BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
29
30                 internal TypeMirror (VirtualMachine vm, long id) : base (vm, id) {
31                 }
32
33                 public string Name {
34                         get {
35                                 return GetInfo ().name;
36                         }
37             }
38
39                 public string Namespace {
40                         get {
41                                 return GetInfo ().ns;
42                         }
43             }
44
45                 public AssemblyMirror Assembly {
46                         get {
47                                 if (ass == null) {
48                                         ass = vm.GetAssembly (GetInfo ().assembly);
49                                 }
50                                 return ass;
51                         }
52                 }
53
54                 public ModuleMirror Module {
55                         get {
56                                 if (module == null) {
57                                         module = vm.GetModule (GetInfo ().module);
58                                 }                                                                                  
59                                 return module;
60                         }
61                 }
62
63                 public int MetadataToken {
64                         get {
65                                 return GetInfo ().token;
66                         }
67                 }
68
69                 public TypeAttributes Attributes {
70                         get {
71                                 return (TypeAttributes)GetInfo ().attributes;
72                         }
73                 }
74
75                 public TypeMirror BaseType {
76                         get {
77                                 // FIXME: base_type could be null for object/interfaces
78                                 if (base_type == null) {
79                                         base_type = vm.GetType (GetInfo ().base_type);
80                                 }
81                                 return base_type;
82                         }
83                 }
84
85                 public int GetArrayRank () {
86                         GetInfo ();
87                         if (info.rank == 0)
88                                 throw new ArgumentException ("Type must be an array type.");
89                         return info.rank;
90                 }
91
92
93                 public bool IsAbstract {
94                         get {
95                                 return (Attributes & TypeAttributes.Abstract) != 0;
96                         }
97                 }
98
99                 public bool IsAnsiClass {
100                         get {
101                                 return (Attributes & TypeAttributes.StringFormatMask)
102                                 == TypeAttributes.AnsiClass;
103                         }
104                 }
105
106                 public bool IsArray {
107                         get {
108                                 return IsArrayImpl ();
109                         }
110                 }
111
112                 public bool IsAutoClass {
113                         get {
114                                 return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.AutoClass;
115                         }
116                 }
117
118                 public bool IsAutoLayout {
119                         get {
120                                 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.AutoLayout;
121                         }
122                 }
123
124                 public bool IsByRef {
125                         get {
126                                 return IsByRefImpl ();
127                         }
128                 }
129
130                 public bool IsClass {
131                         get {
132                                 if (IsInterface)
133                                         return false;
134
135                                 return !IsValueType;
136                         }
137                 }
138
139                 public bool IsCOMObject {
140                         get {
141                                 return IsCOMObjectImpl ();
142                         }
143                 }
144
145                 public bool IsContextful {
146                         get {
147                                 return IsContextfulImpl ();
148                         }
149                 }
150
151                 public bool IsEnum {
152                         get {
153                                 return GetInfo ().is_enum;
154                         }
155                 }
156
157                 public bool IsExplicitLayout {
158                         get {
159                                 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExplicitLayout;
160                         }
161                 }
162
163                 public bool IsImport {
164                         get {
165                                 return (Attributes & TypeAttributes.Import) != 0;
166                         }
167                 }
168
169                 public bool IsInterface {
170                         get {
171                                 return (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
172                         }
173                 }
174
175                 public bool IsLayoutSequential {
176                         get {
177                                 return (Attributes & TypeAttributes.LayoutMask) == TypeAttributes.SequentialLayout;
178                         }
179                 }
180
181                 public bool IsMarshalByRef {
182                         get {
183                                 return IsMarshalByRefImpl ();
184                         }
185                 }
186
187                 public bool IsNestedAssembly {
188                         get {
189                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedAssembly;
190                         }
191                 }
192
193                 public bool IsNestedFamANDAssem {
194                         get {
195                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamANDAssem;
196                         }
197                 }
198
199                 public bool IsNestedFamily {
200                         get {
201                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily;
202                         }
203                 }
204
205                 public bool IsNestedFamORAssem {
206                         get {
207                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem;
208                         }
209                 }
210
211                 public bool IsNestedPrivate {
212                         get {
213                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate;
214                         }
215                 }
216
217                 public bool IsNestedPublic {
218                         get {
219                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic;
220                         }
221                 }
222
223                 public bool IsNotPublic {
224                         get {
225                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic;
226                         }
227                 }
228
229                 public bool IsPointer {
230                         get {
231                                 return IsPointerImpl ();
232                         }
233                 }
234
235                 public bool IsPrimitive {
236                         get {
237                                 return IsPrimitiveImpl ();
238                         }
239                 }
240
241                 public bool IsPublic {
242                         get {
243                                 return (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public;
244                         }
245                 }
246
247                 public bool IsSealed {
248                         get {
249                                 return (Attributes & TypeAttributes.Sealed) != 0;
250                         }
251                 }
252
253                 public bool IsSerializable {
254                         get {
255                                 if ((Attributes & TypeAttributes.Serializable) != 0)
256                                         return true;
257
258                                 // FIXME:
259                                 return false;
260                         }
261                 }
262
263                 public bool IsSpecialName {
264                         get {
265                                 return (Attributes & TypeAttributes.SpecialName) != 0;
266                         }
267                 }
268
269                 public bool IsUnicodeClass {
270                         get {
271                                 return (Attributes & TypeAttributes.StringFormatMask) == TypeAttributes.UnicodeClass;
272                         }
273                 }
274
275                 public bool IsValueType {
276                         get {
277                                 return IsValueTypeImpl ();
278                         }
279                 }
280
281                 public bool HasElementType {
282                         get {
283                                 return HasElementTypeImpl ();
284                         }
285                 }
286
287                 public TypeMirror GetElementType () {
288                         GetInfo ();
289                         if (element_type == null && info.element_type != 0)
290                                 element_type = vm.GetType (info.element_type);
291                         return element_type;
292                 }
293
294                 public string FullName {
295                         get {
296                                 return GetInfo ().full_name;
297                         }
298                 }
299
300                 public string CSharpName {
301                         get {
302                                 if (IsArray) {
303                                         if (GetArrayRank () == 1)
304                                                 return GetElementType ().CSharpName + "[]";
305                                         else {
306                                                 string ranks = "";
307                                                 for (int i = 0; i < GetArrayRank (); ++i)
308                                                         ranks += ',';
309                                                 return GetElementType ().CSharpName + "[" + ranks + "]";
310                                         }
311                                 }
312                                 if (IsPrimitive) {
313                                         switch (Name) {
314                                         case "Byte":
315                                                 return "byte";
316                                         case "Int32":
317                                                 return "int";
318                                         case "Boolean":
319                                                 return "bool";
320                                         default:
321                                                 return FullName;
322                                         }
323                                 }
324                                 // FIXME: Only do this for real corlib types
325                                 if (Namespace == "System") {
326                                         string s = Name;
327                                         switch (s) {
328                                         case "String":
329                                                 return "string";
330                                         default:
331                                                 return FullName;
332                                         }
333                                 } else {
334                                         return FullName;
335                                 }
336                         }
337                 }
338
339                 public MethodMirror[] GetMethods () {
340                         if (methods == null) {
341                                 long[] ids = vm.conn.Type_GetMethods (id);
342                                 MethodMirror[] m = new MethodMirror [ids.Length];
343                                 for (int i = 0; i < ids.Length; ++i) {
344                                         m [i] = vm.GetMethod (ids [i]);
345                                 }
346                                 methods = m;
347                         }
348                         return methods;
349                 }
350
351                 // FIXME: Sync this with Type
352                 public MethodMirror GetMethod (string name) {
353                         foreach (var m in GetMethods ())
354                                 if (m.Name == name)
355                                         return m;
356                         return null;
357                 }
358
359                 public FieldInfoMirror[] GetFields () {
360                         if (fields != null)
361                                 return fields;
362
363                         string[] names;
364                         long[] types;
365                         int[] attrs;
366                         long[] ids = vm.conn.Type_GetFields (id, out names, out types, out attrs);
367
368                         FieldInfoMirror[] res = new FieldInfoMirror [ids.Length];
369                         for (int i = 0; i < res.Length; ++i)
370                                 res [i] = new FieldInfoMirror (this, ids [i], names [i], vm.GetType (types [i]), (FieldAttributes)attrs [i]);
371
372                         fields = res;
373                         return fields;
374                 }
375
376                 public FieldInfoMirror GetField (string name) {
377                         if (name == null)
378                                 throw new ArgumentNullException ("name");
379                         foreach (var f in GetFields ())
380                                 if (f.Name == name)
381                                         return f;
382                         return null;
383                 }
384
385                 public TypeMirror[] GetNestedTypes ()
386                 {
387                         return GetNestedTypes (DefaultBindingFlags);
388                 }
389
390                 public TypeMirror[] GetNestedTypes (BindingFlags bindingAttr) {
391                         if (nested != null)
392                                 return nested;
393
394                         // FIXME: bindingAttr
395                         GetInfo ();
396                         var arr = new TypeMirror [info.nested.Length];
397                         for (int i = 0; i < arr.Length; ++i)
398                                 arr [i] = vm.GetType (info.nested [i]);
399                         nested = arr;
400
401                         return nested;
402                 }
403
404                 public PropertyInfoMirror[] GetProperties () {
405                         return GetProperties (DefaultBindingFlags);
406                 }
407
408                 public PropertyInfoMirror[] GetProperties (BindingFlags bindingAttr) {
409                         if (properties != null)
410                                 return properties;
411
412                         PropInfo[] info = vm.conn.Type_GetProperties (id);
413
414                         PropertyInfoMirror[] res = new PropertyInfoMirror [info.Length];
415                         for (int i = 0; i < res.Length; ++i)
416                                 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);
417
418                         properties = res;
419                         return properties;
420                 }
421
422                 public PropertyInfoMirror GetProperty (string name) {
423                         if (name == null)
424                                 throw new ArgumentNullException ("name");
425                         foreach (var p in GetProperties ())
426                                 if (p.Name == name)
427                                         return p;
428                         return null;
429                 }
430
431                 public virtual bool IsAssignableFrom (TypeMirror c) {
432                         if (c == null)
433                                 throw new ArgumentNullException ("c");
434
435                         CheckMirror (c);
436
437                         // This is complex so do it in the debuggee
438                         return vm.conn.Type_IsAssignableFrom (id, c.Id);
439                 }
440
441                 public Value GetValue (FieldInfoMirror field) {
442                         return GetValues (new FieldInfoMirror [] { field }) [0];
443                 }
444
445                 public Value[] GetValues (IList<FieldInfoMirror> fields) {
446                         if (fields == null)
447                                 throw new ArgumentNullException ("fields");
448                         foreach (FieldInfoMirror f in fields) {
449                                 if (f == null)
450                                         throw new ArgumentNullException ("field");
451                                 CheckMirror (f);
452                         }
453                         long[] ids = new long [fields.Count];
454                         for (int i = 0; i < fields.Count; ++i)
455                                 ids [i] = fields [i].Id;
456                         try {
457                                 return vm.DecodeValues (vm.conn.Type_GetValues (id, ids));
458                         } catch (CommandException ex) {
459                                 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
460                                         throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
461                                 else
462                                         throw;
463                         }
464                 }
465
466                 public void SetValues (IList<FieldInfoMirror> fields, Value[] values) {
467                         if (fields == null)
468                                 throw new ArgumentNullException ("fields");
469                         if (values == null)
470                                 throw new ArgumentNullException ("values");
471                         foreach (FieldInfoMirror f in fields) {
472                                 if (f == null)
473                                         throw new ArgumentNullException ("field");
474                                 CheckMirror (f);
475                         }
476                         foreach (Value v in values) {
477                                 if (v == null)
478                                         throw new ArgumentNullException ("values");
479                                 CheckMirror (v);
480                         }
481                         long[] ids = new long [fields.Count];
482                         for (int i = 0; i < fields.Count; ++i)
483                                 ids [i] = fields [i].Id;
484                         try {
485                                 vm.conn.Type_SetValues (id, ids, vm.EncodeValues (values));
486                         } catch (CommandException ex) {
487                                 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
488                                         throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
489                                 else
490                                         throw;
491                         }
492                 }
493
494                 public void SetValue (FieldInfoMirror field, Value value) {
495                         SetValues (new FieldInfoMirror [] { field }, new Value [] { value });
496                 }
497
498                 public ObjectMirror GetTypeObject () {
499                         return vm.GetObject (vm.conn.Type_GetObject (id));
500                 }
501
502                 /*
503                  * Return a list of source files without path info, where methods of 
504                  * this type are defined. Return an empty list if the information is not 
505                  * available. 
506                  * This can be used by a debugger to find out which types occur in a 
507                  * given source file, to filter the list of methods whose locations
508                  * have to be checked when placing breakpoints.
509                  */
510                 public string[] GetSourceFiles () {
511                         return GetSourceFiles (false);
512                 }
513
514                 public string[] GetSourceFiles (bool return_full_paths) {
515                         return vm.conn.Type_GetSourceFiles (id, return_full_paths);
516                 }
517
518                 public C.TypeDefinition Metadata {
519                         get {
520                                 if (meta == null) {
521                                         if (Assembly.Metadata == null || MetadataToken == 0)
522                                                 return null;
523                                         meta = (C.TypeDefinition)Assembly.Metadata.MainModule.LookupToken (MetadataToken);
524                                 }
525                                 return meta;
526                         }
527                 }
528
529                 TypeInfo GetInfo () {
530                         if (info == null)
531                                 info = vm.conn.Type_GetInfo (id);
532                         return info;
533                 }
534
535                 protected virtual TypeAttributes GetAttributeFlagsImpl () {
536                         return (TypeAttributes)GetInfo ().attributes;
537                 }
538
539                 protected virtual bool HasElementTypeImpl () {
540                         return IsArray || IsByRef || IsPointer;
541                 }
542
543                 protected virtual bool IsArrayImpl () {
544                         return GetInfo ().rank > 0;
545                 }
546
547                 protected virtual bool IsByRefImpl () {
548                         return GetInfo ().is_byref;
549                 }
550
551                 protected virtual bool IsCOMObjectImpl () {
552                         return false;
553                 }
554
555                 protected virtual bool IsPointerImpl () {
556                         return GetInfo ().is_pointer;
557                 }
558
559                 protected virtual bool IsPrimitiveImpl () {
560                         return GetInfo ().is_primitive;
561                 }
562
563                 protected virtual bool IsValueTypeImpl ()
564                 {
565                         return GetInfo ().is_valuetype;
566                 }
567                 
568                 protected virtual bool IsContextfulImpl ()
569                 {
570                         // FIXME:
571                         return false;
572                 }
573
574                 protected virtual bool IsMarshalByRefImpl ()
575                 {
576                         // FIXME:
577                         return false;
578                 }
579
580                 // Same as Enum.GetUnderlyingType ()
581                 public TypeMirror EnumUnderlyingType {
582                         get {
583                                 if (!IsEnum)
584                                         throw new ArgumentException ("Type is not an enum type.");
585                                 foreach (FieldInfoMirror f in GetFields ()) {
586                                         if (!f.IsStatic)
587                                                 return f.FieldType;
588                                 }
589                                 throw new NotImplementedException ();
590                         }
591                 }
592
593                 /*
594                  * Creating the custom attributes themselves could modify the behavior of the
595                  * debuggee, so we return objects similar to the CustomAttributeData objects
596                  * used by the reflection-only functionality on .net.
597                  */
598                 public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
599                         return GetCAttrs (null, inherit);
600                 }
601
602                 public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
603                         if (attributeType == null)
604                                 throw new ArgumentNullException ("attributeType");
605                         return GetCAttrs (attributeType, inherit);
606                 }
607
608                 CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
609                         // FIXME: Handle inherit
610                         if (cattrs == null) {
611                                 CattrInfo[] info = vm.conn.Type_GetCustomAttributes (id, 0, false);
612                                 cattrs = CustomAttributeDataMirror.Create (vm, info);
613                         }
614                         var res = new List<CustomAttributeDataMirror> ();
615                         foreach (var attr in cattrs)
616                                 if (type == null || attr.Constructor.DeclaringType == type)
617                                         res.Add (attr);
618                         return res.ToArray ();
619                 }
620
621                 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
622                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
623                 }
624
625                 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
626                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
627                 }
628
629                 [Obsolete ("Use the overload without the 'vm' argument")]
630                 public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
631                         return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
632                 }
633
634                 public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
635                         return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
636                 }
637
638                 public Value EndInvokeMethod (IAsyncResult asyncResult) {
639                         return ObjectMirror.EndInvokeMethodInternal (asyncResult);
640                 }
641
642                 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
643                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
644                 }                       
645
646                 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
647                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
648                 }                       
649     }
650 }