/// <summary> /// Create a new method in the declaring type of the given implicit implementation with the given new name. /// This method will call the implicit implementation. /// </summary> private void CreateExplicitStub(MethodDefinition implicitImpl, string newName, string oldName, MethodDefinition iMethod, bool avoidGenericParam) { // Create method var newMethod = InterfaceHelper.CreateExplicitStub(implicitImpl, newName, iMethod, avoidGenericParam); // Record addedStubs.Add(Tuple.Create(newMethod, oldName)); }
/// <summary> /// Rename the given method and all references to it from code. /// </summary> private void Rename(MethodDefinition method, string newName) { methodReferences = methodReferences ?? InterfaceHelper.GetReachableMethodReferencesByName(reachableMethods); var resolver = new GenericsResolver(method.DeclaringType); foreach (var methodRef in methodReferences[method.Name]) { if (ReferenceEquals(method, methodRef)) { continue; } if (methodRef.AreSameIncludingDeclaringType(method, resolver.Resolve)) { methodRef.Name = newName; } } method.SetName(newName); }
/// <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); } } }