/// <summary> /// Create the current type as class definition. /// </summary> public virtual void Create(ClassDefinition declaringClass, XTypeDefinition declaringType, DexTargetPackage targetPackage) { // Find xfield xField = XBuilder.AsFieldDefinition(compiler.Module, field); // Create field definition dfield = new Dot42.DexLib.FieldDefinition(); dfield.Name = NameConverter.GetConvertedName(field); AddFieldToDeclaringClass(declaringClass, dfield, targetPackage); targetPackage.NameConverter.Record(xField, dfield); // Set access flags SetAccessFlags(dfield, field); // Give warning if static in generic class. // This could of cause also be handled automagically be the compiler, // with mixture of whats done in the Interlocked converter and whats // done in the GenericInstanceConverter. if (field.IsStatic && declaringType.IsGenericClass) { if (!field.HasSuppressMessageAttribute("StaticFieldInGenericType") && !field.DeclaringType.HasSuppressMessageAttribute("StaticFieldInGenericType")) { string msg; if (field.Name.Contains("CachedAnonymousMethodDelegate")) { msg = "The compiler generated a static field '{0}' in generic type '{1}'. This is not supported " + "in Dot42 if the anonymous delegate accesses a generic class parameter. A workaround " + "is to convert the anonymous static delegate to a normal method.\n"; } else { msg = "Static field '{0}' in generic type {1}: All generic instances will share " + "the same static field, contrary on how CLR operates. A workaround is to " + "use ConcurrentDictionaries to access the values dependent on the type.\n"; } msg += "You can suppress this warning with a [SuppressMessage(\"dot42\"," + " \"StaticFieldInGenericType\")] attribute, either on the field or on the class."; var body = field.DeclaringType.Methods.Select(m => m.Body) .FirstOrDefault(m => m != null && m.Instructions.Any(i => i.SequencePoint(m) != null)); if (body != null) { var seqPoint = body.Instructions.Select(i => i.SequencePoint(body)).First(i => i != null); DLog.Warning(DContext.CompilerILConverter, seqPoint.Document.Url, seqPoint.StartColumn, seqPoint.StartLine, msg, field.Name, declaringType.FullName); } else { DLog.Warning(DContext.CompilerILConverter, msg, field.Name, declaringType.FullName); } } } }
/// <summary> /// Create the current type as class definition. /// </summary> public void Create(ClassDefinition declaringClass, DexTargetPackage targetPackage) { // Find xField xField = XBuilder.AsFieldDefinition(compiler.Module, field); // Create field definition dfield = new Dot42.DexLib.FieldDefinition(); dfield.Name = NameConverter.GetConvertedName(field); AddFieldToDeclaringClass(declaringClass, dfield, targetPackage); targetPackage.NameConverter.Record(xField, dfield); // Set access flags SetAccessFlags(dfield, field); }
/// <summary> /// Create the current type as class definition. /// </summary> protected virtual void CreateClassDefinition(Dex target, NameConverter nsConverter, ClassDefinition parent, ClassFile parentClass) { // Create classdef classDef = new ClassDefinition(); classDef.MapFileId = compiler.GetNextMapFileId(); classDef.Namespace = nsConverter.GetConvertedNamespace(typeDef); var name = NameConverter.GetConvertedName(typeDef); classDef.Name = (parent != null) ? parent.Name + "$" + name : name; // Set access flags //if (typeDef.IsPublic) classDef.IsPublic = true; //else classDef.IsPrivate = true; classDef.IsPublic = true; if (typeDef.IsFinal) { classDef.IsFinal = true; } if (typeDef.IsInterface) { classDef.IsInterface = true; classDef.IsAbstract = true; } else if (typeDef.IsAbstract) { classDef.IsAbstract = true; } if (typeDef.Interfaces.Any(x => x.ClassName == "java/lang/annotation/Annotation")) { classDef.IsAnnotation = true; } classDef.IsEnum = typeDef.IsEnum; if (parent != null) { // Add to parent if this is a nested type classDef.Owner = parent; parent.AddInnerClass(classDef); } else { // Add to dex if it is a root class target.AddClass(classDef); } }
/// <summary> /// Perform name conversion /// </summary> protected virtual string GetMethodName(MethodDefinition method, DexTargetPackage targetPackage) { // Handle special names switch (method.Name) { case ".ctor": return("<init>"); case ".cctor": return("<clinit>"); } // Handle regular names // Test for overrides of dex/java imported methods var javaBaseMethod = method.GetDexImportBaseMethod() ?? method.GetJavaImportBaseMethod(); if (javaBaseMethod != null) { var javaMethodRef = javaBaseMethod.GetReference(targetPackage, compiler.Module); return(javaMethodRef.Name); } // Test for overrides of interface methods var interfaceJavaBaseMethod = method.GetDexImportBaseInterfaceMethod() ?? method.GetJavaImportBaseInterfaceMethod(); if (interfaceJavaBaseMethod != null) { var javaMethodRef = interfaceJavaBaseMethod.GetReference(targetPackage, compiler.Module); return(javaMethodRef.Name); } // If a dex name is specified, use that var dexName = method.GetDexNameAttribute(); if (dexName != null) { return((string)dexName.ConstructorArguments[0].Value); } return(NameConverter.GetConvertedName(xMethod)); }
/// <summary> /// Convert the given interface method if it has explicit implementations. /// </summary> private void ConvertInterfaceMethod(TypeDefinition iType, MethodDefinition iMethod) { var implementations = GetImplementations(iMethod); var iMethodIsJavaWithGenericParams = iMethod.IsJavaMethodWithGenericParams(); var iMethodContainsGenericParams = iMethod.ContainsGenericParameter; if (!iMethodIsJavaWithGenericParams && !iMethodContainsGenericParams && (!implementations.Any(x => x.IsExplicitImplementation()))) { // There are no explicit implementation. // No need to convert return; } // Rename method string newName; bool createExplicitStubs = true; var oldName = iMethod.Name; var attr = iMethod.GetDexOrJavaImportAttribute(); if (attr != null) { string className; string memberName; string descriptor; attr.GetDexOrJavaImportNames(iMethod, out memberName, out descriptor, out className); newName = memberName; } else if ((attr = iMethod.GetDexNameAttribute()) != null) { newName = (string)(attr.ConstructorArguments[0].Value); createExplicitStubs = false; } else { var module = reachableContext.Compiler.Module; var xiType = XBuilder.AsTypeReference(module, iType); newName = methodNames.GetUniqueName(NameConverter.GetConvertedName(xiType) + "_" + iMethod.Name); oldName = newName; } Rename(iMethod, newName); // Update implementations foreach (var impl in implementations) { if (impl.IsExplicitImplementation()) { // Convert to implicit impl.IsPublic = true; // Rename Rename(impl, newName); // Update names of overrides foreach (var @override in impl.Overrides) { @override.Name = newName; } } else if (!(impl.HasDexImportAttribute() || impl.HasJavaImportAttribute())) { // Add stub redirecting explicit implementation to implicit implementation if (createExplicitStubs) { CreateExplicitStub(impl, newName, oldName, iMethod, iMethodIsJavaWithGenericParams /*|| iMethodContainsGenericParams*/); } } } }
/// <summary> /// Create the name of the class. /// </summary> protected virtual string CreateClassName(XTypeDefinition xType) { return(NameConverter.GetConvertedName(XType)); }
/// <summary> /// Create an annotation interface. /// </summary> internal static AttributeAnnotationInterface Create( ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, TypeDefinition attributeType, ClassDefinition attributeClass) { // Create class ClassDefinition @interface = new ClassDefinition(); @interface.Name = CreateAnnotationTypeName(attributeClass); @interface.Namespace = attributeClass.Namespace; @interface.AccessFlags = AccessFlags.Public | AccessFlags.Abstract | AccessFlags.Interface | AccessFlags.Annotation; @interface.Owner = attributeClass; attributeClass.InnerClasses.Add(@interface); // Set super class @interface.SuperClass = new ClassReference("java/lang/Object"); // Implement Dot42.Internal.IAttribute @interface.Interfaces.Add(new ClassReference("java/lang/annotation/Annotation")); // Prepare result AttributeAnnotationInterface result = new AttributeAnnotationInterface(@interface); // Add methods from IAttribute XModel.XTypeDefinition baseIntfType = compiler.GetDot42InternalType("IAttribute").Resolve(); foreach (XModel.XMethodDefinition imethod in baseIntfType.Methods) { if (imethod.Parameters.Count > 0) { throw new CompilerException(string.Format("Invalid IAttribute method {0}", imethod)); } string methodName = NameConverter.GetConvertedName(imethod); TypeReference dfieldType = imethod.ReturnType.GetReference(targetPackage); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dfieldType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; @interface.Methods.Add(method); } // Add field mapping foreach (var field in attributeType.Fields.Where(x => x.IsReachable && x.IsPublic)) { string methodName = CreateGetMethodName(NameConverter.GetConvertedName(field), result); TypeReference dfieldType = field.FieldType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dfieldType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; result.FieldToGetMethodMap.Add(field, method); @interface.Methods.Add(method); } // Add property mapping foreach (var property in attributeType.Properties.Where(x => x.IsReachable && (x.SetMethod != null) && (x.SetMethod.IsPublic) && x.SetMethod.IsReachable)) { string methodName = CreateGetMethodName(NameConverter.GetConvertedName(property), result); TypeReference dpropType = property.PropertyType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dpropType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; result.PropertyToGetMethodMap.Add(property, method); @interface.Methods.Add(method); } // Add ctor mapping var argIndex = 0; foreach (var ctor in attributeType.Methods.Where(x => (x.Name == ".ctor") && x.IsReachable)) { // Add methods for the ctor arguments List <MethodDefinition> paramGetMethods = new List <MethodDefinition>(); foreach (ParameterDefinition p in ctor.Parameters) { string methodName = CreateGetMethodName("c" + argIndex++, result); TypeReference dparamType = p.ParameterType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dparamType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; @interface.Methods.Add(method); paramGetMethods.Add(method); } // Add a builder method MethodDefinition buildMethod = CreateBuildMethod(sequencePoint, ctor, paramGetMethods, compiler, targetPackage, attributeClass, result); result.CtorMap.Add(ctor, new AttributeCtorMapping(buildMethod, paramGetMethods)); } // Create default values annotation Annotation defAnnotation = CreateDefaultAnnotation(result); result.AnnotationInterfaceClass.Annotations.Add(defAnnotation); return(result); }
/// <summary> /// Gets a class reference for the given type reference. /// </summary> internal static TypeReference GetReference(this XTypeReference type, DexTargetPackage targetPackage) { if (type == null) { throw new ArgumentNullException("type"); } type = type.GetWithoutModifiers(); // Handle array's if (type.IsArray) { var arrType = (XArrayType)type; var dimensions = arrType.Dimensions.Count() - 1; var dArrayType = new ArrayType(GetReference(type.ElementType, targetPackage)); while (dimensions > 0) { dArrayType = new ArrayType(dArrayType); dimensions--; } return(dArrayType); } // Handle generic parameters if (type.IsGenericParameter || (type.IsByReference && type.ElementType.IsGenericParameter)) { if (type.IsByReference) // this should be possible as well, but would need some more code at some other places. { return(new ByReferenceType(FrameworkReferences.Object)); } var gp = (XGenericParameter)type; if (gp.AllowConstraintAsTypeReference()) { return(gp.Constraints[0].GetReference(targetPackage)); } return(FrameworkReferences.Object); } // Handle out/ref types if (type.IsByReference) { var byRefType = (XByReferenceType)type; return(new ByReferenceType(GetReference(byRefType.ElementType, targetPackage))); } // Handle Nullable<T> if (type.IsGenericInstance) { var git = (XGenericInstanceType)type; if (git.ElementType.IsNullableT()) { var arg = git.GenericArguments[0]; if (arg.IsBoolean()) { return(new ClassReference("java/lang/Boolean")); } if (arg.IsByte() || arg.IsSByte()) { return(new ClassReference("java/lang/Byte")); } if (arg.IsChar()) { return(new ClassReference("java/lang/Character")); } if (arg.IsInt16() || arg.IsUInt16()) { return(new ClassReference("java/lang/Short")); } if (arg.IsInt32() || arg.IsUInt32()) { return(new ClassReference("java/lang/Integer")); } if (arg.IsInt64() || arg.IsUInt64()) { return(new ClassReference("java/lang/Long")); } if (arg.IsDouble()) { return(new ClassReference("java/lang/Double")); } if (arg.IsFloat()) { return(new ClassReference("java/lang/Float")); } var typeofT = git.GenericArguments[0]; if (typeofT.IsGenericParameter) // use object. { return(FrameworkReferences.Object); } XTypeDefinition typeofTDef; if (!typeofT.TryResolve(out typeofTDef)) { throw new XResolutionException(typeofT); } var className = targetPackage.NameConverter.GetConvertedFullName(typeofTDef); var classDef = targetPackage.DexFile.GetClass(className); // Use nullable base class of T, if enum. if (classDef.IsEnum) { return(classDef.SuperClass); } // I like the base class concept for enums. unfortunately it seems to be // impossible for structs and/or might have performance implications. // Just return the type for structs. return(classDef); } } var primType = GetPrimitiveType(type); if (primType != null) { return(primType); } // Resolve the type to a type definition XTypeDefinition typeDef; if (type.GetElementType().TryResolve(out typeDef)) { // Handle primitive types primType = GetPrimitiveType(typeDef); if (primType != null) { return(primType); } string className; if (typeDef.TryGetDexImportNames(out className)) { // type is a framework type return(new ClassReference(className)); } // Handle enums /* Enums Are Normal classes now * if (typeDef.IsEnum) * { * // Convert to primitive type * //return typeDef.GetEnumUnderlyingType().GetReference(target, nsConverter); * }*/ // Handle nested types of java types string convertedFullName; if (typeDef.IsNested && typeDef.DeclaringType.HasDexImportAttribute()) { // Nested type that is not imported, but it's declaring type is imported. convertedFullName = targetPackage.NameConverter.GetConvertedFullName(typeDef.DeclaringType) + "_" + NameConverter.GetConvertedName(typeDef); } else if (typeDef.TryGetJavaImportNames(out className)) { convertedFullName = className.Replace('/', '.'); } else { convertedFullName = targetPackage.NameConverter.GetConvertedFullName(typeDef); } // type is in the assembly itself var result = targetPackage.DexFile.GetClass(convertedFullName); if (result == null) { throw new ArgumentException(string.Format("Cannot find type {0}", convertedFullName)); } return(result); } var javaType = type as XModel.Java.XBuilder.JavaTypeReference; if (javaType != null) { return(new ClassReference(javaType.JavaClassName)); } throw new ResolveException(string.Format("Type {0} not found", type.FullName)); }