/// <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);
                    }
                }
            }
            /// <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);
                    }
                }
            }
            /// <summary>
            /// Convert interface methods that have an explicit implementation.
            /// </summary>
            public void Convert(ReachableContext reachableContext)
            {
                this.reachableContext = reachableContext;

                // Do we need to convert anything?
                if (!reachableContext.ReachableTypes.SelectMany(x => x.Methods).Any(NeedsConversion))
                    return;

                // Initialize some sets                                                 
                reachableMethods = reachableContext.ReachableTypes.OrderBy(r=>r.FullName)
                                                                   // order,so we get a stable output. useful for debugging.
                                                                  .SelectMany(x => x.Methods)
                                                                  .Where(m => m.IsReachable)
                                                                  .ToList();
                methodNames = new NameSet(reachableMethods.Select(m => m.Name));
                interfaces = reachableContext.ReachableTypes.Where(x => x.IsInterface).ToList();

                var interfaceToImplementingTypes = interfaces.ToDictionary(i=>i,  i=>reachableContext.ReachableTypes
                                                                                                     .Where(x=>x.Implements(i))
                                                                                                     .ToList());

                // Go over all interfaces
                foreach (var iType in interfaces)
                {
                    foreach (var iMethod in iType.Methods)
                    {
                        ConvertInterfaceMethod(iType, iMethod, interfaceToImplementingTypes);
                    }
                }

                // Remove added stubs that are an override of another added stub.
                foreach (var stubPair in addedStubs)
                {
                    var stub = stubPair.Item1;
                    var oldName = stubPair.Item2;
                    if (stub.GetBaseMethod() != null)
                    {
                        stub.DeclaringType.Methods.Remove(stub);
                    }
                    else
                    {
                        // Check for duplicate methods
                        var resolver = new GenericsResolver(stub.DeclaringType);
                        //var methodsWithSameName = stub.DeclaringType.Methods.Where(x => (x != stub) && (x.Name == stub.Name)).ToList();
                        //var duplicate = methodsWithSameName.FirstOrDefault(x => (x != stub) && x.AreSame(stub, resolver.Resolve));
                        var duplicate = stub.DeclaringType.Methods.FirstOrDefault(x => (x != stub) && x.AreSame(stub, resolver.Resolve));
                        if (duplicate != null)
                        {
                            stub.DeclaringType.Methods.Remove(stub);
                            continue;
                        }

                        if (oldName != stub.Name)
                        {
                            var newName = stub.Name;
                            stub.Name = oldName;
                            duplicate = stub.DeclaringType.Methods.FirstOrDefault(x => (x != stub) && x.AreSame(stub, resolver.Resolve));
                            if (duplicate != null)
                            {
                                stub.DeclaringType.Methods.Remove(stub);
                                continue;
                            }
                            stub.Name = newName;
                        }
                    }
                }
            }