예제 #1
0
        /// <summary>
        /// Update the return type (if needed)
        /// </summary>
        private void FixReturnType(TargetFramework target)
        {
            var declaringType = method.DeclaringType;

            if ((declaringType == null) || method.IsSignConverted || (!method.NeedsOverrideKeyword))
            {
                return;
            }

            var returnType = method.ReturnType;

            if ((returnType is NetGenericParameter) && ((NetGenericParameter)returnType).Owner == method)
            {
                return;
            }

            var baseMethod      = method.Overrides.First(x => !x.DeclaringType.IsInterface);
            var expectedRetType = GenericParameters.Resolve(baseMethod.ReturnType, declaringType, target.TypeNameMap);
            var retType         = GenericParameters.Resolve(method.ReturnType, declaringType, target.TypeNameMap);

            if (!retType.AreSame(expectedRetType))
            {
                if (baseMethod.IsAbstract)
                {
                    method.ReturnType = expectedRetType;
                }
                else
                {
                    method.RequireNewSlot();
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Add abstract method (that do not yet exist) for all interface methods.
        /// </summary>
        private void AddAbstractInterfaceMethods(NetTypeDefinition typeDef, TargetFramework target)
        {
            if ((typeDef.IsInterface) || (this is IInterfaceConstantsTypeBuilder))
            {
                return;
            }

            var typeMethods = typeDef.Methods.ToList();

            foreach (var iterator in typeDef.Interfaces)
            {
                // Collect all interface methods
                var iDef     = iterator;
                var iMethods = iDef.GetElementType().Methods.Select(x => Tuple.Create(iDef, x)).ToList();
                iMethods.AddRange(iDef.GetElementType().GetBaseTypes(true).Where(x => x.GetElementType().IsInterface).SelectMany(x => x.GetElementType().Methods.Select(m => Tuple.Create(x, m))));
                foreach (var pair in iMethods)
                {
                    var iMethod = pair.Item2;
                    if (typeMethods.Any(x => x.IsExactDuplicate(iMethod)))
                    {
                        continue;
                    }

                    // Add abstract method
                    var method = new NetMethodDefinition(iMethod.Name, null, typeDef, target, iMethod.SignConvertMode, "TypeBuilder.AddAbstractInterfaceMethods");
                    method.AccessFlags = iMethod.AccessFlags;
                    method.Attributes  = iMethod.Attributes;
                    method.IsAbstract  = false;
                    method.IsVirtual   = !typeDef.IsSealed;
                    method.GenericParameters.AddRange(iMethod.GenericParameters.Select(x => new NetGenericParameter(GetMethodGenericParameterName(typeDef, x.Name), x.Name, method)));
                    method.ReturnType = GenericParameters.Resolve(iMethod.ReturnType, typeDef, target.TypeNameMap);
                    method.Parameters.AddRange(iMethod.Parameters.Select(x => new NetParameterDefinition(x.Name, GenericParameters.Resolve(x.ParameterType, typeDef, target.TypeNameMap), x.IsParams)));

                    // Check if there are duplicates now that the generic parameters are resolved.
                    if (typeMethods.Any(x => x.IsExactDuplicate(method)))
                    {
                        continue;
                    }

                    // Should we ignore this one?
                    if (IgnoreInterfaceMethod(method, iMethod))
                    {
                        continue;
                    }

                    // Test if the method is a duplicate of an existing method, but with different return type
                    var differentAccessMask = !method.HasSameVisibility(iMethod);
                    if (differentAccessMask || typeMethods.Any(x => x.IsDuplicate(method)) ||
                        ImplementAsExplicitInterfaceMethod(method, iMethod) || typeDef.NestedTypes.Any(x => x.Name == method.Name))
                    {
                        // Method with different return type exists.
                        // Make it an explicit interface method
                        method.SetExplicitImplementation(iMethod, pair.Item1);
                        method.IsAbstract = false;
                        method.IsVirtual  = false;
                    }
                    else
                    {
                        // Check for override
                        //method.IsOverride = isOverride;
                        if (method.IsOverride && method.Overrides.All(x => !x.IsVirtual))
                        {
                            // No need to override anything
                            continue;
                        }
                    }

                    // Create DexImport attribute
                    var typeCa   = iMethod.DeclaringType.CustomAttributes.First(x => x.AttributeType == null);
                    var methodCa = iMethod.CustomAttributes.First(x => x.AttributeType == null);
                    var ca       = new NetCustomAttribute(null, typeCa.ConstructorArguments[0], methodCa.ConstructorArguments[0], methodCa.ConstructorArguments[1]);
                    ca.CopyPropertiesFrom(methodCa);
                    method.CustomAttributes.Add(ca);

                    typeDef.Methods.Add(method);
                    typeMethods.Add(method);

                    // Avoid name conflicts
                    var nested = typeDef.NestedTypes.FirstOrDefault(x => x.Name == method.Name);
                    if (nested != null)
                    {
                        nested.Name = "Java" + nested.Name;
                    }
                }
            }
        }
예제 #3
0
            public string Visit(NetTypeDefinition type, bool addDummyGeneric)
            {
                string result;

                if (type.DeclaringType != null)
                {
                    // Nested
                    if (type == context)
                    {
                        result = type.Name;
                    }
                    else
                    {
                        var declType = type.DeclaringType.Accept(this, true);
                        result = declType + "." + type.Name;
                    }
                }
                else
                {
                    result = type.FullName;
                    string mapped;
                    if (useShortTypeNames && shortTypeNameMap.TryGetValue(result, out mapped))
                    {
                        if ((mapped == "void") && !allowVoid)
                        {
                            mapped = "object";
                        }
                        result = mapped;
                    }
                    else
                    {
                        //if (/*(item.Namespace != "System") ||*/ (item.Name == "Exception") || (item.Name == "Type"))
                        {
                            result = "global::" + result;
                        }
                    }
                }
                if (addDummyGeneric && (type.GenericParameters.Count > 0))
                {
                    var sb = new StringBuilder();
                    sb.Append('<');
                    var index = 0;
                    foreach (var gp in type.GenericParameters)
                    {
                        if (index > 0)
                        {
                            sb.Append(", ");
                        }
                        NetTypeReference resolvedGp;
                        var name = GenericParameters.TryResolve(gp, context, typeNameMap, out resolvedGp) ? resolvedGp.Accept(this, true) : "object";
                        sb.Append(name);
                        index++;
                    }
                    sb.Append('>');
                    result += sb;

                    // Add dummy type arguments
                    //var args = string.Join(", ", type.GenericParameters.Select(x => "object").ToArray());
                    //result = result + "<" + args + ">";
                }
                return(result);
            }
예제 #4
0
        /// <summary>
        /// Remove all properties that override / implement a property that does not exist.
        ///
        /// Will also fix property visibility.
        /// </summary>
        private void FixOverridenProperties(MethodRenamer methodRenamer, TargetFramework target)
        {
            if (!typeDef.Properties.Any())
            {
                return;
            }

            // handle overiding properties
            var allBaseTypes      = typeDef.GetBaseTypes(true);
            var allBaseProperties = allBaseTypes.SelectMany(x => x.GetElementType().Properties).ToList();

            var overridingProperties = typeDef.Properties.Where(x => IsAnyOverride(x) && !DoNotFixOverridenProperty(x)).ToList();

            for (int i = 0; i < overridingProperties.Count; ++i)
            {
                var prop = overridingProperties[i];

                NetPropertyDefinition matchingBaseProp = null;

                if (prop.Getter != null)
                {
                    // Note: this logic might need to be also applied for the "lone" setter logic below.
                    foreach (var baseProp in allBaseProperties.Where(p => p.Name == prop.Name))
                    {
                        var basePropType = GenericParameters.Resolve(baseProp.PropertyType, prop.DeclaringType, target.TypeNameMap);
                        if (!prop.PropertyType.AreSame(basePropType))
                        {
                            continue;
                        }
                        matchingBaseProp = baseProp;
                        break;
                    }

                    // Check for existing property in base class
                    if (matchingBaseProp == null)
                    {
                        // implement as normal method.
                        RemoveProperty(prop);
                        continue;
                    }

                    // Check for base property with setter
                    if (prop.Setter != null)
                    {
                        if (matchingBaseProp.Setter == null)
                        {
                            // Remove setter
                            prop.Setter.Property = null;
                            prop.Setter          = null;
                            continue;
                        }
                    }
                }
                else
                {
                    // this is a "lone" setter. for boolean setters, the name might have changed.
                    // try to match all base properties, update the name if neccessary.
                    foreach (var baseProp in allBaseProperties.Where(g => g.Getter != null && g.Setter != null))
                    {
                        if (FindSetter(baseProp.Getter, new[] { prop.Setter }, true) != null)
                        {
                            if (baseProp.Setter.IsVirtual)
                            {
                                if (matchingBaseProp == null || prop.Name == baseProp.Name)
                                {
                                    matchingBaseProp = baseProp;
                                }
                            }
                        }
                    }
                    if (matchingBaseProp == null)
                    {
                        // remove the property alltogether
                        prop.Setter.Property = null;
                        typeDef.Properties.Remove(prop);
                        continue;
                    }

                    prop.Name = matchingBaseProp.Name;
                }


                // We  must implement the property, since we inherited it.
                // Fix up any clashes.

                // clashes with explicit implementations should not occur.
                if ((prop.Getter ?? prop.Setter).InterfaceType != null)
                {
                    continue;
                }

                var propName = prop.Name;
                if (propName == typeDef.Name)
                {
                    if (!matchingBaseProp.DeclaringType.IsInterface)
                    {
                        Console.Error.WriteLine("Warning: Inherited property {0}::{1} clashes with type name. Skipping generation of property and methods.", typeDef.FullName, propName);
                        typeDef.Properties.Remove(prop);
                        typeDef.Methods.Remove(prop.Getter);
                        typeDef.Methods.Remove(prop.Setter);
                        continue;
                    }

                    // make this an explicit interface implementtion.

                    // TODO: We might also want to keep a renamed property in this case,
                    //       too allow access to the property from the class.
                    //       Also, the explicit implementation does not need a "JavaImport" attribute.
                    Console.Error.WriteLine("Warning: Inherited property {0}::{1} clashes with type name. Generating explicit implementation.", typeDef.FullName, propName);

                    if (prop.Getter != null)
                    {
                        if (matchingBaseProp.Getter != null)
                        {
                            prop.Getter.SetExplicitImplementation(matchingBaseProp.Getter, matchingBaseProp.DeclaringType);
                        }
                        else
                        {
                            prop.Getter = null;
                        }
                    }
                    if (prop.Setter != null)
                    {
                        if (matchingBaseProp.Setter != null)
                        {
                            prop.Setter.SetExplicitImplementation(matchingBaseProp.Setter, matchingBaseProp.DeclaringType);
                        }
                        else
                        {
                            prop.Setter = null;
                        }
                    }
                    continue;
                }

                if (typeDef.NestedTypes.Any(x => x.Name == propName))
                {
                    Console.Error.WriteLine("Warning: Inherited property {0}::{1} clashes with nested type. Renaming nested type, but consider renaming the property instead.", typeDef.FullName, propName);
                    typeDef.NestedTypes.Where(x => x.Name == propName).ForEach(t => t.Name += "FixMe");
                }

                foreach (var clash in typeDef.Properties.Where(x => x != prop && x.Name == propName).ToList())
                {
                    if (clash.Parameters.Count != prop.Parameters.Count)
                    {
                        continue;
                    }
                    if ((clash.Getter ?? clash.Setter).InterfaceType != null)
                    {
                        continue;
                    }

                    if (prop.PropertyType.AreSame(clash.PropertyType) &&
                        prop.MainMethod.CreateReason == "TypeBuilder.AddAbstractInterfaceMethods")
                    {
                        // it appears that the method does have an implementation!
                        typeDef.Properties.Remove(prop);
                        typeDef.Methods.Remove(prop.Getter);
                        typeDef.Methods.Remove(prop.Setter);
                        overridingProperties.RemoveAt(i);
                        i -= 1;
                        goto continue_outer;
                    }

                    if (overridingProperties.Contains(clash))
                    {
                        // This would have probably been removed later anyways.
                        //Console.Error.WriteLine("Warning: duplicate property names {0}::{1}. Not generating property for one of the clashes.", typeDef.FullName, propName);
                        RemoveProperty(clash);
                        overridingProperties.Remove(clash); // this must come after us.
                        continue;
                    }

                    // else remove other property
                    RemoveProperty(clash);
                }

                if (typeDef.Methods.Any(x => x != prop.Setter && x != prop.Getter && x.Name == propName))
                {
                    Console.Error.WriteLine("Warning: Inherited property {0}::{1} clashes with methods. Prepending \"Invoke\" prefix to methods.", typeDef.FullName, propName);
                    typeDef.Methods.Where(x => x != prop.Setter && x != prop.Getter && x.Name == propName)
                    .ForEach(m => methodRenamer.Rename(m, "Invoke" + m.Name));
                }
                continue_outer :;
            }
        }