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