mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 20:15:09 +00:00
Merge branch 'i164diag'
This commit is contained in:
commit
92eb7033fa
6 files changed
+247
-3
No files matched your search
@@ -0,0 +1,62 @@
|
||||
package lombok.core.debug;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
|
||||
|
||||
public class DebugSnapshot implements Comparable<DebugSnapshot> {
|
||||
private static AtomicLong counter = new AtomicLong();
|
||||
|
||||
private final long when, id = counter.getAndIncrement();
|
||||
private final List<StackTraceElement> trace;
|
||||
private final String threadName;
|
||||
private final String message;
|
||||
private final Object[] params;
|
||||
private final WeakReference<CompilationUnitDeclaration> owner;
|
||||
|
||||
public DebugSnapshot(CompilationUnitDeclaration owner, int stackHiding, String message, Object... params) {
|
||||
this.when = System.currentTimeMillis();
|
||||
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
|
||||
this.trace = new ArrayList<StackTraceElement>(Math.max(0, stackTrace.length - stackHiding - 1));
|
||||
for (int i = 1 + stackHiding; i < stackTrace.length; i++) trace.add(stackTrace[i]);
|
||||
this.threadName = Thread.currentThread().getName();
|
||||
this.message = message;
|
||||
this.params = params == null ? new Object[0] : params;
|
||||
this.owner = new WeakReference<CompilationUnitDeclaration>(owner);
|
||||
}
|
||||
|
||||
private String ownerName() {
|
||||
CompilationUnitDeclaration node = owner.get();
|
||||
if (node == null) return "--GCed--";
|
||||
char[] tn = node.getMainTypeName();
|
||||
char[] fs = node.getFileName();
|
||||
if (tn == null || tn.length == 0) {
|
||||
return (fs == null || fs.length == 0) ? "--UNKNOWN--" : new String(fs);
|
||||
}
|
||||
|
||||
return new String(tn);
|
||||
}
|
||||
|
||||
public String shortToString() {
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append(String.format("WHEN: %14d THREAD: %s AST: %s", when, threadName, ownerName()));
|
||||
if (message != null) out.append(" ").append(String.format(message, params));
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append(shortToString()).append("\n");
|
||||
for (StackTraceElement elem : trace) {
|
||||
out.append(" ").append(elem.toString()).append("\n");
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override public int compareTo(DebugSnapshot o) {
|
||||
return Long.valueOf(id).compareTo(o.id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package lombok.core.debug;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
|
||||
|
||||
public class DebugSnapshotStore {
|
||||
public static final DebugSnapshotStore INSTANCE = new DebugSnapshotStore();
|
||||
|
||||
private final Map<CompilationUnitDeclaration, List<DebugSnapshot>> map =
|
||||
new WeakHashMap<CompilationUnitDeclaration, List<DebugSnapshot>>();
|
||||
|
||||
public void snapshot(CompilationUnitDeclaration owner, String message, Object... params) {
|
||||
DebugSnapshot snapshot = new DebugSnapshot(owner, 1, message, params);
|
||||
List<DebugSnapshot> list;
|
||||
|
||||
synchronized (map) {
|
||||
list = map.get(owner);
|
||||
if (list == null) {
|
||||
list = new ArrayList<DebugSnapshot>();
|
||||
map.put(owner, list);
|
||||
}
|
||||
list.add(snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
public String print(CompilationUnitDeclaration owner, String message, Object... params) {
|
||||
List<DebugSnapshot> list;
|
||||
|
||||
synchronized (map) {
|
||||
snapshot(owner, message == null ? "Printing" : message, params);
|
||||
list = new ArrayList<DebugSnapshot>();
|
||||
list.addAll(map.get(owner));
|
||||
}
|
||||
|
||||
Collections.sort(list);
|
||||
int idx = 1;
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append("---------------------------\n");
|
||||
for (DebugSnapshot snapshot : list) {
|
||||
out.append(String.format("%3d: %s\n", idx++, snapshot.shortToString()));
|
||||
}
|
||||
out.append("******\n");
|
||||
idx = 1;
|
||||
for (DebugSnapshot snapshot : list) {
|
||||
out.append(String.format("%3d: %s", idx++, snapshot.toString()));
|
||||
}
|
||||
|
||||
try {
|
||||
File logFile = new File(System.getProperty("user.home", "."), String.format("lombok164-%d.err", System.currentTimeMillis()));
|
||||
OutputStream stream = new FileOutputStream(logFile);
|
||||
try {
|
||||
stream.write(out.toString().getBytes("UTF-8"));
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
return logFile.getAbsolutePath();
|
||||
} catch (Exception e) {
|
||||
System.err.println(out);
|
||||
return "(can't write log file - emitted to system err)";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,9 @@ 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();
|
||||
String logFileLocation = DebugSnapshotStore.INSTANCE.print(cud, "Printing: injecting whilst scope is already built.");
|
||||
Eclipse.warning("We believe you may have stumbled on issue 164. Please upload file " + logFileLocation + " to: http://code.google.com/p/projectlombok/issues/detail?id=164", 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();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user