aboutsummaryrefslogtreecommitdiff
path: root/src/eclipseAgent/lombok/eclipse/agent
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2011-07-24 04:38:31 +0200
committerReinier Zwitserloot <reinier@zwitserloot.com>2011-07-24 04:38:31 +0200
commit92eb7033fa16ef14c05cb4461dc005a752399180 (patch)
treef10fa176acc63aeeca57d18a084c14f66c689839 /src/eclipseAgent/lombok/eclipse/agent
parentd4b4a92302af4d52a2a1d07524cb506bdecadf14 (diff)
parenta24daba66ce4705429b266972319ad15b1db0d70 (diff)
downloadlombok-92eb7033fa16ef14c05cb4461dc005a752399180.tar.gz
lombok-92eb7033fa16ef14c05cb4461dc005a752399180.tar.bz2
lombok-92eb7033fa16ef14c05cb4461dc005a752399180.zip
Merge branch 'i164diag'
Diffstat (limited to 'src/eclipseAgent/lombok/eclipse/agent')
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java13
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/Issue164Fixer.java93
2 files changed, 106 insertions, 0 deletions
diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
index c49346bc..f67bd4e3 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
@@ -21,11 +21,15 @@
*/
package lombok.eclipse.agent;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
+import java.security.ProtectionDomain;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import lombok.bytecode.ClassFileMetaData;
import lombok.core.Agent;
import lombok.patcher.Hook;
import lombok.patcher.MethodTarget;
@@ -68,6 +72,15 @@ public class EclipsePatcher extends Agent {
else ecj = injected;
registerPatchScripts(instrumentation, injected, ecj);
+ instrumentation.addTransformer(new ClassFileTransformer() {
+ @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
+ ClassFileMetaData meta = new ClassFileMetaData(classfileBuffer);
+ if (meta.usesField("org/eclipse/jdt/internal/compiler/ast/TypeDeclaration", "scope")) {
+ return Issue164Fixer.fix(classfileBuffer);
+ }
+ return null;
+ }
+ }, true);
}
private static void registerPatchScripts(Instrumentation instrumentation, boolean reloadExistingClasses, boolean ecjOnly) {
diff --git a/src/eclipseAgent/lombok/eclipse/agent/Issue164Fixer.java b/src/eclipseAgent/lombok/eclipse/agent/Issue164Fixer.java
new file mode 100644
index 00000000..65e04e44
--- /dev/null
+++ b/src/eclipseAgent/lombok/eclipse/agent/Issue164Fixer.java
@@ -0,0 +1,93 @@
+package lombok.eclipse.agent;
+
+import lombok.core.debug.DebugSnapshotStore;
+
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
+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;
+import org.objectweb.asm.commons.JSRInlinerAdapter;
+
+public class Issue164Fixer {
+ public static byte[] fix(byte[] classfileBuffer) {
+ return runAsm(classfileBuffer, true);
+ }
+
+ static class FixedClassWriter extends ClassWriter {
+ FixedClassWriter(ClassReader classReader, int flags) {
+ super(classReader, flags);
+ }
+
+ @Override protected String getCommonSuperClass(String type1, String type2) {
+ //By default, ASM will attempt to live-load the class types, which will fail if meddling with classes in an
+ //environment with custom classloaders, such as Equinox. It's just an optimization; returning Object is always legal.
+ try {
+ return super.getCommonSuperClass(type1, type2);
+ } catch (Exception e) {
+ return "java/lang/Object";
+ }
+ }
+ }
+
+ public static void catchScopeSet(TypeDeclaration typeDeclaration, ClassScope scope) {
+ typeDeclaration.scope = scope;
+ Scope sc = scope;
+ while (sc != null && !(sc instanceof CompilationUnitScope)) {
+ sc = sc.parent;
+ }
+
+ if (sc instanceof CompilationUnitScope) {
+ CompilationUnitDeclaration cud = ((CompilationUnitScope) sc).referenceContext;
+ DebugSnapshotStore.INSTANCE.snapshot(cud, "Scope is being set");
+ }
+ }
+
+ /**
+ * Runs ASM on the provider byteCode, chaining a reader to a writer and using the {@code ClassVisitor} you yourself provide
+ * via the {@see #createClassVisitor(ClassWriter)} method as the filter.
+ */
+ protected static byte[] runAsm(byte[] byteCode, boolean computeFrames) {
+ byte[] fixedByteCode = fixJSRInlining(byteCode);
+
+ ClassReader reader = new ClassReader(fixedByteCode);
+ ClassWriter writer = new FixedClassWriter(reader, computeFrames ? ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES : 0);
+
+ ClassVisitor visitor = new ClassAdapter(writer) {
+ @Override public MethodVisitor visitMethod(int access, final String mName, String desc, String signature, String[] exceptions) {
+ return new MethodAdapter(super.visitMethod(access, mName, desc, signature, exceptions)) {
+ @Override public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ if (opcode == Opcodes.PUTFIELD && "org/eclipse/jdt/internal/compiler/ast/TypeDeclaration".equals(owner) && "scope".equals(name) && !"catchScopeSet".equals(mName)) {
+ super.visitMethodInsn(Opcodes.INVOKESTATIC, "lombok/eclipse/agent/Issue164Fixer", "catchScopeSet", "(Lorg/eclipse/jdt/internal/compiler/ast/TypeDeclaration;Lorg/eclipse/jdt/internal/compiler/lookup/ClassScope;)V");
+ } else {
+ super.visitFieldInsn(opcode, owner, name, desc);
+ }
+ }
+ };
+ }
+ };
+ reader.accept(visitor, 0);
+ return writer.toByteArray();
+ }
+
+ protected static byte[] fixJSRInlining(byte[] byteCode) {
+ ClassReader reader = new ClassReader(byteCode);
+ ClassWriter writer = new FixedClassWriter(reader, 0);
+
+ ClassVisitor visitor = new ClassAdapter(writer) {
+ @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ return new JSRInlinerAdapter(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc, signature, exceptions);
+ }
+ };
+
+ reader.accept(visitor, 0);
+ return writer.toByteArray();
+ }
+}