From 7bbb7cf3ca25cb8727a6ec226de1ed1fc5bf47e9 Mon Sep 17 00:00:00 2001
From: Reinier Zwitserloot <reinier@zwitserloot.com>
Date: Tue, 28 May 2013 13:03:54 +0200
Subject: Fixes for issue 470: VerifyErrors when using @SneakyThrows.

---
 .../bytecode/PreventNullAnalysisRemover.java       |   2 +-
 src/core/lombok/bytecode/SneakyThrowsRemover.java  | 115 ++++++++++++++++++++-
 2 files changed, 111 insertions(+), 6 deletions(-)

(limited to 'src/core/lombok/bytecode')

diff --git a/src/core/lombok/bytecode/PreventNullAnalysisRemover.java b/src/core/lombok/bytecode/PreventNullAnalysisRemover.java
index 3342eacb..751e691f 100644
--- a/src/core/lombok/bytecode/PreventNullAnalysisRemover.java
+++ b/src/core/lombok/bytecode/PreventNullAnalysisRemover.java
@@ -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();
 		
diff --git a/src/core/lombok/bytecode/SneakyThrowsRemover.java b/src/core/lombok/bytecode/SneakyThrowsRemover.java
index c54495d4..914c313a 100644
--- a/src/core/lombok/bytecode/SneakyThrowsRemover.java
+++ b/src/core/lombok/bytecode/SneakyThrowsRemover.java
@@ -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) {
-- 
cgit