Merge pull request #194 from QuickJack/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                 string[] source_files;
529                 string[] source_files_full_path;
530                 public string[] GetSourceFiles (bool return_full_paths) {
531                         string[] res = return_full_paths ? source_files_full_path : source_files;
532                         if (res == null) {
533                                 res = vm.conn.Type_GetSourceFiles (id, return_full_paths);
534                                 if (return_full_paths)
535                                         source_files_full_path = res;
536                                 else
537                                         source_files = res;
538                         }
539                         return res;
540                 }
541
542                 public C.TypeDefinition Metadata {
543                         get {
544                                 if (meta == null) {
545                                         if (Assembly.Metadata == null || MetadataToken == 0)
546                                                 return null;
547                                         meta = (C.TypeDefinition)Assembly.Metadata.MainModule.LookupToken (MetadataToken);
548                                 }
549                                 return meta;
550                         }
551                 }
552
553                 TypeInfo GetInfo () {
554                         if (info == null)
555                                 info = vm.conn.Type_GetInfo (id);
556                         return info;
557                 }
558
559                 protected virtual TypeAttributes GetAttributeFlagsImpl () {
560                         return (TypeAttributes)GetInfo ().attributes;
561                 }
562
563                 protected virtual bool HasElementTypeImpl () {
564                         return IsArray || IsByRef || IsPointer;
565                 }
566
567                 protected virtual bool IsArrayImpl () {
568                         return GetInfo ().rank > 0;
569                 }
570
571                 protected virtual bool IsByRefImpl () {
572                         return GetInfo ().is_byref;
573                 }
574
575                 protected virtual bool IsCOMObjectImpl () {
576                         return false;
577                 }
578
579                 protected virtual bool IsPointerImpl () {
580                         return GetInfo ().is_pointer;
581                 }
582
583                 protected virtual bool IsPrimitiveImpl () {
584                         return GetInfo ().is_primitive;
585                 }
586
587                 protected virtual bool IsValueTypeImpl ()
588                 {
589                         return GetInfo ().is_valuetype;
590                 }
591                 
592                 protected virtual bool IsContextfulImpl ()
593                 {
594                         // FIXME:
595                         return false;
596                 }
597
598                 protected virtual bool IsMarshalByRefImpl ()
599                 {
600                         // FIXME:
601                         return false;
602                 }
603
604                 // Same as Enum.GetUnderlyingType ()
605                 public TypeMirror EnumUnderlyingType {
606                         get {
607                                 if (!IsEnum)
608                                         throw new ArgumentException ("Type is not an enum type.");
609                                 foreach (FieldInfoMirror f in GetFields ()) {
610                                         if (!f.IsStatic)
611                                                 return f.FieldType;
612                                 }
613                                 throw new NotImplementedException ();
614                         }
615                 }
616
617                 /*
618                  * Creating the custom attributes themselves could modify the behavior of the
619                  * debuggee, so we return objects similar to the CustomAttributeData objects
620                  * used by the reflection-only functionality on .net.
621                  */
622                 public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
623                         return GetCAttrs (null, inherit);
624                 }
625
626                 public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
627                         if (attributeType == null)
628                                 throw new ArgumentNullException ("attributeType");
629                         return GetCAttrs (attributeType, inherit);
630                 }
631
632                 CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
633                         if (cattrs == null && Metadata != null && !Metadata.HasCustomAttributes)
634                                 cattrs = new CustomAttributeDataMirror [0];
635
636                         // FIXME: Handle inherit
637                         if (cattrs == null) {
638                                 CattrInfo[] info = vm.conn.Type_GetCustomAttributes (id, 0, false);
639                                 cattrs = CustomAttributeDataMirror.Create (vm, info);
640                         }
641                         var res = new List<CustomAttributeDataMirror> ();
642                         foreach (var attr in cattrs)
643                                 if (type == null || attr.Constructor.DeclaringType == type)
644                                         res.Add (attr);
645                         return res.ToArray ();
646                 }
647
648                 public MethodMirror[] GetMethodsByNameFlags (string name, BindingFlags flags, bool ignoreCase) {
649                         if (vm.conn.Version.AtLeast (2, 6)) {
650                                 long[] ids = vm.conn.Type_GetMethodsByNameFlags (id, name, (int)flags, ignoreCase);
651                                 MethodMirror[] m = new MethodMirror [ids.Length];
652                                 for (int i = 0; i < ids.Length; ++i)
653                                         m [i] = vm.GetMethod (ids [i]);
654                                 return m;
655                         } else {
656                                 if (flags != (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.NonPublic))
657                                         throw new NotImplementedException ();
658                                 var res = new List<MethodMirror> ();
659                                 foreach (MethodMirror m in GetMethods ()) {
660                                         if ((!ignoreCase && m.Name == name) || (ignoreCase && m.Name.Equals (name, StringComparison.CurrentCultureIgnoreCase)))
661                                                 res.Add (m);
662                                 }
663                                 return res.ToArray ();
664                         }
665                 }
666
667                 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
668                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
669                 }
670
671                 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
672                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
673                 }
674
675                 [Obsolete ("Use the overload without the 'vm' argument")]
676                 public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
677                         return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
678                 }
679
680                 public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
681                         return ObjectMirror.BeginInvokeMethod (vm, thread, method, null, arguments, options, callback, state);
682                 }
683
684                 public Value EndInvokeMethod (IAsyncResult asyncResult) {
685                         return ObjectMirror.EndInvokeMethodInternal (asyncResult);
686                 }
687
688                 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
689                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
690                 }                       
691
692                 public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
693                         return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
694                 }                       
695     }
696 }