Ejemplo n.º 1
0
        internal static void BuildJavaClass(TypeDefinition cilType, JavaClass parentClass)
        {
            CilMain.Where.Push($"class '{cilType.FullName}'");

            var genericMark = CilMain.GenericStack.Mark();
            var myType      = CilMain.GenericStack.EnterType(cilType);

            var jclass = new JavaClass();

            jclass.Name  = myType.JavaName;
            jclass.Flags = AttributesToAccessFlags(cilType.Attributes, myType.IsInterface);

            if (myType.IsInterface)
            {
                jclass.Super = JavaType.ObjectType.ClassName; // java.lang.Object
            }
            else if (cilType.BaseType != null)
            {
                var myBaseType = CilType.From(cilType.BaseType);
                jclass.Super = myBaseType.Equals(JavaType.ObjectType)
                             ? JavaType.ObjectType.ClassName // java.lang.Object
                             : myBaseType.JavaName;
            }
            else
            {
                throw CilMain.Where.Exception("missing base class");
            }

            var myInterfaces = ImportInterfaces(jclass, myType, cilType);

            int numCastableInterfaces = myType.IsGenericThisOrSuper
                                      ? InterfaceBuilder.CastableInterfaceCount(myInterfaces)
                                      : 0;

            ImportFields(jclass, cilType, myType.IsRetainName);

            ImportMethods(jclass, cilType, numCastableInterfaces);

            if (myType.JavaName == "system.Convert")
            {
                DiscardBase64MethodsInConvertClass(jclass);
            }

            ValueUtil.InitializeStaticFields(jclass, myType);

            if (myType.IsValueClass)
            {
                ValueUtil.MakeValueClass(jclass, myType, numCastableInterfaces);
            }

            else if (myType.IsEnum)
            {
                ValueUtil.MakeEnumClass(jclass, myType,
                                        cilType.HasCustomAttribute("System.FlagsAttribute", true));
            }

            else if (myType.IsDelegate)
            {
                var delegateInterface = Delegate.FixClass(jclass, myType);
                CilMain.JavaClasses.Add(delegateInterface);
            }

            // if derives directly from object, and does not implement ToString
            CodeBuilder.CreateToStringMethod(jclass);

            ResetFieldReferences(jclass);

            LinkClasses(jclass, parentClass, cilType);

            var interfaceClasses = InterfaceBuilder.BuildProxyMethods(
                myInterfaces, cilType, myType, jclass);

            if (interfaceClasses != null)
            {
                foreach (var childClass in interfaceClasses)
                {
                    CilMain.JavaClasses.Add(childClass);
                }
            }

            if (myType.HasGenericParameters)
            {
                JavaClass dataClass;

                if (!myType.IsInterface)
                {
                    dataClass = GenericUtil.MakeGenericClass(jclass, myType);
                    if (dataClass != null)
                    {
                        CilMain.JavaClasses.Add(dataClass);
                    }
                }
                else
                {
                    dataClass = null;
                }

                JavaClass infoClass = jclass;
                if (myType.IsInterface)
                {
                    // Android 'D8' desugars static methods on an interface by
                    // moving into a separate class, so we do it ourselves.
                    // see also system.RuntimeType.CreateGeneric() in baselib
                    infoClass = CilMain.CreateInnerClass(jclass, jclass.Name + "$$info");
                    CilMain.JavaClasses.Add(infoClass);
                }

                GenericUtil.CreateGenericInfoMethod(infoClass, dataClass, myType);

                GenericUtil.CreateGenericVarianceField(infoClass, myType, cilType);
            }

            if (myType.IsGenericThisOrSuper)
            {
                jclass.Signature = GenericUtil.MakeGenericSignature(cilType, jclass.Super);

                if (!myInterfaces.Exists(x => x.InterfaceType.JavaName == "system.IGenericObject"))
                {
                    if (!myType.IsInterface)
                    {
                        // create IGenericObject methods GetType and TryCast
                        // only if class did not already implement IGenericObject
                        if (!myType.HasGenericParameters)
                        {
                            GenericUtil.BuildGetTypeMethod(jclass, myType);
                        }

                        InterfaceBuilder.BuildTryCastMethod(
                            myInterfaces, myType, numCastableInterfaces, jclass);
                    }
                }
            }

            CilMain.GenericStack.Release(genericMark);
            CilMain.Where.Pop();
        }
