back-in-time debugging added. Of course now 164 isn't triggering anymore :/

This commit is contained in:
Reinier Zwitserloot committed 2011-07-18 22:14:18 +02:00
1 parent 43d938a895
commit 43b3f2c0f0
4 files changed
+117 -3

No files matched your search

@@ -23,6 +23,7 @@ package lombok.eclipse;
import java.lang.reflect.Field;
import lombok.core.debug.DebugSnapshotStore;
import lombok.patcher.Symbols;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
@@ -126,9 +127,12 @@ public class TransformEclipseAST {
// Do NOT abort if (ast.bits & ASTNode.HasAllMethodBodies) != 0 - that doesn't work.
try {
DebugSnapshotStore.INSTANCE.snapshot(ast, "transform entry");
EclipseAST existing = getAST(ast, false);
new TransformEclipseAST(existing).go();
DebugSnapshotStore.INSTANCE.snapshot(ast, "transform exit");
} catch (Throwable t) {
DebugSnapshotStore.INSTANCE.snapshot(ast, "transform error: %s", t.getClass().getSimpleName());
try {
String message = "Lombok can't parse this source: " + t.toString();
@@ -25,6 +25,7 @@ import static lombok.eclipse.Eclipse.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
@@ -37,6 +38,7 @@ import lombok.Getter;
import lombok.Lombok;
import lombok.core.AnnotationValues;
import lombok.core.AST.Kind;
import lombok.core.debug.DebugSnapshotStore;
import lombok.core.handlers.TransformationsUtil;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseNode;
@@ -464,9 +466,11 @@ public class EclipseHandlerUtil {
}
if (report) {
Eclipse.warning("We believe you may have just stumbled on lombok issue #164. Please " +
"report the stack trace associated with this message at:\n" +
"http://code.google.com/p/projectlombok/issues/detail?id=164", new Throwable());
CompilationUnitDeclaration cud = (CompilationUnitDeclaration) type.top().get();
DebugSnapshotStore.INSTANCE.print(cud, "Printing: injecting whilst scope is already built.");
// Eclipse.warning("State: " + Issue164Fixer.getState(cud) + " -- We believe you may have just stumbled on lombok issue #164. Please " +
// "report the stack trace associated with this message at:\n" +
// "http://code.google.com/p/projectlombok/issues/detail?id=164. Occurred on class " + new String(parent.name), new Throwable());
}
}
@@ -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) {
@@ -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();
}
}