mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 18:15:55 +00:00
Fixes for issue 470: VerifyErrors when using @SneakyThrows.
This commit is contained in:
1 parent
b3b91a0ddd
commit
7bbb7cf3ca
10 files changed
+131
-28
No files matched your search
@@ -2,6 +2,7 @@ Lombok Changelog
|
||||
----------------
|
||||
|
||||
### v0.11.9 (Edgy Guinea Pig)
|
||||
* BUGFIX: Usage of `Lombok.sneakyThrow()` or `@SneakyThrows` would sometimes result in invalid classes (classes which fail with `VerifyError`). [Issue #470](https://code.google.com/p/projectlombok/issues/detail?id=470)
|
||||
* BUGFIX: Using `val` in try-with-resources did not work for javac. [Issue #520](https://code.google.com/p/projectlombok/issues/detail?id=520)
|
||||
* BUGFIX: When using `@Data`, warnings are not generated if certain aspects are not generated because you wrote explicit versions of them. However, this gets confusing with `equals` / `hashCode` / `canEqual`, as nothing is generated if any one of those methods is present. Now, if one of `equals` or `hashCode` is present but not the other one (or `canEqual` is present but `equals` and/or `hashCode` is missing), a warning is emitted to explain that lombok will not generate any of the equals / hashCode methods, and that you should either write them all yourself or remove them all. [Issue #513](https://code.google.com/p/projectlombok/issues/detail?id=513)
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ public class PreventNullAnalysisRemover implements PostCompilerTransformation {
|
||||
byte[] fixedByteCode = fixJSRInlining(original);
|
||||
|
||||
ClassReader reader = new ClassReader(fixedByteCode);
|
||||
ClassWriter writer = new FixedClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
||||
ClassWriter writer = new FixedClassWriter(reader, 0);
|
||||
|
||||
final AtomicBoolean changesMade = new AtomicBoolean();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2012 The Project Lombok Authors.
|
||||
* Copyright (C) 2010-2013 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -32,19 +32,21 @@ import org.mangosdk.spi.ProviderFor;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
@ProviderFor(PostCompilerTransformation.class)
|
||||
public class SneakyThrowsRemover implements PostCompilerTransformation {
|
||||
|
||||
@Override public byte[] applyTransformations(byte[] original, String fileName, DiagnosticsReceiver diagnostics) {
|
||||
@Override public byte[] applyTransformations(byte[] original, String fileName, final DiagnosticsReceiver diagnostics) {
|
||||
if (!new ClassFileMetaData(original).usesMethod("lombok/Lombok", "sneakyThrow")) return null;
|
||||
|
||||
byte[] fixedByteCode = fixJSRInlining(original);
|
||||
|
||||
ClassReader reader = new ClassReader(fixedByteCode);
|
||||
ClassWriter writer = new FixedClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
||||
ClassWriter writer = new ClassWriter(reader, 0);
|
||||
|
||||
final AtomicBoolean changesMade = new AtomicBoolean();
|
||||
|
||||
@@ -53,6 +55,8 @@ public class SneakyThrowsRemover implements PostCompilerTransformation {
|
||||
super(Opcodes.ASM4, mv);
|
||||
}
|
||||
|
||||
private boolean methodInsnQueued = false;
|
||||
|
||||
@Override public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
||||
if (
|
||||
opcode == Opcodes.INVOKESTATIC &&
|
||||
@@ -60,16 +64,117 @@ public class SneakyThrowsRemover implements PostCompilerTransformation {
|
||||
"lombok/Lombok".equals(owner) &&
|
||||
"(Ljava/lang/Throwable;)Ljava/lang/RuntimeException;".equals(desc)) {
|
||||
|
||||
changesMade.set(true);
|
||||
if (System.getProperty("lombok.debugAsmOnly", null) != null) {
|
||||
super.visitMethodInsn(opcode, owner, name, desc); // DEBUG for issue 470!
|
||||
} else {
|
||||
super.visitInsn(Opcodes.ATHROW);
|
||||
methodInsnQueued = true;
|
||||
}
|
||||
} else {
|
||||
super.visitMethodInsn(opcode, owner, name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleQueue() {
|
||||
if (!methodInsnQueued) return;
|
||||
super.visitMethodInsn(Opcodes.INVOKESTATIC, "lombok/Lombok", "sneakyThrow", "(Ljava/lang/Throwable;)Ljava/lang/RuntimeException;");
|
||||
methodInsnQueued = false;
|
||||
diagnostics.addWarning("Proper usage is: throw lombok.Lombok.sneakyThrow(someException);. You did not 'throw' it. Because of this, the call to sneakyThrow " +
|
||||
"remains in your classfile and you will need lombok.jar on the classpath at runtime.");
|
||||
}
|
||||
|
||||
@Override public void visitInsn(int arg0) {
|
||||
if (methodInsnQueued && arg0 == Opcodes.ATHROW) {
|
||||
changesMade.set(true);
|
||||
// As expected, the required ATHROW. We can now safely 'eat' the previous call.
|
||||
methodInsnQueued = false;
|
||||
}
|
||||
handleQueue();
|
||||
super.visitInsn(arg0);
|
||||
}
|
||||
@Override public void visitFrame(int arg0, int arg1, Object[] arg2, int arg3, Object[] arg4) {
|
||||
handleQueue();
|
||||
super.visitFrame(arg0, arg1, arg2, arg3, arg4);
|
||||
}
|
||||
|
||||
@Override public void visitIincInsn(int arg0, int arg1) {
|
||||
handleQueue();
|
||||
super.visitIincInsn(arg0, arg1);
|
||||
}
|
||||
|
||||
@Override public void visitFieldInsn(int arg0, String arg1, String arg2, String arg3) {
|
||||
handleQueue();
|
||||
super.visitFieldInsn(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
@Override public void visitIntInsn(int arg0, int arg1) {
|
||||
handleQueue();
|
||||
super.visitIntInsn(arg0, arg1);
|
||||
}
|
||||
|
||||
@Override public void visitEnd() {
|
||||
handleQueue();
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
@Override public void visitInvokeDynamicInsn(String arg0, String arg1, Handle arg2, Object... arg3) {
|
||||
handleQueue();
|
||||
super.visitInvokeDynamicInsn(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
@Override public void visitLabel(Label arg0) {
|
||||
handleQueue();
|
||||
super.visitLabel(arg0);
|
||||
}
|
||||
|
||||
@Override public void visitJumpInsn(int arg0, Label arg1) {
|
||||
handleQueue();
|
||||
super.visitJumpInsn(arg0, arg1);
|
||||
}
|
||||
|
||||
@Override public void visitLdcInsn(Object arg0) {
|
||||
handleQueue();
|
||||
super.visitLdcInsn(arg0);
|
||||
}
|
||||
|
||||
@Override public void visitLocalVariable(String arg0, String arg1, String arg2, Label arg3, Label arg4, int arg5) {
|
||||
handleQueue();
|
||||
super.visitLocalVariable(arg0, arg1, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
|
||||
@Override public void visitMaxs(int arg0, int arg1) {
|
||||
handleQueue();
|
||||
super.visitMaxs(arg0, arg1);
|
||||
}
|
||||
|
||||
@Override public void visitLookupSwitchInsn(Label arg0, int[] arg1, Label[] arg2) {
|
||||
handleQueue();
|
||||
super.visitLookupSwitchInsn(arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
@Override public void visitMultiANewArrayInsn(String arg0, int arg1) {
|
||||
handleQueue();
|
||||
super.visitMultiANewArrayInsn(arg0, arg1);
|
||||
}
|
||||
|
||||
@Override public void visitVarInsn(int arg0, int arg1) {
|
||||
handleQueue();
|
||||
super.visitVarInsn(arg0, arg1);
|
||||
}
|
||||
|
||||
@Override public void visitTryCatchBlock(Label arg0, Label arg1, Label arg2, String arg3) {
|
||||
handleQueue();
|
||||
super.visitTryCatchBlock(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
@Override public void visitTableSwitchInsn(int arg0, int arg1, Label arg2, Label... arg3) {
|
||||
handleQueue();
|
||||
super.visitTableSwitchInsn(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
@Override public void visitTypeInsn(int arg0, String arg1) {
|
||||
handleQueue();
|
||||
super.visitTypeInsn(arg0, arg1);
|
||||
}
|
||||
}
|
||||
|
||||
reader.accept(new ClassVisitor(Opcodes.ASM4, writer) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Project Lombok Authors.
|
||||
* Copyright (C) 2010-2013 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -33,6 +33,7 @@ public final class PostCompiler {
|
||||
private static List<PostCompilerTransformation> transformations;
|
||||
|
||||
public static byte[] applyTransformations(byte[] original, String fileName, DiagnosticsReceiver diagnostics) {
|
||||
if (System.getProperty("lombok.disablePostCompiler", null) != null) return original;
|
||||
init(diagnostics);
|
||||
byte[] previous = original;
|
||||
for (PostCompilerTransformation transformation : transformations) {
|
||||
@@ -59,6 +60,7 @@ public final class PostCompiler {
|
||||
}
|
||||
|
||||
public static OutputStream wrapOutputStream(final OutputStream originalStream, final String fileName, final DiagnosticsReceiver diagnostics) throws IOException {
|
||||
if (System.getProperty("lombok.disablePostCompiler", null) != null) return originalStream;
|
||||
return new ByteArrayOutputStream() {
|
||||
@Override public void close() throws IOException {
|
||||
// no need to call super
|
||||
|
||||
@@ -24,6 +24,7 @@ package lombok.eclipse;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import org.eclipse.jdt.internal.compiler.CompilationResult;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -123,7 +124,8 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
|
||||
}
|
||||
|
||||
void addToCompilationResult() {
|
||||
addProblemToCompilationResult((CompilationUnitDeclaration) top().get(),
|
||||
CompilationUnitDeclaration cud = (CompilationUnitDeclaration) top().get();
|
||||
addProblemToCompilationResult(cud.getFileName(), cud.compilationResult,
|
||||
isWarning, message, sourceStart, sourceEnd);
|
||||
}
|
||||
}
|
||||
@@ -147,11 +149,10 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
|
||||
* Adds a problem to the provided CompilationResult object so that it will show up
|
||||
* in the Problems/Warnings view.
|
||||
*/
|
||||
public static void addProblemToCompilationResult(CompilationUnitDeclaration ast,
|
||||
public static void addProblemToCompilationResult(char[] fileNameArray, CompilationResult result,
|
||||
boolean isWarning, String message, int sourceStart, int sourceEnd) {
|
||||
if (ast.compilationResult == null) return;
|
||||
try {
|
||||
EcjReflectionCheck.addProblemToCompilationResult.invoke(null, ast, isWarning, message, sourceStart, sourceEnd);
|
||||
EcjReflectionCheck.addProblemToCompilationResult.invoke(null, fileNameArray, result, isWarning, message, sourceStart, sourceEnd);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
//ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
|
||||
//do anything useful here.
|
||||
@@ -168,7 +169,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
|
||||
//do anything useful here.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final CompilationUnitDeclaration compilationUnitDeclaration;
|
||||
private boolean completeParse;
|
||||
|
||||
@@ -358,7 +359,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
|
||||
}
|
||||
|
||||
private static class EcjReflectionCheck {
|
||||
private static final String CUD_TYPE = "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration";
|
||||
private static final String COMPILATIONRESULT_TYPE = "org.eclipse.jdt.internal.compiler.CompilationResult";
|
||||
|
||||
public static Method addProblemToCompilationResult;
|
||||
public static final Throwable problem;
|
||||
@@ -367,7 +368,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
|
||||
Throwable problem_ = null;
|
||||
Method m = null;
|
||||
try {
|
||||
m = EclipseAstProblemView.class.getMethod("addProblemToCompilationResult", Class.forName(CUD_TYPE), boolean.class, String.class, int.class, int.class);
|
||||
m = EclipseAstProblemView.class.getMethod("addProblemToCompilationResult", char[].class, Class.forName(COMPILATIONRESULT_TYPE), boolean.class, String.class, int.class, int.class);
|
||||
} catch (Throwable t) {
|
||||
// That's problematic, but as long as no local classes are used we don't actually need it.
|
||||
// Better fail on local classes than crash altogether.
|
||||
|
||||
@@ -3,7 +3,6 @@ package lombok.eclipse;
|
||||
|
||||
import org.eclipse.jdt.core.compiler.CategorizedProblem;
|
||||
import org.eclipse.jdt.internal.compiler.CompilationResult;
|
||||
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
|
||||
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
|
||||
import org.eclipse.jdt.internal.compiler.util.Util;
|
||||
@@ -13,14 +12,12 @@ public class EclipseAstProblemView {
|
||||
* Adds a problem to the provided CompilationResult object so that it will show up
|
||||
* in the Problems/Warnings view.
|
||||
*/
|
||||
public static void addProblemToCompilationResult(CompilationUnitDeclaration ast,
|
||||
public static void addProblemToCompilationResult(char[] fileNameArray, CompilationResult result,
|
||||
boolean isWarning, String message, int sourceStart, int sourceEnd) {
|
||||
if (ast.compilationResult == null) return;
|
||||
char[] fileNameArray = ast.getFileName();
|
||||
if (result == null) return;
|
||||
if (fileNameArray == null) fileNameArray = "(unknown).java".toCharArray();
|
||||
int lineNumber = 0;
|
||||
int columnNumber = 1;
|
||||
CompilationResult result = ast.compilationResult;
|
||||
int[] lineEnds = null;
|
||||
lineNumber = sourceStart >= 0
|
||||
? Util.getLineNumber(sourceStart, lineEnds = result.getLineSeparatorPositions(), 0, lineEnds.length-1)
|
||||
@@ -33,7 +30,7 @@ public class EclipseAstProblemView {
|
||||
fileNameArray, message, 0, new String[0],
|
||||
isWarning ? ProblemSeverities.Warning : ProblemSeverities.Error,
|
||||
sourceStart, sourceEnd, lineNumber, columnNumber);
|
||||
ast.compilationResult.record(ecProblem, null);
|
||||
result.record(ecProblem, null);
|
||||
}
|
||||
|
||||
private static class LombokProblem extends DefaultProblem {
|
||||
|
||||
@@ -144,7 +144,7 @@ public class TransformEclipseAST {
|
||||
try {
|
||||
String message = "Lombok can't parse this source: " + t.toString();
|
||||
|
||||
EclipseAST.addProblemToCompilationResult(ast, false, message, 0, 0);
|
||||
EclipseAST.addProblemToCompilationResult(ast.getFileName(), ast.compilationResult, false, message, 0, 0);
|
||||
t.printStackTrace();
|
||||
} catch (Throwable t2) {
|
||||
try {
|
||||
|
||||
@@ -142,7 +142,7 @@ public class EclipseHandlerUtil {
|
||||
} catch (NoClassDefFoundError e) { //standalone ecj does not jave Platform, ILog, IStatus, and friends.
|
||||
new TerminalLogger().error(message, bundleName, error);
|
||||
}
|
||||
if (cud != null) EclipseAST.addProblemToCompilationResult(cud, false, message + " - See error log.", 0, 0);
|
||||
if (cud != null) EclipseAST.addProblemToCompilationResult(cud.getFileName(), cud.compilationResult, false, message + " - See error log.", 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -267,7 +267,7 @@ public class EclipsePatcher extends Agent {
|
||||
.build());
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void patchPostCompileHookEclipse(ScriptManager sm) {
|
||||
sm.addScript(ScriptBuilder.wrapMethodCall()
|
||||
.target(new MethodTarget("org.eclipse.jdt.internal.core.builder.IncrementalImageBuilder", "writeClassFileContents"))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2012 The Project Lombok Authors.
|
||||
* Copyright (C) 2010-2013 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -329,19 +329,16 @@ public class PatchFixes {
|
||||
return newSimpleNames;
|
||||
}
|
||||
|
||||
public static byte[] runPostCompiler(byte[] bytes, String fileName) {
|
||||
if (System.getProperty("lombok.disablePostCompiler", null) != null) return bytes;
|
||||
public static byte[] runPostCompiler(byte[] bytes, String fileName) {
|
||||
byte[] transformed = PostCompiler.applyTransformations(bytes, fileName, DiagnosticsReceiver.CONSOLE);
|
||||
return transformed == null ? bytes : transformed;
|
||||
}
|
||||
|
||||
public static OutputStream runPostCompiler(OutputStream out) throws IOException {
|
||||
if (System.getProperty("lombok.disablePostCompiler", null) != null) return out;
|
||||
return PostCompiler.wrapOutputStream(out, "TEST", DiagnosticsReceiver.CONSOLE);
|
||||
}
|
||||
|
||||
public static BufferedOutputStream runPostCompiler(BufferedOutputStream out, String path, String name) throws IOException {
|
||||
if (System.getProperty("lombok.disablePostCompiler", null) != null) return out;
|
||||
String fileName = path + "/" + name;
|
||||
return new BufferedOutputStream(PostCompiler.wrapOutputStream(out, fileName, DiagnosticsReceiver.CONSOLE));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user