Ejemplo n.º 2
0
        public static void ImportMethods(JavaClass jclass, TypeDefinition cilType,
                                         int numCastableInterfaces)
        {
            if (cilType.HasMethods)
            {
                int n = cilType.Methods.Count;
                if (n > 0)
                {
                    jclass.Methods = new List <JavaMethod>(n);
                    for (int i = 0; i < n; i++)
                    {
                        var defMethod = cilType.Methods[i];

                        /*
                         * if (defMethod.HasCustomAttribute("Discard"))
                         *  continue; // if decorated with [java.attr.Discard], don't export to java
                         */

                        var genericMark = CilMain.GenericStack.Mark();
                        var myMethod    = CilMain.GenericStack.EnterMethod(defMethod);

                        var newMethod = new JavaMethod(jclass, myMethod.WithGenericParameters);
                        newMethod.Flags = AttributesToAccessFlags(
                            defMethod.Attributes, defMethod.HasOverrides,
                            (cilType.HasNestedTypes || cilType.HasGenericParameters));

                        if (myMethod.IsStatic & myMethod.IsConstructor)
                        {
                            newMethod.Flags &= ~(JavaAccessFlags.ACC_PUBLIC
                                                 | JavaAccessFlags.ACC_PRIVATE
                                                 | JavaAccessFlags.ACC_PROTECTED);
                        }

                        if (defMethod.HasBody)
                        {
                            CilMain.Where.Push($"method '{defMethod.Name}'");
                            CodeBuilder.BuildJavaCode(newMethod, myMethod, defMethod,
                                                      numCastableInterfaces);

                            if ((defMethod.ImplAttributes & MethodImplAttributes.Synchronized) != 0)
                            {
                                // if method is decorated with [MethodImplOptions.Synchronized],
                                // create a wrapper method that locks appropriately
                                jclass.Methods.Add(
                                    CodeBuilder.CreateSyncWrapper(newMethod, myMethod.DeclType));
                            }
                            else if (defMethod.Name == "Finalize" &&
                                     (!defMethod.HasParameters) && defMethod.IsVirtual)
                            {
                                // if method is a finalizer, create a wrapper method that
                                // checks if finalization was suppressed for the object

                                CodeBuilder.CreateSuppressibleFinalize(
                                    newMethod, myMethod.DeclType, jclass);
                            }

                            if (defMethod.IsVirtual)
                            {
                                InterfaceBuilder.BuildOverloadProxy(
                                    cilType, defMethod, myMethod, jclass);
                            }
                            else if (!myMethod.IsConstructor)
                            {
                                newMethod.Flags |= JavaAccessFlags.ACC_FINAL;
                            }

                            CilMain.Where.Pop();
                        }
                        else
                        {
                            if ((!defMethod.IsAbstract) &&
                                (defMethod.IsInternalCall || defMethod.IsPInvokeImpl))
                            {
                                // skip native methods
                                continue;
                            }

                            // clear ACC_STATIC and access, set ACC_ABSTRACT and ACC_PUBLIC
                            newMethod.Flags = (newMethod.Flags | JavaAccessFlags.ACC_ABSTRACT
                                               | JavaAccessFlags.ACC_PUBLIC)
                                              & ~(JavaAccessFlags.ACC_STATIC
                                                  | JavaAccessFlags.ACC_PRIVATE
                                                  | JavaAccessFlags.ACC_PROTECTED);
                        }

                        jclass.Methods.Add(newMethod);

                        CilMain.GenericStack.Release(genericMark);

                        if (myMethod.IsConstructor)
                        {
                            var dummyClass = CreateDummyClassForConstructor(myMethod, jclass);
                            if (dummyClass != null)
                            {
                                CilMain.JavaClasses.Add(dummyClass);
                            }
                        }
                        else if (myMethod.WithGenericParameters != myMethod &&
                                 (!myMethod.IsRetainName))
                        {
                            jclass.Methods.Add(
                                Delegate.CreateCapturingBridgeMethod(
                                    newMethod, myMethod.Parameters, cilType.IsInterface));
                        }
                    }
                }
            }
            else
            {
                jclass.Methods = new List <JavaMethod>(0);
            }

            JavaClass CreateDummyClassForConstructor(CilMethod theMethod, JavaClass theClass)
            {
                if (!theMethod.HasDummyClassArg)
                {
                    return(null);
                }
                return(CilMain.CreateInnerClass(
                           theClass,
                           theMethod.Parameters[
                               theMethod.Parameters.Count - 1].Type.ClassName));
            }
        }