/// <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);
                    }
                }
            }
예제 #2
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);
                    }
                }
            }