Beispiel #1
0
        public static CilInterfaceMethod FindMethod(List <CilInterfaceMethod> haystack,
                                                    CilInterfaceMethod needle)
        {
            int n = needle.Parameters.Count;

            foreach (var current in haystack)
            {
                if (current.PlainCompare(needle))
                {
                    return(current);
                }
            }
            return(null);
        }
Beispiel #2
0
        public static void BuildGenericProxy(CilInterfaceMethod ifcMethod, string methodSuffix,
                                             CilType intoType, List <CilInterfaceMethod> classMethods,
                                             JavaClass ifcClass)
        {
            CilMethod targetMethod = null;

            //Console.WriteLine("\n***** LOOKING FOR INTERFACE METHOD " + ifcMethod + " (SUFFIX " + methodSuffix + ") AKA " + ifcMethod.Method);

            foreach (var clsMethod in classMethods)
            {
                /*Console.WriteLine("> LOOKING AT "
                 + (clsMethod.Method.IsExplicitImpl ? "EXPLICIT " : "")
                 + "CLASS METHOD " + clsMethod + " AKA " + clsMethod.Method);*/

                if (ifcMethod.GenericCompare(clsMethod))
                {
                    if (clsMethod.Method.IsExplicitImpl)
                    {
                        // a matching explicit override method is the best match,
                        // and we can immediately stop searching
                        targetMethod = clsMethod.Method;
                        break;
                    }
                    else
                    {
                        // more than one method may match, if a derived type overrides
                        // or hides a method that also exists in a base type.  but the
                        // derived (primary) type methods always come first.
                        if (targetMethod == null)
                        {
                            targetMethod = clsMethod.Method;
                        }
                    }
                }
            }

            if (targetMethod == null)
            {
                throw CilMain.Where.Exception(
                          $"missing method '{ifcMethod.Method}' "
                          + $"(for interface '{ifcMethod.Method.DeclType}')");
            }

            // Console.WriteLine("INTERFACE METHOD " + ifcMethod.Method + " TARGET " + targetMethod);

            BuildGenericProxy2(ifcMethod, targetMethod, true, intoType, ifcClass);
        }
Beispiel #3
0
        public bool EqualGenericParameters(CilInterfaceMethod other)
        {
            if (!EqualGenericParameter(ReturnType, other.ReturnType))
            {
                return(false);
            }
            int n = Parameters.Count;

            if (other.Parameters.Count != n)
            {
                return(false);
            }
            for (int i = 0; i < n; i++)
            {
                if (!EqualGenericParameter(Parameters[i], other.Parameters[i]))
                {
                    return(false);
                }
            }
            return(true);
        }
Beispiel #4
0
        public bool EqualParameters(CilInterfaceMethod other)
        {
            if (!ReturnType.Equals(other.ReturnType))
            {
                return(false);
            }
            int n = Parameters.Count;

            if (other.Parameters.Count != n)
            {
                return(false);
            }
            for (int i = 0; i < n; i++)
            {
                if (!Parameters[i].Equals(other.Parameters[i]))
                {
                    return(false);
                }
            }
            return(true);
        }
