Merge remote branch 'upstream/master'
[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, ThreadMirror thread) {
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, thread !=  null ? thread.Id : 0));
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 Value[] GetValues (IList<FieldInfoMirror> fields) {
467                         return GetValues (fields, null);
468                 }
469
470                 /*
471                  * Return the value of the [ThreadStatic] field FIELD on the thread THREAD.
472                  */
473                 public Value GetValue (FieldInfoMirror field, ThreadMirror thread) {
474                         if (thread == null)
475                                 throw new ArgumentNullException ("thread");
476                         CheckMirror (thread);
477                         return GetValues (new FieldInfoMirror [] { field }, thread) [0];
478                 }
479
480                 public void SetValues (IList<FieldInfoMirror> fields, Value[] values) {
481                         if (fields == null)
482                                 throw new ArgumentNullException ("fields");
483                         if (values == null)
484                                 throw new ArgumentNullException ("values");
485                         foreach (FieldInfoMirror f in fields) {
486                                 if (f == null)
487                                         throw new ArgumentNullException ("field");
488                                 CheckMirror (f);
489                         }
490                         foreach (Value v in values) {
491                                 if (v == null)
492                                         throw new ArgumentNullException ("values");
493                                 CheckMirror (v);
494                         }
495                         long[] ids = new long [fields.Count];
496                         for (int i = 0; i < fields.Count; ++i)
497                                 ids [i] = fields [i].Id;
498                         try {
499                                 vm.conn.Type_SetValues (id, ids, vm.EncodeValues (values));
500                         } catch (CommandException ex) {
501                                 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
502                                         throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
503                                 else
504                                         throw;
505                         }
506                 }
507
508                 public void SetValue (FieldInfoMirror field, Value value) {
509                         SetValues (new FieldInfoMirror [] { field }, new Value [] { value });
510                 }
511
512                 public ObjectMirror GetTypeObject () {
513                         return vm.GetObject (vm.conn.Type_GetObject (id));
514                 }
515
516                 /*
517                  * Return a list of source files without path info, where methods of 
518                  * this type are defined. Return an empty list if the information is not 
519                  * available. 
520                  * This can be used by a debugger to find out which types occur in a 
521                  * given source file, to filter the list of methods whose locations
522                  * have to be checked when placing breakpoints.
523                  */
524                 public string[] GetSourceFiles () {
525                         return GetSourceFiles (false);
526                 }
527
528                 public string[] GetSourceFiles (bool return_full_paths) {
529                         return vm.conn.Type_GetSourceFiles (id, return_full_paths);
530                 }
531
532                 public C.TypeDefinition Metadata {
533                         get {
534                                 if (meta == null) {
535                                         if (Assembly.Metadata == null || MetadataToken == 0)
536                                                 return null;
537                                         meta = (C.TypeDefinition)Assembly.Metadata.MainModule.LookupToken (MetadataToken);
538                                 }
539                                 return meta;
540                         }
541                 }
542
543                 TypeInfo GetInfo () {
544                         if (info == null)
545                                 info = vm.conn.Type_GetInfo (id);
546                         return info;
547                 }
548
549                 protected virtual TypeAttributes GetAttributeFlagsImpl () {
550                         return (TypeAttributes)GetInfo ().attributes;
551                 }
552
553                 protected virtual bool HasElementTypeImpl () {
554                         return IsArray || IsByRef || IsPointer;
555                 }
556
557                 protected virtual bool IsArrayImpl () {
558                         return GetInfo ().rank > 0;
559                 }
560
561                 protected virtual bool IsByRefImpl () {
562                         return GetInfo ().is_byref;
563                 }
564
565                 protected virtual bool IsCOMObjectImpl () {
566                         return false;
567                 }
568
569                 protected virtual bool IsPointerImpl () {
570                         return GetInfo ().is_pointer;
571                 }
572
573                 protected virtual bool IsPrimitiveImpl () {
574                         return GetInfo ().is_primitive;
575                 }
576
577                 protected virtual bool IsValueTypeImpl ()
578                 {
579                         return GetInfo ().is_valuetype;
580                 }
581                 
582                 protected virtual bool IsContextfulImpl ()
583                 {
584                         // FIXME:
585                         return false;
586                 }
587
588                 protected virtual bool IsMarshalByRefImpl ()
589                 {
590                         // FIXME:
591                         return false;
592                 }
593
594                 // Same as Enum.GetUnderlyingType ()
595                 public TypeMirror EnumUnderlyingType {
596                         get {
597                                 if (!IsEnum)
598                                         throw new ArgumentException ("Type is not an enum type.");
599                                 foreach (FieldInfoMirror f in GetFields ()) {
600                                         if (!f.IsStatic)
601                                                 return f.FieldType;
602                                 }
603                                 throw new NotImplementedException ();
604                         }
605                 }
606
607                 /*
608                  * Creating the custom attributes themselves could modify the behavior of the
609                  * debuggee, so we return objects similar to the CustomAttributeData objects
610                  * used by the reflection-only functionality on .net.
611                  */
612                 public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
613                         return GetCAttrs (null, inherit);
614                 }
615
616                 public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
617                         if (attributeType == null)
618                                 throw new ArgumentNullException ("attributeType");
619                         return GetCAttrs (attributeType, inherit);
620                 }
621
622                 CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
623                         // FIXME: Handle inherit
624                         if (cattrs == null) {
625                                 CattrInfo[] info = vm.conn.Type_GetCustomAttributes (id, 0, false);
626                                 cattrs = CustomAttributeDataMirror.Create (vm, info);
627                         }
628                         var res = new List<CustomAttributeDataMirror> ();
629                         foreach (var attr in cattrs)
630                                 if (type == null || attr.Constructor.DeclaringType == type)
631                                         res.Add (attr);
632                         return res.ToArray ();
633                 }
634
635                 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
636                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
637                 }
638
639                 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
640                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
641                 }
642
643                 [Obsolete ("Use the overload without the 'vm' argument")]
644                 public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
645                         return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
646                 }
647
648                 public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
649                         return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
650                 }
651
652                 public Value EndInvokeMethod (IAsyncResult asyncResult) {
653                         return ObjectMirror.EndInvokeMethodInternal (asyncResult);
654                 }
655
656                 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
657                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
658                 }                       
659
660                 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
661                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
662                 }                       
663     }
664 }