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