private String getFieldName(Remapper remapper, String desc, int idx) { char[] chars = desc.toCharArray(); int i = 0; for (int len = chars.length; i < len; ++i) { if (chars[i] != '[') { break; } } StringBuilder builder = new StringBuilder(); switch (chars[i]) { case 'I': builder.append("anInt"); break; case 'Z': builder.append("aBoolean"); break; case 'B': builder.append("aByte"); break; case 'S': builder.append("aShort"); break; case 'C': builder.append("aChar"); break; case 'J': builder.append("aLong"); break; case 'F': builder.append("aFloat"); break; case 'D': builder.append("aDouble"); break; case 'L': String name = remapper.map(desc.substring(i + 1, desc.indexOf(";"))); name = name.substring(name.lastIndexOf('/') + 1); char first = name.toLowerCase().charAt(0); if (first == 'a' || first == 'e' || first == 'i' || first == 'o' || first == 'u') { builder.append("an"); } else { builder.append("a"); } builder.append(name); while (i-- > 0) { builder.append("Array"); } char last = builder.charAt(builder.length() - 1); if (last >= '0' && last <= '9') { builder.append("_"); } return builder.append(idx).toString(); default: builder.append("aField"); } while (i-- > 0) { builder.append("Array"); } return builder.append(idx).toString(); }
@Override public void visitTypeInsn(int opcode, String type) { if (opcode == Opcodes.ANEWARRAY) { type = remapper.mapType(type); } super.visitTypeInsn(opcode, type); }
static void optimize(final File f, final File d, final Remapper remapper) throws IOException { if (f.isDirectory()) { File[] files = f.listFiles(); for (int i = 0; i < files.length; ++i) { optimize(files[i], d, remapper); } } else if (f.getName().endsWith(".class")) { ConstantPool cp = new ConstantPool(); ClassReader cr = new ClassReader(new FileInputStream(f)); // auto-boxing removal requires to recompute the maxs ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassConstantsCollector ccc = new ClassConstantsCollector(cw, cp); ClassOptimizer co = new ClassOptimizer(ccc, remapper); cr.accept(co, ClassReader.SKIP_DEBUG); Set<Constant> constants = new TreeSet<Constant>(new ConstantComparator()); constants.addAll(cp.values()); cr = new ClassReader(cw.toByteArray()); cw = new ClassWriter(0); Iterator<Constant> i = constants.iterator(); while (i.hasNext()) { Constant c = i.next(); c.write(cw); } cr.accept(cw, ClassReader.SKIP_DEBUG); if (MAPPING.get(cr.getClassName() + "/remove") != null) { return; } String n = remapper.mapType(cr.getClassName()); File g = new File(d, n + ".class"); if (!g.exists() || g.lastModified() < f.lastModified()) { if (!g.getParentFile().exists() && !g.getParentFile().mkdirs()) { throw new IOException("Cannot create directory " + g.getParentFile()); } OutputStream os = new FileOutputStream(g); try { os.write(cw.toByteArray()); } finally { os.close(); } } } }
@SuppressWarnings("unchecked") private static void processReflection(Remapper remapper, ClassNode node) { for (MethodNode mn : (List<MethodNode>) node.methods) { InsnList insns = mn.instructions; ListIterator<AbstractInsnNode> iterator = insns.iterator(); while (iterator.hasNext()) { AbstractInsnNode insn = iterator.next(); if (insn.getOpcode() == Opcodes.INVOKESTATIC) { MethodInsnNode min = (MethodInsnNode) insn; if (min.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) { AbstractInsnNode push = insn.getPrevious(); if (push.getOpcode() == Opcodes.LDC) { LdcInsnNode lin = (LdcInsnNode) push; lin.cst = remapper.map(((String) lin.cst).replace('.', '/')).replace('/', '.'); } } } } } }
@Override public void visitMultiANewArrayInsn(String desc, int dims) { desc = remapper.mapType(desc); super.visitMultiANewArrayInsn(desc, dims); }
@Override public void visitLdcInsn(Object cst) { cst = remapper.mapValue(cst); super.visitLdcInsn(cst); }