Beispiel #5
0
        public static List <CilInterfaceMethod> CollectAll(TypeDefinition fromType)
        {
            var map = new Dictionary <string, List <CilInterfaceMethod> >();

            Process(fromType, map);

            var newList = new List <CilInterfaceMethod>();

            foreach (var oldList in map.Values)
            {
                newList.AddRange(oldList);
            }
            return(newList);

            void Process(TypeDefinition fromType, Dictionary <string, List <CilInterfaceMethod> > map)
            {
                foreach (var fromMethod in fromType.Methods)
                {
                    if ((fromMethod.IsPublic || fromMethod.HasOverrides) &&
                        !(fromMethod.IsStatic || fromMethod.IsConstructor))
                    {
                        if (fromType.IsInterface && fromMethod.HasBody)
                        {
                            // skip default interface methods, they are not needed
                            // in the context of resolving interface implementations
                            continue;
                        }

                        if (fromMethod.HasCustomAttribute("Discard"))
                        {
                            continue; // skip if decorated with [java.attr.Discard]
                        }
                        var genericMark = CilMain.GenericStack.Mark();
                        var inputMethod = CilMain.GenericStack.EnterMethod(fromMethod);

                        var outputMethod = new CilInterfaceMethod(inputMethod);

                        if (map.TryGetValue(inputMethod.Name, out var list))
                        {
                            bool dup = false;
                            foreach (var oldMethod in list)
                            {
                                if (oldMethod.EqualParameters(outputMethod))
                                {
                                    dup = true;
                                    break;
                                }
                            }
                            if (!dup)
                            {
                                list.Add(outputMethod);
                            }
                        }
                        else
                        {
                            var list2 = new List <CilInterfaceMethod>();
                            list2.Add(outputMethod);
                            map.Add(inputMethod.Name, list2);
                        }

                        CilMain.GenericStack.Release(genericMark);
                    }
                }

                var fromBaseTypeRef = fromType.BaseType;

                if (fromBaseTypeRef != null && !fromType.IsInterface)
                {
                    var fromBaseTypeDef = CilType.AsDefinition(fromBaseTypeRef);

                    var genericMark = CilMain.GenericStack.Mark();
                    CilMain.GenericStack.EnterType(fromBaseTypeDef);

                    Process(fromBaseTypeDef, map);

                    CilMain.GenericStack.Release(genericMark);
                }
            }
        }
Beispiel #6
0
 public bool GenericCompare(CilInterfaceMethod other)
 => SimpleName == other.SimpleName && EqualGenericParameters(other);
Beispiel #7
0
 public bool PlainCompare(CilInterfaceMethod other)
 => SimpleName == other.SimpleName && EqualParameters(other);
Beispiel #8
0
        public static List <CilInterface> CollectAll(TypeDefinition fromType)
        {
            var list = new List <CilInterface>();

            if (fromType.HasInterfaces)
            {
                Process(fromType, list, true, false);
            }
            return(list);

            void Process(TypeDefinition fromType, List <CilInterface> list,
                         bool directReference, bool markSuperImplements)
            {
                if (fromType.HasInterfaces)
                {
                    foreach (var ifcIterator in fromType.Interfaces)
                    {
                        var fromInterfaceRef = ifcIterator.InterfaceType;
                        var fromInterfaceDef = CilType.AsDefinition(fromInterfaceRef);

                        var genericMark   = CilMain.GenericStack.Mark();
                        var interfaceType = CilMain.GenericStack.EnterType(fromInterfaceRef);

                        var myInterface = interfaceType.HasGenericParameters
                                        ? ImportGenericInterface(interfaceType, list)
                                        : ImportPlainInterface(interfaceType, list);

                        if (!myInterface.Inserted)
                        {
                            // interface not inserted yet, which means it was just created

                            myInterface.Methods = CilInterfaceMethod.CollectAll(fromInterfaceDef);
                            myInterface.LoadType(fromInterfaceRef);
                            myInterface.DirectReference = directReference;
                            myInterface.SuperImplements = markSuperImplements;
                            myInterface.Inserted        = true;

                            list.Add(myInterface);

                            Process(fromInterfaceDef, list, false, markSuperImplements);
                        }
                        else if (markSuperImplements)
                        {
                            // an interface that was found for the initial type,
                            // was also found in a base type, mark it so

                            myInterface.SuperImplements = true;
                        }

                        CilMain.GenericStack.Release(genericMark);
                    }
                }

                //
                // scan base types to detect interfaces implemented there
                //

                var fromBaseTypeRef = fromType.BaseType;

                if (fromBaseTypeRef != null && !fromType.IsInterface)
                {
                    var fromBaseTypeDef = CilType.AsDefinition(fromBaseTypeRef);

                    var genericMark = CilMain.GenericStack.Mark();
                    CilMain.GenericStack.EnterType(fromBaseTypeDef);

                    Process(fromBaseTypeDef, list, false, true);

                    CilMain.GenericStack.Release(genericMark);
                }
            }
        }
