Post Compiler now works, including the sneaky throws remover. Also added a lombok app for it. Not yet in eclipse, though

This commit is contained in:
Roel Spilker committed 2010-08-03 03:41:07 +02:00
1 parent 40466c3e2d
commit 57bb88a769
4 files changed
+222 -31

No files matched your search

@@ -0,0 +1,152 @@
/*
* Copyright © 2010 Reinier Zwitserloot and Roel Spilker.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.bytecode;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import lombok.core.DiagnosticsReceiver;
import lombok.core.LombokApp;
import lombok.core.PostCompiler;
import org.mangosdk.spi.ProviderFor;
import com.zwitserloot.cmdreader.CmdReader;
import com.zwitserloot.cmdreader.Description;
import com.zwitserloot.cmdreader.InvalidCommandLineException;
import com.zwitserloot.cmdreader.Mandatory;
import com.zwitserloot.cmdreader.Sequential;
import com.zwitserloot.cmdreader.Shorthand;
@ProviderFor(LombokApp.class)
public class PostCompilerApp implements LombokApp {
@Override public List<String> getAppAliases() {
return Arrays.asList("post", "postcompile");
}
@Override public String getAppDescription() {
return "Runs registered post compiler handlers to against existing class files, modifying them in the process.";
}
@Override public String getAppName() {
return "post-compile";
}
public static class CmdArgs {
@Sequential
@Mandatory
@Description("paths to class files to be converted. If a directory is named, all files (recursively) in that directory will be converted.")
private List<String> classFiles = new ArrayList<String>();
@Shorthand("v")
@Description("Prints lots of status information as the post compiler runs")
boolean verbose = false;
@Shorthand({"h", "?"})
@Description("Shows this help text")
boolean help = false;
}
@Override public int runApp(List<String> raw) throws Exception {
CmdReader<CmdArgs> reader = CmdReader.of(CmdArgs.class);
CmdArgs args;
try {
args = reader.make(raw.toArray(new String[0]));
if (args.help) {
System.out.println(reader.generateCommandLineHelp("java -jar lombok.jar post-compile"));
return 0;
}
} catch (InvalidCommandLineException e) {
System.err.println(e.getMessage());
System.err.println(reader.generateCommandLineHelp("java -jar lombok.jar post-compile"));
return 1;
}
List<File> filesToProcess = new ArrayList<File>();
for (String f : args.classFiles) addFiles(filesToProcess, f);
int filesVisited = 0, filesTouched = 0;
for (File file : filesToProcess) {
if (!file.exists() || !file.isFile()) {
System.out.printf("Cannot find file '%s'\n", file);
continue;
}
filesVisited++;
if (args.verbose) System.out.println("Processing " + file.getAbsolutePath());
byte[] original = readFile(file);
byte[] clone = original.clone();
byte[] transformed = PostCompiler.applyTransformations(clone, file.toString(), DiagnosticsReceiver.CONSOLE);
if (clone != transformed && !Arrays.equals(clone, transformed)) {
filesTouched++;
if (args.verbose) System.out.println("Rewriting " + file.getAbsolutePath());
writeFile(file, transformed);
}
}
if (args.verbose) {
System.out.printf("Total files visited: %d total files changed: %d\n", filesVisited, filesTouched);
}
return filesVisited == 0 ? 1 : 0;
}
private void addFiles(List<File> filesToProcess, String f) {
File file = new File(f);
if (file.isDirectory()) {
addRecursively(filesToProcess, file);
} else {
filesToProcess.add(file);
}
}
private void addRecursively(List<File> filesToProcess, File file) {
for (File f : file.listFiles()) {
if (f.isDirectory()) addRecursively(filesToProcess, f);
else if (f.getName().endsWith(".class")) filesToProcess.add(f);
}
}
private static byte[] readFile(File file) throws IOException {
byte[] buffer = new byte[1024];
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
FileInputStream fileInputStream = new FileInputStream(file);
while (true) {
int read = fileInputStream.read(buffer);
if (read == -1) break;
bytes.write(buffer, 0, read);
}
fileInputStream.close();
return bytes.toByteArray();
}
private static void writeFile(File file, byte[] transformed) throws IOException {
FileOutputStream out = new FileOutputStream(file);
out.write(transformed);
out.close();
}
}
@@ -1,5 +1,28 @@
/*
* Copyright © 2010 Reinier Zwitserloot and Roel Spilker.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.bytecode;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.core.DiagnosticsReceiver;
import lombok.core.PostCompilerTransformation;
@@ -51,30 +74,33 @@ public class SneakyThrowsRemover implements PostCompilerTransformation {
ClassReader reader = new ClassReader(fixedByteCode);
ClassWriter writer = new FixedClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
final AtomicBoolean changesMade = new AtomicBoolean();
class SneakyThrowsRemoverVisitor extends MethodAdapter {
SneakyThrowsRemoverVisitor(MethodVisitor mv) {
super(mv);
}
@Override public void visitMethodInsn(int opcode, String owner, String name, String desc) {
boolean hit = true;
if (hit && opcode != Opcodes.INVOKESTATIC) hit = false;
if (hit && !"sneakyThrow".equals(name)) hit = false;
if (hit && !"lombok/Lombok".equals(owner)) hit = false;
if (hit && !"(Ljava/lang/Throwable;)Ljava/lang/RuntimeException;".equals(desc)) hit = false;
if (hit) {
changesMade.set(true);
super.visitInsn(Opcodes.ATHROW);
} else {
super.visitMethodInsn(opcode, owner, name, desc);
}
}
}
reader.accept(new ClassAdapter(writer) {
@Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new SneakyThrowsRemoverVisitor(super.visitMethod(access, name, desc, signature, exceptions));
}
}, 0);
return writer.toByteArray();
}
private class SneakyThrowsRemoverVisitor extends MethodAdapter {
SneakyThrowsRemoverVisitor(MethodVisitor mv) {
super(mv);
}
@Override public void visitMethodInsn(int opcode, String owner, String name, String desc) {
boolean hit = true;
if (hit && opcode != Opcodes.INVOKESTATIC) hit = false;
if (hit && !"sneakyThrow".equals(name)) hit = false;
if (hit && !"lombok/Lombok".equals(owner)) hit = false;
if (hit && !"(Ljava/lang/Throwable;)Ljava/lang/RuntimeException;".equals(desc)) hit = false;
if (hit) {
super.visitInsn(Opcodes.ATHROW);
} else {
super.visitMethodInsn(opcode, owner, name, desc);
}
}
return changesMade.get() ? writer.toByteArray() : null;
}
}
+3 -11
View File
@@ -22,8 +22,7 @@
package lombok.core;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Collections;
import java.util.List;
public final class PostCompiler {
@@ -49,17 +48,10 @@ public final class PostCompiler {
private static synchronized void init(DiagnosticsReceiver diagnostics) {
if (transformations != null) return;
transformations = new ArrayList<PostCompilerTransformation>();
try {
Iterator<PostCompilerTransformation> discovered = SpiLoadUtil.findServices(PostCompilerTransformation.class).iterator();
while (discovered.hasNext()) {
try {
transformations.add(discovered.next());
} catch (Exception e) {
diagnostics.addWarning("Error during loading post-compile transformers: " + e.getMessage());
}
}
transformations = SpiLoadUtil.readAllFromIterator(SpiLoadUtil.findServices(PostCompilerTransformation.class, PostCompilerTransformation.class.getClassLoader()));
} catch (IOException e) {
transformations = Collections.emptyList();
diagnostics.addWarning("Could not load post-compile transformers: " + e.getMessage());
}
}
@@ -1,3 +1,24 @@
/*
* Copyright © 2010 Reinier Zwitserloot and Roel Spilker.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.core;
public interface PostCompilerTransformation {