Skip to content

Commit

Permalink
Improve automatic renaming
Browse files Browse the repository at this point in the history
 - Look at methods and fields inherited from classpath classes too, to avoid generating remap entry for overridden library methods
 - Don't remap <init>, <clinit>, access$*, values, valueOf
 - Add enum as superclasses
  • Loading branch information
Runemoro committed Jun 18, 2018
1 parent 46eadfc commit 6e67dda
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 13 deletions.
48 changes: 43 additions & 5 deletions src/main/java/org/dimdev/javaremapper/GeneratingMapping.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.dimdev.javaremapper;

import org.objectweb.asm.Type;

import java.util.Set;

public class GeneratingMapping extends Mapping {
Expand Down Expand Up @@ -49,18 +51,54 @@ public String getMethod(String className, String methodName, String methodDescri
// Don't remap classes not in jar
if (!classFilter.contains(className)) return null;

// Don't remap <init>, <clinit>, values, valueOf, access$* TODO: don't remap any synthetic/bridge methods
if (methodName.equals("<init>") ||
methodName.equals("<clinit>") ||
methodName.equals("values") ||
methodName.equals("valueOf") ||
methodName.startsWith("access$")) return null;

// Don't remap inherited methods, their name is inherited from the parent's mapping
for (String superclass : inheritanceProvider.getAllSuperclasses(className)) {
if (inheritanceProvider.getInheritableMethods(superclass).contains(new MemberRef(methodName, methodDescriptor))) {
return null;
for (MemberRef ref : inheritanceProvider.getInheritableMethods(superclass)) {
if (methodName.equals(ref.name) && methodDescriptorOverrides(methodDescriptor, ref.descriptor)) {
return null;
}
}
}

String result = super.getField(className, methodName, methodDescriptor);
String result = super.getMethod(className, methodName, methodDescriptor);
if (result == null) {
result = "method" + fieldIndex++;
addMethod(className, methodName, methodDescriptor, "method" + methodIndex++);
result = "method" + methodIndex++;
addMethod(className, methodName, methodDescriptor, result);
}
return result;
}

private boolean methodDescriptorOverrides(String descriptor1, String descriptor2) {
// Check return types
Type ret1 = Type.getReturnType(descriptor1);
Type ret2 = Type.getReturnType(descriptor2);
if (!ret1.equals(ret2) && !inheritanceProvider.getAllSuperclasses(ret1.getClassName()).contains(ret2.getClassName())) {
return false;
}

// Check argument types
Type[] args1 = Type.getArgumentTypes(descriptor1);
Type[] args2 = Type.getArgumentTypes(descriptor2);

if (args1.length != args2.length) return false;

for (int i = 0; i < args1.length; i++) {
String class1 = args1[i].getClassName();
String class2 = args2[i].getClassName();

// Arguments must be the identical in Java, not supertypes
if (!class1.equals(class2)) {
return false;
}
}

return true;
}
}
50 changes: 42 additions & 8 deletions src/main/java/org/dimdev/javaremapper/InheritanceMapper.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package org.dimdev.javaremapper;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.*;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class InheritanceMapper extends ClassVisitor implements InheritanceProvider {
Expand All @@ -23,8 +22,9 @@ public void visit(int version, int access, String name, String signature, String
super.visit(version, access, name, signature, superName, interfaces);

Set<String> inheritanceSet = inheritanceMap.computeIfAbsent(name, k -> new HashSet<>());
inheritanceSet.add(superName);
if (superName != null) inheritanceSet.add(superName); // java/lang/Object has a null superclass
inheritanceSet.addAll(Arrays.asList(interfaces));
if ((access & Opcodes.ACC_ENUM) != 0) inheritanceSet.add("java/lang/Enum");
className = name;
}

Expand All @@ -48,7 +48,15 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str

@Override
public Set<String> getSuperclasses(String name) {
return inheritanceMap.getOrDefault(name, Collections.emptySet());
Set<String> result = inheritanceMap.get(name);
if (result == null) {
inheritanceMap.put(name, new HashSet<>());
inheritableFields.put(name, new HashSet<>());
inheritableMethods.put(name, new HashSet<>());
visitClasspathClass(name);
result = inheritanceMap.get(name);
}
return result;
}

@Override
Expand All @@ -71,11 +79,37 @@ public Set<String> getAllSuperclasses(String name) {

@Override
public Set<MemberRef> getInheritableFields(String name) {
return inheritableFields.getOrDefault(name, Collections.emptySet());
Set<MemberRef> result = inheritableFields.get(name);
if (result == null) {
inheritanceMap.put(name, new HashSet<>());
inheritableFields.put(name, new HashSet<>());
inheritableMethods.put(name, new HashSet<>());
visitClasspathClass(name);
result = inheritableFields.get(name);
}
return result;
}

@Override
public Set<MemberRef> getInheritableMethods(String name) {
return inheritableMethods.getOrDefault(name, Collections.emptySet());
Set<MemberRef> result = inheritableMethods.get(name);
if (result == null) {
inheritanceMap.put(name, new HashSet<>());
inheritableFields.put(name, new HashSet<>());
inheritableMethods.put(name, new HashSet<>());
visitClasspathClass(name);
result = inheritableMethods.get(name);
}
return result;
}

private void visitClasspathClass(String name) {
try (InputStream inputStream = InheritanceMapper.class.getClassLoader().getResourceAsStream(name + ".class")) {
if (inputStream == null) return;
ClassReader reader = new ClassReader(inputStream);
reader.accept(this, 0);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

0 comments on commit 6e67dda

Please sign in to comment.