Beispiel #9
0
        public static List <CilInterfaceMethod> CollectAll(TypeDefinition fromType)
        {
            var list = new List <CilInterfaceMethod>();

            Process(fromType, list);
            return(list);

            void Process(TypeDefinition fromType, List <CilInterfaceMethod> list)
            {
                foreach (var fromMethod in fromType.Methods)
                {
                    if ((fromMethod.IsPublic || fromMethod.HasOverrides) &&
                        !(fromMethod.IsStatic || fromMethod.IsConstructor))
                    {
                        if (fromType.IsInterface && fromMethod.HasBody)
                        {
                            // skip default interface methods, they are not needed
                            // in the context of resolving interface implementations
                            continue;
                        }

                        var genericMark = CilMain.GenericStack.Mark();
                        var inputMethod = CilMain.GenericStack.EnterMethod(fromMethod);

                        var outputMethod = new CilInterfaceMethod(inputMethod);

                        bool dup = false;
                        foreach (var oldMethod in list)
                        {
                            if (oldMethod.Method.Name == outputMethod.Method.Name &&
                                oldMethod.EqualParameters(outputMethod))
                            {
                                dup = true;
                                break;
                            }
                        }

                        if (!dup)
                        {
                            list.Add(outputMethod);
                        }

                        CilMain.GenericStack.Release(genericMark);
                    }
                }

                var fromBaseTypeRef = fromType.BaseType;

                if (fromBaseTypeRef != null && !fromType.IsInterface)
                {
                    var fromBaseTypeDef = CilType.AsDefinition(fromBaseTypeRef);

                    var genericMark = CilMain.GenericStack.Mark();
                    CilMain.GenericStack.EnterType(fromBaseTypeDef);

                    Process(fromBaseTypeDef, list);

                    CilMain.GenericStack.Release(genericMark);
                }
            }
        }
