2003-07-16 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / mbas / pending.cs
index 68b0cf8c7a27c7d57ee79b05bf2a5d1642a979e8..cd453dd4ce11d71adca05169b6d67b5d403c4631 100644 (file)
@@ -30,6 +30,11 @@ namespace Mono.CSharp {
                // because it was private, we could not use the match
                //
                public bool []       found;
+
+               // If a method is defined here, then we always need to
+               // create a proxy for it.  This is used when implementing
+               // an interface's indexer with a different IndexerName.
+               public MethodInfo [] need_proxy;
        }
 
        public class PendingImplementation {
@@ -78,7 +83,7 @@ namespace Mono.CSharp {
                        Type current_type = t;
                        
                        do {
-                               MemberInfo [] mi;
+                               MemberList mi;
                                
                                mi = TypeContainer.FindMembers (
                                        current_type, MemberTypes.Method,
@@ -94,14 +99,10 @@ namespace Mono.CSharp {
                                                searching = false;
                                }
 
-                               if (mi == null)
-                                       continue;
-
-                               int count = mi.Length;
-                               if (count == 0)
+                               if (mi.Count == 0)
                                        continue;
 
-                               if (count == 1 && !(mi [0] is MethodBase))
+                               if (mi.Count == 1 && !(mi [0] is MethodBase))
                                        searching = false;
                                else 
                                        list = TypeManager.CopyNewMethods (list, mi);
@@ -138,7 +139,7 @@ namespace Mono.CSharp {
 
                                                iface = TypeManager.LookupInterface (t);
                                                
-                                               mi = iface.GetMethods ();
+                                               mi = iface.GetMethods (container);
                                        } else
                                                mi = t.GetMethods ();
 
@@ -147,6 +148,7 @@ namespace Mono.CSharp {
                                        pending_implementations [i].methods = mi;
                                        pending_implementations [i].args = new Type [count][];
                                        pending_implementations [i].found = new bool [count];
+                                       pending_implementations [i].need_proxy = new MethodInfo [count];
 
                                        int j = 0;
                                        foreach (MethodInfo m in mi){
@@ -162,6 +164,7 @@ namespace Mono.CSharp {
                        if (abstract_methods != null){
                                int count = abstract_methods.Count;
                                pending_implementations [i].methods = new MethodInfo [count];
+                               pending_implementations [i].need_proxy = new MethodInfo [count];
                                
                                abstract_methods.CopyTo (pending_implementations [i].methods, 0);
                                pending_implementations [i].found = new bool [count];
@@ -203,6 +206,7 @@ namespace Mono.CSharp {
                        // TypeBuilder.
                        //
                        ifaces = type_builder.GetInterfaces ();
+
 #if DEBUG
                        {
                                Type x = type_builder;
@@ -253,18 +257,30 @@ namespace Mono.CSharp {
                        //
                        Lookup, ClearOne, ClearAll
                }
-               
+
                /// <summary>
                ///   Whether the specified method is an interface method implementation
                /// </summary>
                public MethodInfo IsInterfaceMethod (Type t, string name, Type ret_type, Type [] args)
                {
-                       return InterfaceMethod (t, name, ret_type, args, Operation.Lookup);
+                       return InterfaceMethod (t, name, ret_type, args, Operation.Lookup, null);
+               }
+
+               public MethodInfo IsInterfaceIndexer (Type t, Type ret_type, Type [] args)
+               {
+                       return InterfaceMethod (t, null, ret_type, args, Operation.Lookup, null);
                }
 
                public void ImplementMethod (Type t, string name, Type ret_type, Type [] args, bool clear_one) 
                {
-                       InterfaceMethod (t, name, ret_type, args, clear_one ? Operation.ClearOne : Operation.ClearAll);
+                       InterfaceMethod (t, name, ret_type, args,
+                                        clear_one ? Operation.ClearOne : Operation.ClearAll, null);
+               }
+
+               public void ImplementIndexer (Type t, MethodInfo mi, Type ret_type, Type [] args, bool clear_one) 
+               {
+                       InterfaceMethod (t, mi.Name, ret_type, args,
+                                        clear_one ? Operation.ClearOne : Operation.ClearAll, mi);
                }
                
                /// <remarks>
@@ -273,10 +289,19 @@ namespace Mono.CSharp {
                ///   arguments `args' implements an interface, this method will
                ///   return the MethodInfo that this method implements.
                ///
+               ///   If `name' is null, we operate solely on the method's signature.  This is for
+               ///   instance used when implementing indexers.
+               ///
                ///   The `Operation op' controls whether to lookup, clear the pending bit, or clear
                ///   all the methods with the given signature.
+               ///
+               ///   The `MethodInfo need_proxy' is used when we're implementing an interface's
+               ///   indexer in a class.  If the new indexer's IndexerName does not match the one
+               ///   that was used in the interface, then we always need to create a proxy for it.
+               ///
                /// </remarks>
-               public MethodInfo InterfaceMethod (Type t, string name, Type ret_type, Type [] args, Operation op)
+               public MethodInfo InterfaceMethod (Type t, string name, Type ret_type, Type [] args,
+                                                  Operation op, MethodInfo need_proxy)
                {
                        int arg_len = args.Length;
 
@@ -294,7 +319,12 @@ namespace Mono.CSharp {
                                                continue;
                                        }
 
-                                       if (name != m.Name){
+                                       // `need_proxy' is not null when we're implementing an
+                                       // interface indexer and this is Clear(One/All) operation.
+                                       // If `name' is null, then we do a match solely based on the
+                                       // signature and not on the name (this is done in the Lookup
+                                       // for an interface indexer).
+                                       if ((name != null) && (need_proxy == null) && (name != m.Name)){
                                                i++;
                                                continue;
                                        }
@@ -330,8 +360,18 @@ namespace Mono.CSharp {
                                                continue;
                                        }
 
-                                       if (op != Operation.Lookup)
-                                               tm.methods [i] = null;
+                                       if (op != Operation.Lookup){
+                                               // If `t != null', then this is an explicitly interface
+                                               // implementation and we can always clear the method.
+                                               // `need_proxy' is not null if we're implementing an
+                                               // interface indexer.  In this case, we need to create
+                                               // a proxy if the implementation's IndexerName doesn't
+                                               // match the IndexerName in the interface.
+                                               if ((t == null) && (need_proxy != null) && (name != m.Name))
+                                                       tm.need_proxy [i] = need_proxy;
+                                               else
+                                                       tm.methods [i] = null;
+                                       }
                                        tm.found [i] = true;
 
                                        //
@@ -394,6 +434,45 @@ namespace Mono.CSharp {
                        container.TypeBuilder.DefineMethodOverride (proxy, iface_method);
                }
                
+               static bool IsPropertyGetMethod (string m)
+               {
+                       return (m.Substring (0, 4) == "get_");  
+               }
+
+               static bool IsPropertySetMethod (string m)
+               {
+                       return (m.Substring (0, 4) == "set_");  
+               }
+
+               MethodInfo FindExplicitImplementation (string iface_name, string method_name)
+               {
+                       if (container.Properties != null) {
+                               foreach (Property p in container.Properties) 
+                               {
+                                       if (p.Implements != null) {                                     
+                                               if (IsPropertyGetMethod (method_name) && (container.Namespace.Name +  "." + p.Implements.ToString() == iface_name + "." + method_name.Substring(4))) 
+                                                               return p.PropertyBuilder.GetGetMethod(true);
+
+                                               if (IsPropertySetMethod (method_name) && (container.Namespace.Name +  "." + p.Implements.ToString() == iface_name + "." + method_name.Substring(4))) 
+                                                               return p.PropertyBuilder.GetSetMethod(true);
+                                       }
+                               }
+                       }
+
+                       if (container.Methods != null) 
+                       {
+                               foreach (Method m in container.Methods) 
+                               {
+                                       if (m.Implements != null) 
+                                       {                                       
+                                               if (container.Namespace.Name +  "." + m.Implements.ToString() == iface_name + "." + method_name)
+                                                       return (MethodInfo) m.MethodBuilder;
+                                       }
+                               }
+                       }
+                       return null;
+               }
+
                /// <summary>
                ///   This function tells whether one of our parent classes implements
                ///   the given method (which turns out, it is valid to have an interface
@@ -402,21 +481,29 @@ namespace Mono.CSharp {
                bool ParentImplements (Type iface_type, MethodInfo mi)
                {
                        MethodSignature ms;
+                       MethodInfo mr;
                        
                        Type [] args = TypeManager.GetArgumentTypes (mi);
+
                        ms = new MethodSignature (mi.Name, mi.ReturnType, args);
-                       MemberInfo [] list = TypeContainer.FindMembers (
+                       MemberList list = TypeContainer.FindMembers (
                                container.TypeBuilder.BaseType, MemberTypes.Method | MemberTypes.Property,
                                BindingFlags.Public | BindingFlags.Instance,
                                MethodSignature.method_signature_filter, ms);
 
-                       if (list == null || list.Length == 0)
-                               return false;
-                       
-                       DefineProxy (iface_type, (MethodInfo) list [0], mi, args);
-                       return true;
+                       if (list.Count == 0) 
+                       {
+                               mr = FindExplicitImplementation (iface_type.ToString(), mi.Name);
+                               if (mr == null)
+                                       return false;
+                       }
+                       else
+                               mr = (MethodInfo) list[0];
+
+                       DefineProxy (iface_type, mr, mi, args);
+                       return true;                                            
                }
-               
+
                /// <summary>
                ///   Verifies that any pending abstract methods or interface methods
                ///   were implemented.
@@ -436,9 +523,18 @@ namespace Mono.CSharp {
                                                continue;
 
                                        if (type.IsInterface){
+                                               MethodInfo need_proxy =
+                                                       pending_implementations [i].need_proxy [j];
+
+                                               if (need_proxy != null) {
+                                                       Type [] args = TypeManager.GetArgumentTypes (mi);
+                                                       DefineProxy (type, need_proxy, mi, args);
+                                                       continue;
+                                               }
+
                                                if (ParentImplements (type, mi))
                                                        continue;
+
                                                string extra = "";
                                                
                                                if (pending_implementations [i].found [j])