Rewrite of the eclipse agent to use the new lombok.patcher project.

This commit is contained in:
Reinier Zwitserloot committed 2009-09-26 09:00:12 +02:00
1 parent 35691e83ed
commit 27a3efeb1c
9 files changed
+78 -407

No files matched your search

+1
View File
@@ -18,5 +18,6 @@
<classpathentry kind="lib" path="deps/lombok/org.eclipse.equinox.common_3.5.0.v20090520-1800.jar"/>
<classpathentry kind="lib" path="deps/lombok/spi-0.2.3-pre.jar"/>
<classpathentry kind="lib" path="deps/tools.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/lombok.patcher"/>
<classpathentry kind="output" path="bin"/>
</classpath>
Binary file not shown.
@@ -52,6 +52,10 @@ public class ClassLoaderWorkaround {
private static final Map<ClassLoader, Method> transform = new HashMap<ClassLoader, Method>();
public static void transformCompilationUnitDeclarationSwapped(Object cud, Object parser) throws Exception {
transformCompilationUnitDeclaration(parser, cud);
}
public static void transformCompilationUnitDeclaration(Object parser, Object cud) throws Exception {
Method transformMethod = getTransformMethod(cud);
try {
@@ -0,0 +1,14 @@
package java.lombok.eclipse;
public class PatchFixes {
public static int fixRetrieveStartingCatchPosition(int in) {
return in;
}
private static final int BIT24 = 0x800000;
public static boolean checkBit24(Object node) throws Exception {
int bits = (Integer)(node.getClass().getField("bits").get(node));
return (bits & BIT24) != 0;
}
}
@@ -1,95 +0,0 @@
/*
* Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
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.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* Transforms Eclipse's <code>org.eclipse.jdt.core.dom.ASTConverter</code> class, which sometimes rescans bits and pieces
* of source files because Eclipse's own AST doesn't actually have enough information for eclipse (why they don't just fix
* the AST tree generator is beyond me). At any rate, for catch blocks generated by lombok, eclipse tries to rescan the
* source file to find the source position of the catch statement, which will of course fail as there's nothing there.
* We will fix the code to return the original starting position, which is a pretty good simile, instead of '-1', which
* screws up all sorts of things.
*
* Transformations applied:<ul>
* <li>The <code>retrieveStartingCatchPosition(int, int)</code> method is instrumented to return its first parameter
* instead of the constant -1.</li></ul>
*/
@ProviderFor(EclipseTransformer.class)
public class EclipseASTConverterTransformer implements EclipseTransformer {
public byte[] transform(byte[] classfileBuffer) {
ClassReader reader = new ClassReader(classfileBuffer);
ClassWriter writer = new ClassWriter(reader, 0);
ClassAdapter adapter = new ASTConverterPatcherAdapter(writer);
reader.accept(adapter, 0);
return writer.toByteArray();
}
private static class ASTConverterPatcherAdapter extends ClassAdapter {
public ASTConverterPatcherAdapter(ClassVisitor cv) {
super(cv);
}
@Override public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor writerVisitor = super.visitMethod(access, name, desc, signature, exceptions);
if ( !name.equals("retrieveStartingCatchPosition") ) return writerVisitor;
return new RetrieveStartingCatchPositionPatcher(writerVisitor);
}
}
static class RetrieveStartingCatchPositionPatcher extends MethodAdapter {
RetrieveStartingCatchPositionPatcher(MethodVisitor mv) {
super(mv);
}
int count = 0;
@Override public void visitInsn(int opcode) {
if ( opcode == Opcodes.IRETURN ) {
if ( count++ == 0 ) {
super.visitInsn(opcode);
return;
}
//replaces: "return -1" with "return [firstParam]";
super.visitInsn(Opcodes.POP);
super.visitVarInsn(Opcodes.ILOAD, 1);
super.visitInsn(Opcodes.IRETURN);
} else {
super.visitInsn(opcode);
}
}
}
@Override public String getTargetClassName() {
return "org/eclipse/jdt/core/dom/ASTConverter";
}
}
@@ -1,68 +0,0 @@
/*
* Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
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.FieldVisitor;
import org.objectweb.asm.Opcodes;
/**
* Transforms Eclipse's {@code org.eclipse.jdt.internal.compiler.ast.ASTNode} class,
* which is the super-class of all AST Node class for Eclipse.
*
* Transformations applied:<ul>
* <li>A field is added: 'public transient ASTNode $generatedBy = null;'. It is set to something other than {@code null} if
* this node is generated; the reference then points at the node that is responsible for its generation (example: a {@code @Data} annotation).</li></ul>
*/
@ProviderFor(EclipseTransformer.class)
public class EclipseASTNodeTransformer implements EclipseTransformer {
private static final String ASTNODE = "org/eclipse/jdt/internal/compiler/ast/ASTNode";
public byte[] transform(byte[] classfileBuffer) {
ClassReader reader = new ClassReader(classfileBuffer);
ClassWriter writer = new ClassWriter(reader, 0);
ClassAdapter adapter = new ASTNodePatcherAdapter(writer);
reader.accept(adapter, 0);
return writer.toByteArray();
}
private static class ASTNodePatcherAdapter extends ClassAdapter {
ASTNodePatcherAdapter(ClassVisitor cv) {
super(cv);
}
@Override public void visitEnd() {
FieldVisitor fv = cv.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_TRANSIENT, "$generatedBy", "L" + ASTNODE + ";", null, null);
fv.visitEnd();
cv.visitEnd();
}
}
@Override public String getTargetClassName() {
return ASTNODE;
}
}
@@ -1,66 +0,0 @@
/*
* Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
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.FieldVisitor;
import org.objectweb.asm.Opcodes;
/**
* Transforms Eclipse's <code>org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration</code> class,
* which is the top-level AST Node class for Eclipse.
*
* Transformations applied:<ul>
* <li>A field is added: 'public transient Object $lombokAST = null;'. We use it to cache our own AST object,
* usually of type <code>lombok.eclipse.EclipseAST.</code></li></ul>
*/
@ProviderFor(EclipseTransformer.class)
public class EclipseCUDTransformer implements EclipseTransformer {
public byte[] transform(byte[] classfileBuffer) {
ClassReader reader = new ClassReader(classfileBuffer);
ClassWriter writer = new ClassWriter(reader, 0);
ClassAdapter adapter = new CUDPatcherAdapter(writer);
reader.accept(adapter, 0);
return writer.toByteArray();
}
private static class CUDPatcherAdapter extends ClassAdapter {
CUDPatcherAdapter(ClassVisitor cv) {
super(cv);
}
@Override public void visitEnd() {
FieldVisitor fv = cv.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_TRANSIENT, "$lombokAST", "Ljava/lang/Object;", null, null);
fv.visitEnd();
cv.visitEnd();
}
}
@Override public String getTargetClassName() {
return "org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration";
}
}
@@ -1,178 +0,0 @@
/*
* Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.eclipse.agent;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import lombok.Lombok;
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.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* Transforms Eclipse's <code>org.eclipse.jdt.internal.compiler.parser.Parser</code> class,
* which handles all the actual java source to AST tree conversion in eclipse.
*
* Transformations applied:<ul>
* <li>The <code>CompilationUnitDeclaration endParse(int)</code> method is instrumented to call
* the lombok framework via ClassLoaderWorkaround to TransformEclipseAST with the CompilationUnitDeclaration
* right before it returns the CompilationUnitDeclaration.</li>
* <li>The <code>getMethodBodies(CompilationUnitDeclaration)</code> is similarly instrumented; eclipse uses a
* 2-step parsing system, where the bodies of methods aren't filled in until its actually neccessary. Lombok
* gets a chance to change the AST immediately after either step.</li>
* <li>The <code>parse(MethodDeclaration, CUD)</code>, <code>parse(ConstructorDeclaration, CUD)</code> and
* <code>parse(Initializer, TypeDeclaration, CUD)</code> methods are all instrumented to not attempt to
* complete parsing a method generated by lombok, as the source positions are obviously all wrong
* (the method content isn't in the source file!) - lombok has already filled in the complete AST.
*
* Bit24 on the flags field on all ASTNode objects is used as a marker.</li></ul>
*/
@ProviderFor(EclipseTransformer.class)
public class EclipseParserTransformer implements EclipseTransformer {
private static final String COMPILER_PKG =
"Lorg/eclipse/jdt/internal/compiler/ast/";
private static final String TARGET_STATIC_CLASS = "java/lombok/eclipse/ClassLoaderWorkaround";
private static final String TARGET_STATIC_METHOD_NAME = "transformCompilationUnitDeclaration";
private static final String TARGET_STATIC_METHOD_DESC = "(Ljava/lang/Object;Ljava/lang/Object;)V";
private static final Map<String, Class<? extends MethodVisitor>> rewriters;
static {
Map<String, Class<? extends MethodVisitor>> map = new HashMap<String, Class<? extends MethodVisitor>>();
map.put(String.format("endParse(I)%sCompilationUnitDeclaration;", COMPILER_PKG), EndParsePatcher.class);
map.put(String.format("getMethodBodies(%sCompilationUnitDeclaration;)V", COMPILER_PKG), GetMethodBodiesPatcher.class);
map.put(String.format("parse(%1$sMethodDeclaration;%1$sCompilationUnitDeclaration;)V", COMPILER_PKG), ParseBlockContainerPatcher.class);
map.put(String.format("parse(%1$sConstructorDeclaration;%1$sCompilationUnitDeclaration;Z)V", COMPILER_PKG), ParseBlockContainerPatcher.class);
map.put(String.format("parse(%1$sInitializer;%1$sTypeDeclaration;%1$sCompilationUnitDeclaration;)V", COMPILER_PKG), ParseBlockContainerPatcher.class);
rewriters = Collections.unmodifiableMap(map);
}
public byte[] transform(byte[] classfileBuffer) {
ClassReader reader = new ClassReader(classfileBuffer);
ClassWriter writer = new ClassWriter(reader, 0);
ClassAdapter adapter = new ParserPatcherAdapter(writer);
reader.accept(adapter, 0);
return writer.toByteArray();
}
private static class ParserPatcherAdapter extends ClassAdapter {
public ParserPatcherAdapter(ClassVisitor cv) {
super(cv);
}
@Override public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor writerVisitor = super.visitMethod(access, name, desc, signature, exceptions);
Class<? extends MethodVisitor> targetVisitorClass = rewriters.get(name+desc);
if ( targetVisitorClass == null ) return writerVisitor;
try {
Constructor<? extends MethodVisitor> c = targetVisitorClass.getDeclaredConstructor(MethodVisitor.class);
c.setAccessible(true);
return c.newInstance(writerVisitor);
} catch ( InvocationTargetException e ) {
throw Lombok.sneakyThrow(e.getCause());
} catch ( Exception e ) {
//NoSuchMethodException: We know they exist.
//IllegalAccessException: We called setAccessible.
//InstantiationException: None of these classes are abstract.
throw Lombok.sneakyThrow(e);
}
}
}
private static final int BIT24 = 0x800000;
static class GetMethodBodiesPatcher extends MethodAdapter {
GetMethodBodiesPatcher(MethodVisitor mv) {
super(mv);
}
@Override public void visitInsn(int opcode) {
if ( opcode == Opcodes.RETURN ) {
//injects: ClassLoaderWorkaround.transformCUD(parser, compilationUnitDeclaration);
super.visitVarInsn(Opcodes.ALOAD, 0);
super.visitVarInsn(Opcodes.ALOAD, 1);
super.visitMethodInsn(Opcodes.INVOKESTATIC, TARGET_STATIC_CLASS,
TARGET_STATIC_METHOD_NAME, TARGET_STATIC_METHOD_DESC);
}
super.visitInsn(opcode);
}
}
static class ParseBlockContainerPatcher extends MethodAdapter {
ParseBlockContainerPatcher(MethodVisitor mv) {
super(mv);
}
@Override public void visitCode() {
//injects: if ( constructorDeclaration.bits & BIT24 > 0 ) return;
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitFieldInsn(Opcodes.GETFIELD, "org/eclipse/jdt/internal/compiler/ast/ASTNode", "bits", "I");
mv.visitLdcInsn(Integer.valueOf(BIT24));
mv.visitInsn(Opcodes.IAND);
Label l0 = new Label();
mv.visitJumpInsn(Opcodes.IFLE, l0);
mv.visitInsn(Opcodes.RETURN);
mv.visitLabel(l0);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
super.visitCode();
}
}
static class EndParsePatcher extends MethodAdapter {
private static final String TARGET_STATIC_METHOD_NAME = "transformCompilationUnitDeclaration";
EndParsePatcher(MethodVisitor mv) {
super(mv);
}
@Override public void visitInsn(int opcode) {
if ( opcode == Opcodes.ARETURN ) {
//injects: ClassLoaderWorkaround.transformCUD(parser, compilationUnitDeclaration);
super.visitInsn(Opcodes.DUP);
super.visitVarInsn(Opcodes.ALOAD, 0);
super.visitInsn(Opcodes.SWAP);
super.visitMethodInsn(Opcodes.INVOKESTATIC, TARGET_STATIC_CLASS,
TARGET_STATIC_METHOD_NAME, TARGET_STATIC_METHOD_DESC);
}
super.visitInsn(opcode);
}
}
@Override public String getTargetClassName() {
return "org/eclipse/jdt/internal/compiler/parser/Parser";
}
}
@@ -37,8 +37,17 @@ import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.objectweb.asm.Opcodes;
import lombok.Lombok;
import lombok.core.SpiLoadUtil;
import lombok.patcher.Hook;
import lombok.patcher.MethodTarget;
import lombok.patcher.ScriptManager;
import lombok.patcher.StackRequest;
import lombok.patcher.scripts.AddFieldScript;
import lombok.patcher.scripts.ExitFromMethodEarlyScript;
import lombok.patcher.scripts.WrapReturnValuesScript;
/**
* This is a java-agent that patches some of eclipse's classes so AST Nodes are handed off to Lombok
@@ -108,6 +117,56 @@ public class EclipsePatcher {
public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception {
registerPatcher(instrumentation, false);
addLombokToSearchPaths(instrumentation);
ScriptManager sm = new ScriptManager();
sm.registerTransformer(instrumentation);
sm.addScript(new WrapReturnValuesScript(
new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveStartingCatchPosition"),
new Hook("java/lombok/eclipse/PatchFixes", "fixRetrieveStartingCatchPosition", "(I)I"),
StackRequest.PARAM1));
sm.addScript(new AddFieldScript("org.eclipse.jdt.internal.compiler.ast.ASTNode",
Opcodes.ACC_PUBLIC | Opcodes.ACC_TRANSIENT, "$generatedBy", "Lorg/eclipse/jdt/internal/compiler/ast/ASTNode;"));
sm.addScript(new AddFieldScript("org.eclipse.jdt.core.dom.ASTNode",
Opcodes.ACC_PUBLIC | Opcodes.ACC_TRANSIENT, "$isGenerated", "Z"));
sm.addScript(new AddFieldScript("org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration",
Opcodes.ACC_PUBLIC | Opcodes.ACC_TRANSIENT, "$lombokAST", "Ljava/lang/Object;"));
sm.addScript(new WrapReturnValuesScript(
new MethodTarget("org.eclipse.jdt.internal.compiler.parser.Parser", "getMethodBodies", "void",
"org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration"),
new Hook("java/lombok/eclipse/ClassLoaderWorkaround", "transformCompilationUnitDeclaration",
"(Ljava/lang/Object;Ljava/lang/Object;)V"), StackRequest.THIS, StackRequest.PARAM1));
sm.addScript(new WrapReturnValuesScript(
new MethodTarget("org.eclipse.jdt.internal.compiler.parser.Parser", "endParse",
"org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration", "int"),
new Hook("java/lombok/eclipse/ClassLoaderWorkaround", "transformCompilationUnitDeclarationSwapped",
"(Ljava/lang/Object;Ljava/lang/Object;)V"), StackRequest.THIS, StackRequest.RETURN_VALUE));
sm.addScript(new ExitFromMethodEarlyScript(
new MethodTarget("org.eclipse.jdt.internal.compiler.parser.Parser", "parse", "void",
"org.eclipse.jdt.internal.compiler.ast.MethodDeclaration",
"org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration"),
new Hook("java/lombok/eclipse/PatchFixes", "checkBit24",
"(Ljava/lang/Object;)Z"), null, StackRequest.PARAM1));
sm.addScript(new ExitFromMethodEarlyScript(
new MethodTarget("org.eclipse.jdt.internal.compiler.parser.Parser", "parse", "void",
"org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration",
"org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration", "boolean"),
new Hook("java/lombok/eclipse/PatchFixes", "checkBit24",
"(Ljava/lang/Object;)Z"), null, StackRequest.PARAM1));
sm.addScript(new ExitFromMethodEarlyScript(
new MethodTarget("org.eclipse.jdt.internal.compiler.parser.Parser", "parse", "void",
"org.eclipse.jdt.internal.compiler.ast.Initializer",
"org.eclipse.jdt.internal.compiler.ast.TypeDeclaration",
"org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration"),
new Hook("java/lombok/eclipse/PatchFixes", "checkBit24",
"(Ljava/lang/Object;)Z"), null, StackRequest.PARAM1));
}
private static void registerPatcher(Instrumentation instrumentation, boolean transformExisting) throws IOException {