aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@tipit.to>2009-11-25 07:32:49 +0100
committerReinier Zwitserloot <reinier@tipit.to>2009-11-25 07:32:49 +0100
commit1a0e611a9c5e1ee518670647ce1a44beae559b44 (patch)
treee5ef8f671bc6688f486e874d4e2e1a7813e4f0b2 /src/core/lombok/eclipse/handlers/HandleSneakyThrows.java
parent7fd947ea40c25dad9ee543ebc4b92de9a2e05efc (diff)
downloadlombok-1a0e611a9c5e1ee518670647ce1a44beae559b44.tar.gz
lombok-1a0e611a9c5e1ee518670647ce1a44beae559b44.tar.bz2
lombok-1a0e611a9c5e1ee518670647ce1a44beae559b44.zip
Refactored the source folders.
Diffstat (limited to 'src/core/lombok/eclipse/handlers/HandleSneakyThrows.java')
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSneakyThrows.java224
1 files changed, 224 insertions, 0 deletions
diff --git a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java
new file mode 100644
index 00000000..38f22b2a
--- /dev/null
+++ b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright © 2009 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.eclipse.handlers;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import lombok.SneakyThrows;
+import lombok.core.AnnotationValues;
+import lombok.eclipse.Eclipse;
+import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.EclipseNode;
+
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
+import org.eclipse.jdt.internal.compiler.ast.Block;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
+import org.eclipse.jdt.internal.compiler.ast.MessageSend;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.Statement;
+import org.eclipse.jdt.internal.compiler.ast.ThrowStatement;
+import org.eclipse.jdt.internal.compiler.ast.TryStatement;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.mangosdk.spi.ProviderFor;
+
+/**
+ * Handles the {@code lombok.HandleSneakyThrows} annotation for eclipse.
+ */
+@ProviderFor(EclipseAnnotationHandler.class)
+public class HandleSneakyThrows implements EclipseAnnotationHandler<SneakyThrows> {
+ private static class DeclaredException {
+ final String exceptionName;
+ final ASTNode node;
+
+ DeclaredException(String exceptionName, ASTNode node) {
+ this.exceptionName = exceptionName;
+ this.node = node;
+ }
+
+ public long getPos() {
+ return (long)node.sourceStart << 32 | node.sourceEnd;
+ }
+ }
+
+ @Override public boolean handle(AnnotationValues<SneakyThrows> annotation, Annotation source, EclipseNode annotationNode) {
+ List<String> exceptionNames = annotation.getRawExpressions("value");
+ List<DeclaredException> exceptions = new ArrayList<DeclaredException>();
+
+ MemberValuePair[] memberValuePairs = source.memberValuePairs();
+ if (memberValuePairs == null || memberValuePairs.length == 0) {
+ exceptions.add(new DeclaredException("java.lang.Throwable", source));
+ } else {
+ Expression arrayOrSingle = memberValuePairs[0].value;
+ final Expression[] exceptionNameNodes;
+ if (arrayOrSingle instanceof ArrayInitializer) {
+ exceptionNameNodes = ((ArrayInitializer)arrayOrSingle).expressions;
+ } else exceptionNameNodes = new Expression[] { arrayOrSingle };
+
+ if (exceptionNames.size() != exceptionNameNodes.length) {
+ annotationNode.addError(
+ "LOMBOK BUG: The number of exception classes in the annotation isn't the same pre- and post- guessing.");
+ }
+
+ int idx = 0;
+ for (String exceptionName : exceptionNames) {
+ if (exceptionName.endsWith(".class")) exceptionName = exceptionName.substring(0, exceptionName.length() - 6);
+ exceptions.add(new DeclaredException(exceptionName, exceptionNameNodes[idx++]));
+ }
+ }
+
+
+ EclipseNode owner = annotationNode.up();
+ switch (owner.getKind()) {
+// case FIELD:
+// return handleField(annotationNode, (FieldDeclaration)owner.get(), exceptions);
+ case METHOD:
+ return handleMethod(annotationNode, (AbstractMethodDeclaration)owner.get(), exceptions);
+ default:
+ annotationNode.addError("@SneakyThrows is legal only on methods and constructors.");
+ return true;
+ }
+ }
+
+// private boolean handleField(Node annotation, FieldDeclaration field, List<DeclaredException> exceptions) {
+// if (field.initialization == null) {
+// annotation.addError("@SneakyThrows can only be used on fields with an initialization statement.");
+// return true;
+// }
+//
+// Expression expression = field.initialization;
+// Statement[] content = new Statement[] {new Assignment(
+// new SingleNameReference(field.name, 0), expression, 0)};
+// field.initialization = null;
+//
+// for (DeclaredException exception : exceptions) {
+// content = new Statement[] { buildTryCatchBlock(content, exception) };
+// }
+//
+// Block block = new Block(0);
+// block.statements = content;
+//
+// Node typeNode = annotation.up().up();
+//
+// Initializer initializer = new Initializer(block, field.modifiers & Modifier.STATIC);
+// initializer.sourceStart = expression.sourceStart;
+// initializer.sourceEnd = expression.sourceEnd;
+// initializer.declarationSourceStart = expression.sourceStart;
+// initializer.declarationSourceEnd = expression.sourceEnd;
+// injectField(typeNode, initializer);
+//
+// typeNode.rebuild();
+//
+// return true;
+// }
+
+ private boolean handleMethod(EclipseNode annotation, AbstractMethodDeclaration method, List<DeclaredException> exceptions) {
+ if (method.isAbstract()) {
+ annotation.addError("@SneakyThrows can only be used on concrete methods.");
+ return true;
+ }
+
+ if (method.statements == null) return false;
+
+ Statement[] contents = method.statements;
+
+ for (DeclaredException exception : exceptions) {
+ contents = new Statement[] { buildTryCatchBlock(contents, exception, exception.node) };
+ }
+
+ method.statements = contents;
+ annotation.up().rebuild();
+
+ return true;
+ }
+
+ private Statement buildTryCatchBlock(Statement[] contents, DeclaredException exception, ASTNode source) {
+ long p = exception.getPos();
+ int pS = (int)(p >> 32), pE = (int)p;
+
+ TryStatement tryStatement = new TryStatement();
+ Eclipse.setGeneratedBy(tryStatement, source);
+ tryStatement.tryBlock = new Block(0);
+ tryStatement.tryBlock.sourceStart = pS; tryStatement.tryBlock.sourceEnd = pE;
+ Eclipse.setGeneratedBy(tryStatement.tryBlock, source);
+ tryStatement.tryBlock.statements = contents;
+ TypeReference typeReference;
+ if (exception.exceptionName.indexOf('.') == -1) {
+ typeReference = new SingleTypeReference(exception.exceptionName.toCharArray(), p);
+ typeReference.statementEnd = pE;
+ } else {
+ String[] x = exception.exceptionName.split("\\.");
+ char[][] elems = new char[x.length][];
+ long[] poss = new long[x.length];
+ int start = pS;
+ for (int i = 0; i < x.length; i++) {
+ elems[i] = x[i].trim().toCharArray();
+ int end = start + x[i].length();
+ poss[i] = (long)start << 32 | end;
+ start = end + 1;
+ }
+ typeReference = new QualifiedTypeReference(elems, poss);
+ }
+ Eclipse.setGeneratedBy(typeReference, source);
+
+ Argument catchArg = new Argument("$ex".toCharArray(), p, typeReference, Modifier.FINAL);
+ Eclipse.setGeneratedBy(catchArg, source);
+ catchArg.declarationSourceEnd = catchArg.declarationEnd = catchArg.sourceEnd = pE;
+ catchArg.declarationSourceStart = catchArg.modifiersSourceStart = catchArg.sourceStart = pS;
+
+ tryStatement.catchArguments = new Argument[] { catchArg };
+
+ MessageSend sneakyThrowStatement = new MessageSend();
+ Eclipse.setGeneratedBy(sneakyThrowStatement, source);
+ sneakyThrowStatement.receiver = new QualifiedNameReference(new char[][] { "lombok".toCharArray(), "Lombok".toCharArray() }, new long[] { p, p }, pS, pE);
+ Eclipse.setGeneratedBy(sneakyThrowStatement.receiver, source);
+ sneakyThrowStatement.receiver.statementEnd = pE;
+ sneakyThrowStatement.selector = "sneakyThrow".toCharArray();
+ SingleNameReference exRef = new SingleNameReference("$ex".toCharArray(), p);
+ Eclipse.setGeneratedBy(exRef, source);
+ exRef.statementEnd = pE;
+ sneakyThrowStatement.arguments = new Expression[] { exRef };
+ sneakyThrowStatement.nameSourcePosition = p;
+ sneakyThrowStatement.sourceStart = pS;
+ sneakyThrowStatement.sourceEnd = sneakyThrowStatement.statementEnd = pE;
+ Statement rethrowStatement = new ThrowStatement(sneakyThrowStatement, pS, pE);
+ Eclipse.setGeneratedBy(rethrowStatement, source);
+ Block block = new Block(0);
+ block.sourceStart = pS;
+ block.sourceEnd = pE;
+ Eclipse.setGeneratedBy(block, source);
+ block.statements = new Statement[] { rethrowStatement };
+ tryStatement.catchBlocks = new Block[] { block };
+ tryStatement.sourceStart = pS;
+ tryStatement.sourceEnd = pE;
+ return tryStatement;
+ }
+}