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(); }
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)); } }