Ejemplo n.º 1
0
            /// <summary>
            /// Rename "new" methods that override a final base method.
            /// </summary>
            public void Convert(ReachableContext reachableContext)
            {
                // Collect all names
                var newSlotMethods = reachableContext.ReachableTypes
                                     .SelectMany(x => x.Methods)
                                     .Where(m => m.IsHideBySig && !m.IsStatic &&
                                            !m.IsRuntimeSpecialName &&
                                            !m.DeclaringType.IsInterface &&
                                            (m.GetDexOrJavaImportAttribute() == null))
                                     .ToList();

                if (newSlotMethods.Count == 0)
                {
                    return;
                }

                // Go over each method, find methods to rename
                var methodsToRename = new HashSet <MethodDefinition>();

                foreach (var method in newSlotMethods)
                {
                    // Is the direct base method final?
                    var baseMethod = method.GetBaseMethod();
                    if (baseMethod == null)
                    {
                        continue;
                    }
                    if ((baseMethod.IsVirtual || baseMethod.IsAbstract) && !baseMethod.IsFinal)
                    {
                        continue;
                    }

                    methodsToRename.Add(method);
                    methodsToRename.Add(baseMethod);
                }
                if (methodsToRename.Count == 0)
                {
                    return;
                }

                // Initialize some sets
                reachableMethods = reachableContext.ReachableTypes.SelectMany(x => x.Methods)
                                   .Where(m => m.IsReachable)
                                   .ToList();

                methodNames = new NameSet(reachableMethods.Select(m => m.Name));

                var reachableMethodReferences = InterfaceHelper.GetReachableMethodReferencesByName(reachableMethods);

                var baseMethodToImplementation = reachableMethods.Except(methodsToRename)
                                                 .SelectMany(m => m.GetBaseMethods(),
                                                             (e, m) => new { Impl = e, Base = m })
                                                 .ToLookup(p => p.Base, p => p.Impl);


                // Rename methods that need renaming
                foreach (var method in methodsToRename)
                {
                    // Create new name
                    var newName = methodNames.GetUniqueName(method.Name);

                    // Find all methods that derive from method
                    var groupMethods = new HashSet <MethodDefinition> {
                        method
                    };

                    foreach (var otherMethod in baseMethodToImplementation[method])
                    {
                        // Rename this other method as well
                        groupMethods.Add(otherMethod);
                    }

                    // Add explicit implementations for interface methods
                    foreach (var iMethod in method.GetBaseInterfaceMethods())
                    {
                        var iMethodIsJavaWithGenericParams = iMethod.IsJavaMethodWithGenericParams();
                        var explicitName = methodNames.GetUniqueName(method.DeclaringType.Name + "_" + iMethod.Name);
                        var stub         = InterfaceHelper.CreateExplicitStub(method.DeclaringType, method, explicitName, iMethod, iMethodIsJavaWithGenericParams);
                        stub.IsPrivate = true;
                        stub.IsFinal   = false;
                        stub.IsVirtual = true;
                    }

                    // Rename all methods in the group
                    foreach (var m in groupMethods)
                    {
                        InterfaceHelper.Rename(m, newName, reachableMethodReferences);
                    }
                }
            }
Ejemplo n.º 2
0
            /// <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*/);
                        }
                    }
                }
            }
Ejemplo n.º 3
0
            /// <summary>
            /// Rename "new" methods that override a final base method.
            /// </summary>
            public void Convert(ReachableContext reachableContext)
            {
                // Only consider
                //   - methods that don't implement and interface or overwrite another method
                //   - are not getters or setters, if they don't hide a base setter/getter.
                //   - are not event-adders or removers
                //   - do not generics-rename Nullable<T>, as it is used heavily by the compiler.
                //   - don't belong to Dot42.Internal namespace (as these are compiler-used)

                // TODO: either check here or in CreateSignaturePostfix, but not at both places...
                var consideredMethods = reachableContext.ReachableTypes
                                        .AsParallel()
                                        .SelectMany(x => x.Methods)
                                        .Where(m => !m.IsRuntimeSpecialName &&
                                               ((!m.IsGetter && !m.IsSetter) || m.IsHideBySig) &&
                                               !DontConsiderForMethodRenaming(m.DeclaringType) &&
                                               m.GetDexOrJavaImportAttribute() == null &&
                                               !m.IsExplicitImplementation() &&
                                               m.GetBaseInterfaceMethod() == null &&
                                               m.GetBaseMethod() == null)
                                        .ToList();

                // Go over each method, check if it needs renaming
                var methodsToRename = new Dictionary <MethodDefinition, string>();

                foreach (var method in consideredMethods)
                {
                    var postfix = CreateSignaturePostfix(method);
                    if (string.IsNullOrEmpty(postfix))
                    {
                        continue;
                    }

                    methodsToRename.Add(method, postfix);
                }

                var orderedRenames = methodsToRename.OrderBy(p => p.Key.DeclaringType.FullName)
                                     .ThenBy(p => p.Key.MemberFullName())
                                     .ThenBy(p => p.Key.FullName)
                                     .ToList();

                if (orderedRenames.Count == 0)
                {
                }
                if (methodsToRename.Count == 0)
                {
                    return;
                }

                // Initialize some sets
                var reachableMethods = reachableContext.ReachableTypes
                                       .SelectMany(x => x.Methods)
                                       .Where(m => m.IsReachable)
                                       .ToList();

                var methodNames = new NameSet(reachableMethods.Select(m => m.Name));

                var baseMethodToImplementationOrOverride = reachableMethods.Except(methodsToRename.Keys)
                                                           .SelectMany(m => m.GetBaseMethods()
                                                                       .Concat(m.GetBaseInterfaceMethods())
                                                                       .Concat(m.Overrides),
                                                                       (e, m) => new { Impl = e, Base = m })
                                                           .ToLookup(p => p.Base, p => p.Impl);

                var reachableMethodReferences = InterfaceHelper.GetReachableMethodReferencesByName(reachableMethods);


                // Rename methods that need renaming
                foreach (var keyVal in methodsToRename)
                {
                    var method  = keyVal.Key;
                    var postfix = keyVal.Value;

                    // Create new name
                    var newName = methodNames.GetUniqueName(method.Name + postfix);

                    // Find all methods that derive from method
                    var groupMethods = new HashSet <MethodDefinition> {
                        method
                    };

                    if (method.IsVirtual && !method.IsFinal)
                    {
                        foreach (var otherMethod in baseMethodToImplementationOrOverride[method])
                        {
                            // Rename this other method as well
                            groupMethods.Add(otherMethod);
                        }
                    }

                    // Rename all methods in the group
                    foreach (var m in groupMethods)
                    {
                        InterfaceHelper.Rename(m, newName, reachableMethodReferences);
                    }
                }
            }