package lombok.eclipse.agent; import org.mangosdk.spi.ProviderFor; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import static org.objectweb.asm.Opcodes.*; @ProviderFor(EclipseTransformer.class) public class EclipseLinkedNodeFinderTransformer implements EclipseTransformer { private static final String LINKED_NODE_FINDER = "org/eclipse/jdt/core/internal/corext/dom/LinkedNodeFinder"; @Override public String getTargetClassName() { return LINKED_NODE_FINDER; } @Override public byte[] transform(byte[] in) { ClassReader reader = new ClassReader(in); ClassWriter writer = new ClassWriter(reader, 0); ClassAdapter adapter = new LinkedNodeFinderPatcherAdapter(writer); reader.accept(adapter, 0); return writer.toByteArray(); } private static class LinkedNodeFinderPatcherAdapter extends ClassAdapter { private int originalAccess; private String originalDesc; private String originalSignature; private String[] originalExceptions; LinkedNodeFinderPatcherAdapter(ClassVisitor cv) { super(cv); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if ( !name.equals("findByNode") ) return super.visitMethod(access, name, desc, signature, exceptions); originalAccess = access; originalDesc = desc; originalSignature = signature; originalExceptions = exceptions; return super.visitMethod(0, "findByNode0", desc, signature, exceptions); } private static final String SIMPLENAME = "org/eclipse/jdt/core/dom/SimpleName"; private static final String SIMPLENAME_ARRAY = "[L" + SIMPLENAME + ";"; private static final String ASTNODE = "Lorg/eclipse/jdt/internal/compiler/ast/ASTNode;"; /* * code generated by running ASMifier on: * public SimpleName[] findByNode(ASTNode a, SimpleName b) { SimpleName[] ps = this.findByNode0(a, b); int count = 0; for (int i = 0; i < ps.length; i++) { if ( ps[i] == null || ps[i].$generatedBy == null ) count++; } if (count == ps.length) return ps; SimpleName[] newPs = new SimpleName[count]; count = 0; for (int i = 0; i < ps.length; i++) { if ( ps[i] == null || ps[i].p == null ) newPs[count++] = ps[i]; } return newPs; } */ @Override public void visitEnd() { MethodVisitor mv = super.visitMethod(originalAccess, "findByNode", originalDesc, originalSignature, originalExceptions); mv.visitCode(); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKESPECIAL, LINKED_NODE_FINDER, "findByNode0", originalDesc); mv.visitVarInsn(ASTORE, 3); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 4); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 5); Label l0 = new Label(); mv.visitLabel(l0); mv.visitFrame(F_APPEND,3, new Object[] {SIMPLENAME_ARRAY, INTEGER, INTEGER}, 0, null); mv.visitVarInsn(ILOAD, 5); mv.visitVarInsn(ALOAD, 3); mv.visitInsn(ARRAYLENGTH); Label l1 = new Label(); mv.visitJumpInsn(IF_ICMPGE, l1); mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ILOAD, 5); mv.visitInsn(AALOAD); Label l2 = new Label(); mv.visitJumpInsn(IFNULL, l2); mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ILOAD, 5); mv.visitInsn(AALOAD); mv.visitFieldInsn(GETFIELD, SIMPLENAME, "$generatedBy", ASTNODE); Label l3 = new Label(); mv.visitJumpInsn(IFNONNULL, l3); mv.visitLabel(l2); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitIincInsn(4, 1); mv.visitLabel(l3); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitIincInsn(5, 1); mv.visitJumpInsn(GOTO, l0); mv.visitLabel(l1); mv.visitFrame(F_CHOP,1, null, 0, null); mv.visitVarInsn(ILOAD, 4); mv.visitVarInsn(ALOAD, 3); mv.visitInsn(ARRAYLENGTH); Label l4 = new Label(); mv.visitJumpInsn(IF_ICMPNE, l4); mv.visitVarInsn(ALOAD, 3); mv.visitInsn(ARETURN); mv.visitLabel(l4); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitVarInsn(ILOAD, 4); mv.visitTypeInsn(ANEWARRAY, SIMPLENAME); mv.visitVarInsn(ASTORE, 5); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 4); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 6); Label l5 = new Label(); mv.visitLabel(l5); mv.visitFrame(F_APPEND,2, new Object[] {SIMPLENAME_ARRAY, INTEGER}, 0, null); mv.visitVarInsn(ILOAD, 6); mv.visitVarInsn(ALOAD, 3); mv.visitInsn(ARRAYLENGTH); Label l6 = new Label(); mv.visitJumpInsn(IF_ICMPGE, l6); mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ILOAD, 6); mv.visitInsn(AALOAD); Label l7 = new Label(); mv.visitJumpInsn(IFNULL, l7); mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ILOAD, 6); mv.visitInsn(AALOAD); mv.visitFieldInsn(GETFIELD, SIMPLENAME, "$generatedBy", ASTNODE); Label l8 = new Label(); mv.visitJumpInsn(IFNONNULL, l8); mv.visitLabel(l7); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 5); mv.visitVarInsn(ILOAD, 4); mv.visitIincInsn(4, 1); mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ILOAD, 6); mv.visitInsn(AALOAD); mv.visitInsn(AASTORE); mv.visitLabel(l8); mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitIincInsn(6, 1); mv.visitJumpInsn(GOTO, l5); mv.visitLabel(l6); mv.visitFrame(F_CHOP,1, null, 0, null); mv.visitVarInsn(ALOAD, 5); mv.visitInsn(ARETURN); mv.visitMaxs(4, 7); super.visitEnd(); } } }