/// <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> /// 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); } } }