Beispiel #10
0
        public static void BuildOverloadProxy(TypeDefinition fromType, MethodDefinition fromMethod,
                                              CilMethod targetMethod, JavaClass intoClass)
        {
            // create a proxy bridge to forward invocations of a virtual method from
            // the base class, to an implementation in a derived class.  this is needed
            // where the base virtual method has generic parameters or return type,
            // for example:  virtual T SomeMethod(T arg)   will be translated as:
            //      java.lang.Object SomeMethod(-generic-$)(java.lang.Object arg)
            // and in a derived class that specializes T as String:
            //      java.lang.String SomeMethod(java.lang.String arg)
            // so the derived class must also include a proxy bridge method with the
            // same name as in the base class, and forward the call.

            //Console.WriteLine($"CHECK OVERRIDE {fromMethod}");
            int targetMethodCount = targetMethod.Parameters.Count;

            for (;;)
            {
                var baseType = fromType.BaseType;
                if (baseType == null)
                {
                    break;
                }
                fromType = CilType.AsDefinition(baseType);
                if (!baseType.IsGenericInstance)
                {
                    continue;
                }

                foreach (var fromMethod2 in fromType.Methods)
                {
                    //Console.WriteLine($"\tCOMPARE {fromMethod2} {fromMethod2.IsVirtual} {fromMethod2.Name == fromMethod.Name} {targetMethodCount == fromMethod2.Parameters.Count}");
                    if (fromMethod2.IsVirtual && fromMethod2.Name == fromMethod.Name &&
                        targetMethodCount == fromMethod2.Parameters.Count)
                    {
                        if (CilMethod.CompareMethods(fromMethod, fromMethod2))
                        {
                            //Console.WriteLine(">>>>>>>>>>>>> WARNING SAME: " + fromMethod.ToString() + " AND " + fromType);
                            continue;
                        }

                        var genericMark = CilMain.GenericStack.Mark();
                        CilMain.GenericStack.EnterType(baseType);
                        var baseMethod = new CilInterfaceMethod(
                            CilMain.GenericStack.EnterMethod(fromMethod2));
                        CilMain.GenericStack.Release(genericMark);

                        //Console.WriteLine($"\twould compare with {fromMethod2} in class {baseType}");
                        //Console.WriteLine($"\t\t{baseMethod}");

                        if (targetMethodCount != baseMethod.Parameters.Count)
                        {
                            continue;
                        }
                        if (!IsGenericOrEqual(targetMethod.ReturnType, baseMethod.ReturnType))
                        {
                            continue;
                        }
                        bool sameParameters = true;
                        for (int i = 0; i < targetMethodCount; i++)
                        {
                            if (!IsGenericOrEqual(targetMethod.Parameters[i].Type,
                                                  baseMethod.Parameters[i]))
                            {
                                bool equalsAfterUnboxing = (
                                    targetMethod.Parameters[i].Type is BoxedType boxedType &&
                                    boxedType.UnboxedType.Equals(baseMethod.Parameters[i]));

                                if (!equalsAfterUnboxing)
                                {
                                    //Console.WriteLine($"\tMISMATCH {targetMethod.Parameters[i].Type} vs {baseMethod.Parameters[i]}/{baseMethod.Parameters[i].IsGenericParameter}");
                                    sameParameters = false;
                                    break;
                                }
                            }
                        }
                        if (sameParameters)
                        {
                            //Console.WriteLine($"proxying {targetMethod} in class {targetMethod.DeclType}");
                            BuildGenericProxy2(baseMethod, targetMethod,
                                               false, targetMethod.DeclType, intoClass);
                            return;
                        }
                    }
                }
            }
Beispiel #11
0
        public static void BuildGenericProxy2(CilInterfaceMethod ifcMethod, CilMethod targetMethod,
                                              bool parentField, CilType intoType, JavaClass ifcClass)
        {
            //
            // create proxy method
            //

            var targetMethod2 = targetMethod.WithGenericParameters;
            var ifcMethod2    = ifcMethod.Method.WithGenericParameters;

            var newMethod = new JavaMethod(ifcClass, targetMethod2);

            newMethod.Name  = ifcMethod2.Name;
            newMethod.Flags = JavaAccessFlags.ACC_PUBLIC | JavaAccessFlags.ACC_BRIDGE;

            var code = newMethod.Code = new JavaCode();

            code.Method       = newMethod;
            code.Instructions = new List <JavaCode.Instruction>();

            //
            // push a reference to the parent object
            //

            code.NewInstruction(0x19 /* aload */, null, (int)0);
            if (parentField)
            {
                code.NewInstruction(0xB4 /* getfield */, new JavaType(0, 0, ifcClass.Name),
                                    new JavaFieldRef(ParentFieldName, intoType));
            }

            //
            // push all other parameters
            //

            int numArgs  = newMethod.Parameters.Count;
            int index    = 1;
            int maxStack = 1;

            for (int i = 0; i < numArgs; i++)
            {
                var ifcArg = ifcMethod2.Parameters[i].Type;
                code.NewInstruction(ifcArg.LoadOpcode, null, (int)index);
                index += ifcArg.Category;

                var clsArg = (CilType)targetMethod2.Parameters[i].Type;
                if (JavaType.ObjectType.Equals(ifcArg))
                {
                    if (!clsArg.IsReference)
                    {
                        var boxedArg = new BoxedType(clsArg, false);
                        code.NewInstruction(0xC0 /* checkcast */, boxedArg, null);
                        boxedArg.GetValue(code);
                    }
                    else if (!JavaType.ObjectType.Equals(clsArg))
                    {
                        code.NewInstruction(0xC0 /* checkcast */, clsArg, null);
                    }
                    // a parameter in the target method may be a concrete type,
                    // but if it is a generic java.lang.Object in the interface,
                    // then it must be a generic java.lang.Object in the proxy
                    newMethod.Parameters[i] = new JavaFieldRef("", ifcArg);
                }
                maxStack += clsArg.Category;
            }

            //
            // invoke proxy target method
            //

            code.NewInstruction(0xB6 /* invokevirtual */, intoType, targetMethod2);

            //
            // return value from method
            //

            var clsRet = (CilType)targetMethod2.ReturnType;
            var ifcRet = ifcMethod2.ReturnType;

            if (JavaType.ObjectType.Equals(ifcRet))
            {
                if (!clsRet.IsReference)
                {
                    var boxedArg = new BoxedType(clsRet, false);
                    boxedArg.BoxValue(code);
                }
                // the return value in the target method may be a concrete type,
                // but if it is a generic java.lang.Object in the interface,
                // then it must also be a generic java.lang.Object in the proxy
                newMethod.ReturnType = ifcRet;
                code.NewInstruction(ifcRet.ReturnOpcode, null, null);
            }
            else
            {
                code.NewInstruction(clsRet.ReturnOpcode, null, null);
            }

            code.MaxLocals = index;
            code.MaxStack  = maxStack;

            ifcClass.Methods.Add(newMethod);
        }
Beispiel #12
0
        public static JavaMethod BuildPlainProxy(CilInterfaceMethod ifcMethod, CilType intoType,
                                                 List <CilInterfaceMethod> classMethods)
        {
            CilMethod targetMethod = null;

            foreach (var clsMethod in classMethods)
            {
                if (clsMethod.Method.IsExplicitImpl)
                {
                    // no need for a proxy if we already have an override method,
                    // which has the same name as the proxy:  interface$method
                    if (ifcMethod.Method.Name == clsMethod.Method.Name)
                    {
                        return(null);
                    }
                }
                else if (ifcMethod.PlainCompare(clsMethod))
                {
                    // more than one method may match, if a derived type overrides
                    // or hides a method that also exists in a base type.  but the
                    // derived (primary) type methods always come first.
                    if (targetMethod == null)
                    {
                        targetMethod = clsMethod.Method;
                    }
                }
            }

            if (targetMethod == null)
            {
                throw CilMain.Where.Exception(
                          $"missing method '{ifcMethod.Method}' "
                          + $"(for interface '{ifcMethod.Method.DeclType}')");
            }

            if (targetMethod.IsRetainName)
            {
                // method retains is name, so it doesn't require a proxy bridge
                return(null);
            }

            //
            // create proxy method
            //

            var newMethod = new JavaMethod(null, targetMethod);

            newMethod.Name  = ifcMethod.Method.Name;
            newMethod.Flags = JavaAccessFlags.ACC_PUBLIC | JavaAccessFlags.ACC_BRIDGE;

            var code = newMethod.Code = new JavaCode();

            code.Method       = newMethod;
            code.Instructions = new List <JavaCode.Instruction>();

            //
            // push 'this' and all other parameters
            //

            code.NewInstruction(0x19 /* aload */, null, (int)0);
            int numArgs = newMethod.Parameters.Count;
            int index   = 1;

            for (int i = 0; i < numArgs; i++)
            {
                var arg = targetMethod.Parameters[i].Type;
                code.NewInstruction(arg.LoadOpcode, null, (int)index);
                index += arg.Category;
            }

            //
            // invoke proxy target method and return
            //

            code.NewInstruction(0xB6 /* invokevirtual */, intoType, targetMethod);
            code.NewInstruction(targetMethod.ReturnType.ReturnOpcode, null, null);

            code.MaxLocals = code.MaxStack = index;

            return(newMethod);
        }
Beispiel #13
0
        public static List <JavaClass> BuildProxyMethods(List <CilInterface> allInterfaces,
                                                         TypeDefinition fromType, CilType intoType,
                                                         JavaClass theClass)
        {
            //
            // process only if the class (or interface) has any methods or super interfaces
            //

            var classMethods = theClass.Methods;

            if (classMethods.Count == 0)
            {
                return(null);
            }

            bool isInterface = intoType.IsInterface;

            if ((!isInterface) && theClass.Interfaces == null)
            {
                return(null);
            }

            var theMethods = CilInterfaceMethod.CollectAll(fromType);

            //
            // if any interfaces are marked [RetainName], make sure that
            // all corresponding methods are also marked [RetainName]
            //

            CheckRetainNameMethods(theMethods, allInterfaces, intoType);

            //
            // if this is an abstract class but forced to an interface via [AddInterface]
            // decoration, then we need to remove all constructors generated for the class
            //

            if (intoType.IsInterface)
            {
                if (!fromType.IsInterface)
                {
                    for (int i = classMethods.Count; i-- > 0;)
                    {
                        if (classMethods[i].Name == "<init>")
                        {
                            classMethods.RemoveAt(i);
                        }
                    }
                }

                if (intoType.HasGenericParameters)
                {
                    // the RuntimeType constructor in baselib uses IGenericEntity
                    // marker interface to identify generic classes.  note that
                    // real generic types implement IGenericObject -> IGenericEntity.

                    theClass.AddInterface("system.IGenericEntity");
                }

                return(null);
            }

            //
            // for each implemented interface, build proxy methods
            //

            List <JavaClass> output = null;

            int ifcNumber = 0;

            foreach (var ifc in allInterfaces)
            {
                if ((!ifc.DirectReference) && ifc.SuperImplements)
                {
                    // we don't have to build proxy for an interface if it is
                    // implemented by a super type and not by our primary type
                    continue;
                }
                if (ifc.GenericTypes == null)
                {
                    foreach (var ifcMethod in ifc.Methods)
                    {
                        // build proxy methods:  interface$method -> method
                        var newMethod = BuildPlainProxy(ifcMethod, intoType, theMethods);
                        if (newMethod != null)
                        {
                            newMethod.Class = theClass;
                            theClass.Methods.Add(newMethod);
                        }
                    }
                }
                else
                {
                    var ifcClass = CreateInnerClass(theClass, intoType, ++ifcNumber);
                    ifcClass.AddInterface(ifc.InterfaceType.JavaName);

                    if (output == null)
                    {
                        output = new List <JavaClass>();
                        CreateInterfaceArrayField(theClass);
                    }
                    output.Add(ifcClass);

                    // if the class implements a generic interface for multiple types,
                    // then we need a method suffix to differentiate between the methods.
                    // see also:  CilMethod::InsertMethodNamePrefix
                    string methodSuffix = "";
                    foreach (var genericType in ifc.GenericTypes)
                    {
                        methodSuffix += "--" + CilMethod.GenericParameterSuffixName(genericType);
                    }

                    foreach (var ifcMethod in ifc.Methods)
                    {
                        // build proxy classes:  proxy sub-class -> this class
                        BuildGenericProxy(ifcMethod, methodSuffix, intoType, theMethods, ifcClass);
                    }
                }
            }

            return(output);

            JavaClass CreateInnerClass(JavaClass parentClass, CilType parentType, int ifcNumber)
            {
                // generic interfaces are implemented as proxy sub-classes which
                // call methods on the parent class object.  we need to define
                // an inner class.  this class has one instance field which is a
                // reference to the parent class.  the constructor takes this
                // reference as a parameter and initializes the instance field.

                var newClass = CilMain.CreateInnerClass(parentClass,
                                                        parentClass.Name + "$$generic" + ifcNumber.ToString());

                var fld = new JavaField();

                fld.Name  = ParentFieldName;
                fld.Type  = parentType;
                fld.Class = newClass;
                fld.Flags = JavaAccessFlags.ACC_PRIVATE;
                newClass.Fields.Add(fld);

                var code = CilMain.CreateHelperMethod(newClass,
                                                      new JavaMethodRef("<init>", JavaType.VoidType, JavaType.ObjectType),
                                                      2, 2);

                code.Method.Flags &= ~JavaAccessFlags.ACC_BRIDGE;   // invalid for constructor

                code.NewInstruction(0x19 /* aload */, null, (int)0);
                code.NewInstruction(0xB7 /* invokespecial */, JavaType.ObjectType,
                                    new JavaMethodRef("<init>", JavaType.VoidType));
                code.NewInstruction(0x19 /* aload */, null, (int)0);
                code.NewInstruction(0x19 /* aload */, null, (int)1);
                code.NewInstruction(0xC0 /* checkcast */, parentType, null);
                code.NewInstruction(0xB5 /* putfield */, new JavaType(0, 0, newClass.Name),
                                    new JavaFieldRef(ParentFieldName, parentType));
                code.NewInstruction(JavaType.VoidType.ReturnOpcode, null, null);

                return(newClass);
            }

            void CreateInterfaceArrayField(JavaClass parentClass)
            {
                // the parent class has a helper array field that is used to track
                // the proxy objects generated for implemented generic interfaces.
                // see also: InitInterfaceArrayField, below.

                var fld = new JavaField();

                fld.Name  = InterfaceArrayField.Name;
                fld.Type  = InterfaceArrayField.Type;
                fld.Class = parentClass;
                fld.Flags = JavaAccessFlags.ACC_PRIVATE;

                if (parentClass.Fields == null)
                {
                    parentClass.Fields = new List <JavaField>(1);
                }
                parentClass.Fields.Add(fld);
            }
        }
Beispiel #14
0
        //
        // if any interfaces are marked [RetainName], make sure that
        // all corresponding methods are also marked [RetainName]
        //

        static void CheckRetainNameMethods(List <CilInterfaceMethod> theMethods,
                                           List <CilInterface> theInterfaces,
                                           CilType checkedType)
        {
            List <CilInterface> retainNameInterfaces = null;

            foreach (var myInterface in theInterfaces)
            {
                if (myInterface.InterfaceType.IsRetainName)
                {
                    if (retainNameInterfaces == null)
                    {
                        retainNameInterfaces = new List <CilInterface>();
                    }
                    retainNameInterfaces.Add(myInterface);
                }
            }

            if (retainNameInterfaces == null)
            {
                return;
            }

            foreach (var myMethod in theMethods)
            {
                // if the method was not declared on the type itself, skip it.

                if (myMethod.Method.DeclType != checkedType)
                {
                    continue;
                }

                // methods may be marked with [RetainName] to avoid shadow renaming
                // (via CilMethod::MethodIsShadowing), as well as to match methods
                // from [RetainName] interfaces.  so if the method is marked so,
                // then we can just skip it.

                if (myMethod.Method.IsRetainName)
                {
                    continue;
                }

                // if the method is an explicit method implementation, then it cannot
                // implement a method from a [RetainName] interface (checked in
                // CilMethod::InsertMethodNamePrefix) and cannot be marked [RetainName]
                // (checked in CilMethod::SetMethodType).

                if (myMethod.Method.IsExplicitImpl)
                {
                    continue;
                }

                // if the method is not marked [RetainName], then make sure it is not
                // overriding an interface method marked [RetainName]

                var(foundInterface, foundMethod) =
                    FindMethod(retainNameInterfaces, myMethod);

                if (foundMethod != null)
                {
                    var interfaceName = foundInterface.InterfaceType.JavaName;

                    throw CilMain.Where.Exception(
                              $"method '{myMethod}' (for interface '{interfaceName}') "
                              + $"should be decorated with [java.attr.RetainName]");
                }
            }

            (CilInterface, CilInterfaceMethod) FindMethod(List <CilInterface> haystack,
                                                          CilInterfaceMethod needle)
            {
                foreach (var ifc in haystack)
                {
                    var mth = CilInterfaceMethod.FindMethod(ifc.Methods, needle);
                    if (mth != null)
                    {
                        return(ifc, mth);
                    }
                }
                return(null, null);
            }
        }
Beispiel #15
0
        public static void BuildGenericProxy(CilInterfaceMethod ifcMethod, /*string methodSuffix,*/
                                             CilType intoType, List <CilInterfaceMethod> classMethods,
                                             JavaClass ifcClass)
        {
            CilMethod targetMethod = null;

            //Console.WriteLine("\n***** LOOKING FOR INTERFACE METHOD " + ifcMethod + " (SUFFIX " + methodSuffix + ") AKA " + ifcMethod.Method);

            foreach (var clsMethod in classMethods)
            {
                /*Console.WriteLine("> LOOKING AT "
                 + (clsMethod.Method.IsExplicitImpl ? "EXPLICIT " : "")
                 + "CLASS METHOD " + clsMethod + " AKA " + clsMethod.Method);*/

                if (ifcMethod.GenericCompare(clsMethod))
                {
                    if (clsMethod.Method.IsExplicitImpl)
                    {
                        // a matching explicit override method is the best match,
                        // and we can immediately stop searching
                        targetMethod = clsMethod.Method;
                        break;
                    }
                    else
                    {
                        // more than one method may match, if a derived type overrides
                        // or hides a method that also exists in a base type.  but the
                        // derived (primary) type methods always come first
                        if (targetMethod == null)
                        {
                            targetMethod = clsMethod.Method;
                        }

                        // if a second method matches, and the set of generic types
                        // in its signature exactly matches the interface method we
                        // are looking for, then prefer this method.  when a class
                        // implements same-name methods from multiple interfaces,
                        // this is needed to pick the right method.
                        // see also ResolvedGenericTypes in CilInterfaceMethod.

                        else if (clsMethod.ResolvedGenericTypes.Length != 0 &&
                                 clsMethod.ResolvedGenericTypes
                                 == ifcMethod.ResolvedGenericTypes)
                        {
                            targetMethod = clsMethod.Method;
                        }
                    }
                }
            }

            if (targetMethod == null)
            {
                throw CilMain.Where.Exception(
                          $"missing method '{ifcMethod.Method}' "
                          + $"(for interface '{ifcMethod.Method.DeclType}')");
            }

            // Console.WriteLine("INTERFACE METHOD " + ifcMethod.Method + " TARGET " + targetMethod);

            BuildGenericProxy2(ifcMethod, targetMethod, true, intoType, ifcClass);
        }