Merge branch 'BigIntegerParse'
[mono.git] / mcs / class / Mono.Debugger.Soft / Mono.Debugger.Soft / TypeMirror.cs
index 803783cbc60b2442c26d0f1e2033377ae7465ada..e7baa44fae09943942b1353621458bebe76374b9 100644 (file)
@@ -3,6 +3,9 @@ using System.Collections.Generic;
 using System.Reflection;
 using C = Mono.Cecil;
 using Mono.Cecil.Metadata;
+#if NET_4_5
+using System.Threading.Tasks;
+#endif
 
 namespace Mono.Debugger.Soft
 {
@@ -20,9 +23,14 @@ namespace Mono.Debugger.Soft
                FieldInfoMirror[] fields;
                PropertyInfoMirror[] properties;
                TypeInfo info;
-               TypeMirror base_type, element_type;
+               TypeMirror base_type, element_type, gtd;
                TypeMirror[] nested;
                CustomAttributeDataMirror[] cattrs;
+               TypeMirror[] ifaces;
+               Dictionary<TypeMirror, InterfaceMappingMirror> iface_map;
+               TypeMirror[] type_args;
+               bool cached_base_type;
+               bool inited;
 
                internal const BindingFlags DefaultBindingFlags =
                BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
@@ -34,13 +42,13 @@ namespace Mono.Debugger.Soft
                        get {
                                return GetInfo ().name;
                        }
-           }
+               }
 
                public string Namespace {
                        get {
                                return GetInfo ().ns;
                        }
-           }
+               }
 
                public AssemblyMirror Assembly {
                        get {
@@ -74,9 +82,9 @@ namespace Mono.Debugger.Soft
 
                public TypeMirror BaseType {
                        get {
-                               // FIXME: base_type could be null for object/interfaces
-                               if (base_type == null) {
+                               if (!cached_base_type) {
                                        base_type = vm.GetType (GetInfo ().base_type);
+                                       cached_base_type = true;
                                }
                                return base_type;
                        }
@@ -284,6 +292,25 @@ namespace Mono.Debugger.Soft
                        }
                }
 
+               // Since protocol version 2.12
+               public bool IsGenericTypeDefinition {
+                       get {
+                               vm.CheckProtocolVersion (2, 12);
+                               GetInfo ();
+                               return info.is_gtd;
+                       }
+               }
+
+               public bool IsGenericType {
+                       get {
+                               if (vm.Version.AtLeast (2, 12)) {
+                                       return GetInfo ().is_generic_type;
+                               } else {
+                                       return Name.IndexOf ('`') != -1;
+                               }
+                       }
+               }
+
                public TypeMirror GetElementType () {
                        GetInfo ();
                        if (element_type == null && info.element_type != 0)
@@ -291,6 +318,25 @@ namespace Mono.Debugger.Soft
                        return element_type;
                }
 
+               public TypeMirror GetGenericTypeDefinition () {
+                       vm.CheckProtocolVersion (2, 12);
+                       GetInfo ();
+                       if (gtd == null) {
+                               if (info.gtd == 0)
+                                       throw new InvalidOperationException ();
+                               gtd = vm.GetType (info.gtd);
+                       }
+                       return gtd;
+               }
+
+               // Since protocol version 2.15
+               public TypeMirror[] GetGenericArguments () {
+                       vm.CheckProtocolVersion (2, 15);
+                       if (type_args == null)
+                               type_args = vm.GetTypes (GetInfo ().type_args);
+                       return type_args;
+               }
+
                public string FullName {
                        get {
                                return GetInfo ().full_name;
@@ -313,8 +359,26 @@ namespace Mono.Debugger.Soft
                                        switch (Name) {
                                        case "Byte":
                                                return "byte";
+                                       case "Sbyte":
+                                               return "sbyte";
+                                       case "Char":
+                                               return "char";
+                                       case "UInt16":
+                                               return "ushort";
+                                       case "Int16":
+                                               return "short";
+                                       case "UInt32":
+                                               return "uint";
                                        case "Int32":
                                                return "int";
+                                       case "UInt64":
+                                               return "ulong";
+                                       case "Int64":
+                                               return "long";
+                                       case "Single":
+                                               return "float";
+                                       case "Double":
+                                               return "double";
                                        case "Boolean":
                                                return "bool";
                                        default:
@@ -325,6 +389,10 @@ namespace Mono.Debugger.Soft
                                if (Namespace == "System") {
                                        string s = Name;
                                        switch (s) {
+                                       case "Decimal":
+                                               return "decimal";
+                                       case "Object":
+                                               return "object";
                                        case "String":
                                                return "string";
                                        default:
@@ -527,11 +595,11 @@ namespace Mono.Debugger.Soft
 
                string[] source_files;
                string[] source_files_full_path;
-               public string[] GetSourceFiles (bool return_full_paths) {
-                       string[] res = return_full_paths ? source_files_full_path : source_files;
+               public string[] GetSourceFiles (bool returnFullPaths) {
+                       string[] res = returnFullPaths ? source_files_full_path : source_files;
                        if (res == null) {
-                               res = vm.conn.Type_GetSourceFiles (id, return_full_paths);
-                               if (return_full_paths)
+                               res = vm.conn.Type_GetSourceFiles (id, returnFullPaths);
+                               if (returnFullPaths)
                                        source_files_full_path = res;
                                else
                                        source_files = res;
@@ -620,29 +688,38 @@ namespace Mono.Debugger.Soft
                 * used by the reflection-only functionality on .net.
                 */
                public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
-                       return GetCAttrs (null, inherit);
+                       return GetCustomAttrs (null, inherit);
                }
 
                public CustomAttributeDataMirror[] GetCustomAttributes (TypeMirror attributeType, bool inherit) {
                        if (attributeType == null)
                                throw new ArgumentNullException ("attributeType");
-                       return GetCAttrs (attributeType, inherit);
+                       return GetCustomAttrs (attributeType, inherit);
                }
 
-               CustomAttributeDataMirror[] GetCAttrs (TypeMirror type, bool inherit) {
+               void AppendCustomAttrs (IList<CustomAttributeDataMirror> attrs, TypeMirror type, bool inherit)
+               {
                        if (cattrs == null && Metadata != null && !Metadata.HasCustomAttributes)
                                cattrs = new CustomAttributeDataMirror [0];
 
-                       // FIXME: Handle inherit
                        if (cattrs == null) {
                                CattrInfo[] info = vm.conn.Type_GetCustomAttributes (id, 0, false);
                                cattrs = CustomAttributeDataMirror.Create (vm, info);
                        }
-                       var res = new List<CustomAttributeDataMirror> ();
-                       foreach (var attr in cattrs)
+
+                       foreach (var attr in cattrs) {
                                if (type == null || attr.Constructor.DeclaringType == type)
-                                       res.Add (attr);
-                       return res.ToArray ();
+                                       attrs.Add (attr);
+                       }
+
+                       if (inherit && BaseType != null)
+                               BaseType.AppendCustomAttrs (attrs, type, inherit);
+               }
+
+               CustomAttributeDataMirror[] GetCustomAttrs (TypeMirror type, bool inherit) {
+                       var attrs = new List<CustomAttributeDataMirror> ();
+                       AppendCustomAttrs (attrs, type, inherit);
+                       return attrs.ToArray ();
                }
 
                public MethodMirror[] GetMethodsByNameFlags (string name, BindingFlags flags, bool ignoreCase) {
@@ -653,10 +730,46 @@ namespace Mono.Debugger.Soft
                                        m [i] = vm.GetMethod (ids [i]);
                                return m;
                        } else {
-                               if (flags != (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.NonPublic))
+                               if ((flags & BindingFlags.IgnoreCase) != 0) {
+                                       flags &= ~BindingFlags.IgnoreCase;
+                                       ignoreCase = true;
+                               }
+                               
+                               if (flags == BindingFlags.Default)
+                                       flags = BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static;
+                               
+                               MethodAttributes access = (MethodAttributes) 0;
+                               bool matchInstance = false;
+                               bool matchStatic = false;
+                               
+                               if ((flags & BindingFlags.NonPublic) != 0) {
+                                       access |= MethodAttributes.Private;
+                                       flags &= ~BindingFlags.NonPublic;
+                               }
+                               if ((flags & BindingFlags.Public) != 0) {
+                                       access |= MethodAttributes.Public;
+                                       flags &= ~BindingFlags.Public;
+                               }
+                               if ((flags & BindingFlags.Instance) != 0) {
+                                       flags &= ~BindingFlags.Instance;
+                                       matchInstance = true;
+                               }
+                               if ((flags & BindingFlags.Static) != 0) {
+                                       flags &= ~BindingFlags.Static;
+                                       matchStatic = true;
+                               }
+                               
+                               if ((int) flags != 0)
                                        throw new NotImplementedException ();
+                               
                                var res = new List<MethodMirror> ();
                                foreach (MethodMirror m in GetMethods ()) {
+                                       if ((m.Attributes & access) == (MethodAttributes) 0)
+                                               continue;
+                                       
+                                       if (!((matchStatic && m.IsStatic) || (matchInstance && !m.IsStatic)))
+                                               continue;
+                                       
                                        if ((!ignoreCase && m.Name == name) || (ignoreCase && m.Name.Equals (name, StringComparison.CurrentCultureIgnoreCase)))
                                                res.Add (m);
                                }
@@ -685,12 +798,91 @@ namespace Mono.Debugger.Soft
                        return ObjectMirror.EndInvokeMethodInternal (asyncResult);
                }
 
+#if NET_4_5
+               public Task<Value> InvokeMethodAsync (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options = InvokeOptions.None) {
+                       var tcs = new TaskCompletionSource<Value> ();
+                       BeginInvokeMethod (thread, method, arguments, options, iar =>
+                                       {
+                                               try {
+                                                       tcs.SetResult (EndInvokeMethod (iar));
+                                               } catch (OperationCanceledException) {
+                                                       tcs.TrySetCanceled ();
+                                               } catch (Exception ex) {
+                                                       tcs.TrySetException (ex);
+                                               }
+                                       }, null);
+                       return tcs.Task;
+               }
+#endif
+
                public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
                        return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, InvokeOptions.None);
                }                       
 
                public Value NewInstance (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
                        return ObjectMirror.InvokeMethod (vm, thread, method, null, arguments, options);
-               }                       
+               }
+
+               // Since protocol version 2.11
+               public TypeMirror[] GetInterfaces () {
+                       if (ifaces == null)
+                               ifaces = vm.GetTypes (vm.conn.Type_GetInterfaces (id));
+                       return ifaces;
+               }
+
+               // Since protocol version 2.11
+               public InterfaceMappingMirror GetInterfaceMap (TypeMirror interfaceType) {
+                       if (interfaceType == null)
+                               throw new ArgumentNullException ("interfaceType");
+                       if (!interfaceType.IsInterface)
+                               throw new ArgumentException ("Argument must be an interface.", "interfaceType");
+                       if (IsInterface)
+                               throw new ArgumentException ("'this' type cannot be an interface itself");
+
+                       if (iface_map == null) {
+                               // Query the info in bulk
+                               GetInterfaces ();
+                               var ids = new long [ifaces.Length];
+                               for (int i = 0; i < ifaces.Length; ++i)
+                                       ids [i] = ifaces [i].Id;
+
+                               var ifacemap = vm.conn.Type_GetInterfaceMap (id, ids);
+
+                               var imap = new Dictionary<TypeMirror, InterfaceMappingMirror> ();
+                               for (int i = 0; i < ifacemap.Length; ++i) {
+                                       IfaceMapInfo info = ifacemap [i];
+
+                                       MethodMirror[] imethods = new MethodMirror [info.iface_methods.Length];
+                                       for (int j = 0; j < info.iface_methods.Length; ++j)
+                                               imethods [j] = vm.GetMethod (info.iface_methods [j]);
+
+                                       MethodMirror[] tmethods = new MethodMirror [info.iface_methods.Length];
+                                       for (int j = 0; j < info.target_methods.Length; ++j)
+                                               tmethods [j] = vm.GetMethod (info.target_methods [j]);
+
+                                       InterfaceMappingMirror map = new InterfaceMappingMirror (vm, this, vm.GetType (info.iface_id), imethods, tmethods);
+
+                                       imap [map.InterfaceType] = map;
+                               }
+
+                               iface_map = imap;
+                       }
+
+                       InterfaceMappingMirror res;
+                       if (!iface_map.TryGetValue (interfaceType, out res))
+                               throw new ArgumentException ("Interface not found", "interfaceType");
+                       return res;
+               }
+
+               // Return whenever the type initializer of this type has ran
+               // Since protocol version 2.23
+               public bool IsInitialized {
+                       get {
+                               vm.CheckProtocolVersion (2, 23);
+                               if (!inited)
+                                       inited = vm.conn.Type_IsInitialized (id);
+                               return inited;
+                       }
+               }
     }
 }