package bytecode; import java.io.Reader; import java.util.Arrays; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; public class RemoveGenericMethods extends BaseStreamingJarProcessor { public static void main(String[] args) { new RemoveGenericMethods().go(args); } public boolean hasConfig() { return false; } @Override public ClassVisitor createClassVisitor(final ClassVisitor parent) throws Exception { return new ClassVisitor(Opcodes.ASM5, parent) { String className; @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(version, access, name, signature, superName, interfaces); className = name; } @Override public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) { // Delete any method that calls the same method in the same class with a different return type (and the same arg types) // This could remove a lot of methods that shouldn't be removed, in theory. In practice it doesn't. // These method calls are probably never generated by javac in other cases. final Type caller = Type.getMethodType(desc); final String callerName = name; final MethodNode mn = new MethodNode(access, name, desc, signature, exceptions); return new MethodVisitor(Opcodes.ASM5, mn) { boolean deleteMethod = false; @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { if(owner.equals(className) && name.equals(callerName)) { Type callee = Type.getMethodType(desc); if(Arrays.equals(caller.getArgumentTypes(), callee.getArgumentTypes()) && !caller.getReturnType().equals(callee.getReturnType()) && opcode != Opcodes.INVOKESTATIC) deleteMethod = true; } super.visitMethodInsn(opcode, owner, name, desc, itf); } @Override public void visitEnd() { super.visitEnd(); if(!deleteMethod) { mn.accept(parent.visitMethod(access, name, desc, signature, exceptions)); } //else // System.err.println("Removing "+className+"/"+name+desc); } }; } }; } @Override public void loadConfig(Reader file) throws Exception { } }