aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/eclipse
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2012-08-10 18:06:13 +0200
committerReinier Zwitserloot <reinier@zwitserloot.com>2012-08-10 18:06:13 +0200
commit1be7da76012b246af24d0515d192bca85d65c823 (patch)
tree21d9675c00d812c6bbbf76edb80d38b16777740d /src/core/lombok/eclipse
parent70317c73841d3e83b4b8008b68bea95753a5275f (diff)
downloadlombok-1be7da76012b246af24d0515d192bca85d65c823.tar.gz
lombok-1be7da76012b246af24d0515d192bca85d65c823.tar.bz2
lombok-1be7da76012b246af24d0515d192bca85d65c823.zip
* Added priorities to handlers, along with implementation of the priority system for javac and ecj.
* @Value now makes the class itself final by default.
Diffstat (limited to 'src/core/lombok/eclipse')
-rw-r--r--src/core/lombok/eclipse/HandlerLibrary.java85
-rw-r--r--src/core/lombok/eclipse/TransformEclipseAST.java23
-rw-r--r--src/core/lombok/eclipse/handlers/HandleExtensionMethod.java4
-rw-r--r--src/core/lombok/eclipse/handlers/HandleFieldDefaults.java2
-rw-r--r--src/core/lombok/eclipse/handlers/HandlePrintAST.java2
-rw-r--r--src/core/lombok/eclipse/handlers/HandleVal.java2
-rw-r--r--src/core/lombok/eclipse/handlers/HandleValue.java12
7 files changed, 100 insertions, 30 deletions
diff --git a/src/core/lombok/eclipse/HandlerLibrary.java b/src/core/lombok/eclipse/HandlerLibrary.java
index 14102ba1..5f360f6f 100644
--- a/src/core/lombok/eclipse/HandlerLibrary.java
+++ b/src/core/lombok/eclipse/HandlerLibrary.java
@@ -28,17 +28,20 @@ import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
import java.util.WeakHashMap;
import lombok.Lombok;
import lombok.core.AnnotationValues;
-import lombok.core.PrintAST;
+import lombok.core.AnnotationValues.AnnotationValueDecodeFail;
+import lombok.core.HandlerPriority;
import lombok.core.SpiLoadUtil;
import lombok.core.TypeLibrary;
import lombok.core.TypeResolver;
-import lombok.core.AnnotationValues.AnnotationValueDecodeFail;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
@@ -59,13 +62,39 @@ public class HandlerLibrary {
private TypeLibrary typeLibrary = new TypeLibrary();
+ private static class VisitorContainer {
+ private final EclipseASTVisitor visitor;
+ private final long priority;
+ private final boolean deferUntilPostDiet;
+
+ VisitorContainer(EclipseASTVisitor visitor) {
+ this.visitor = visitor;
+ this.deferUntilPostDiet = visitor.getClass().isAnnotationPresent(DeferUntilPostDiet.class);
+ HandlerPriority hp = visitor.getClass().getAnnotation(HandlerPriority.class);
+ this.priority = hp == null ? 0L : (((long)hp.value()) << 32) + hp.subValue();
+ }
+
+ public boolean deferUntilPostDiet() {
+ return deferUntilPostDiet;
+ }
+
+ public long getPriority() {
+ return priority;
+ }
+ }
+
private static class AnnotationHandlerContainer<T extends Annotation> {
- private EclipseAnnotationHandler<T> handler;
- private Class<T> annotationClass;
+ private final EclipseAnnotationHandler<T> handler;
+ private final Class<T> annotationClass;
+ private final long priority;
+ private final boolean deferUntilPostDiet;
AnnotationHandlerContainer(EclipseAnnotationHandler<T> handler, Class<T> annotationClass) {
this.handler = handler;
this.annotationClass = annotationClass;
+ this.deferUntilPostDiet = handler.getClass().isAnnotationPresent(DeferUntilPostDiet.class);
+ HandlerPriority hp = handler.getClass().getAnnotation(HandlerPriority.class);
+ this.priority = hp == null ? 0L : (((long)hp.value()) << 32) + hp.subValue();
}
public void handle(org.eclipse.jdt.internal.compiler.ast.Annotation annotation,
@@ -81,14 +110,18 @@ public class HandlerLibrary {
}
public boolean deferUntilPostDiet() {
- return handler.getClass().isAnnotationPresent(DeferUntilPostDiet.class);
+ return deferUntilPostDiet;
+ }
+
+ public long getPriority() {
+ return priority;
}
}
private Map<String, AnnotationHandlerContainer<?>> annotationHandlers =
new HashMap<String, AnnotationHandlerContainer<?>>();
- private Collection<EclipseASTVisitor> visitorHandlers = new ArrayList<EclipseASTVisitor>();
+ private Collection<VisitorContainer> visitorHandlers = new ArrayList<VisitorContainer>();
/**
* Creates a new HandlerLibrary. Errors will be reported to the Eclipse Error log.
@@ -101,9 +134,24 @@ public class HandlerLibrary {
loadAnnotationHandlers(lib);
loadVisitorHandlers(lib);
+ lib.calculatePriorities();
+
return lib;
}
+ private SortedSet<Long> priorities;
+
+ public SortedSet<Long> getPriorities() {
+ return priorities;
+ }
+
+ private void calculatePriorities() {
+ SortedSet<Long> set = new TreeSet<Long>();
+ for (AnnotationHandlerContainer<?> container : annotationHandlers.values()) set.add(container.getPriority());
+ for (VisitorContainer container : visitorHandlers) set.add(container.getPriority());
+ this.priorities = Collections.unmodifiableSortedSet(set);
+ }
+
/** Uses SPI Discovery to find implementations of {@link EclipseAnnotationHandler}. */
@SuppressWarnings({"rawtypes", "unchecked"})
private static void loadAnnotationHandlers(HandlerLibrary lib) {
@@ -131,7 +179,7 @@ public class HandlerLibrary {
private static void loadVisitorHandlers(HandlerLibrary lib) {
try {
for (EclipseASTVisitor visitor : SpiLoadUtil.findServices(EclipseASTVisitor.class, EclipseASTVisitor.class.getClassLoader())) {
- lib.visitorHandlers.add(visitor);
+ lib.visitorHandlers.add(new VisitorContainer(visitor));
}
} catch (Throwable t) {
throw Lombok.sneakyThrow(t);
@@ -170,7 +218,7 @@ public class HandlerLibrary {
* @param annotationNode The Lombok AST Node representing the Annotation AST Node.
* @param annotation 'node.get()' - convenience parameter.
*/
- public void handleAnnotation(CompilationUnitDeclaration ast, EclipseNode annotationNode, org.eclipse.jdt.internal.compiler.ast.Annotation annotation, boolean skipPrintAst) {
+ public void handleAnnotation(CompilationUnitDeclaration ast, EclipseNode annotationNode, org.eclipse.jdt.internal.compiler.ast.Annotation annotation, long priority) {
String pkgName = annotationNode.getPackageDeclaration();
Collection<String> imports = annotationNode.getImportStatements();
@@ -179,11 +227,10 @@ public class HandlerLibrary {
if (rawType == null) return;
for (String fqn : resolver.findTypeMatches(annotationNode, typeLibrary, toQualifiedName(annotation.type.getTypeName()))) {
- boolean isPrintAST = fqn.equals(PrintAST.class.getName());
- if (isPrintAST == skipPrintAst) continue;
AnnotationHandlerContainer<?> container = annotationHandlers.get(fqn);
-
if (container == null) continue;
+ if (priority != container.getPriority()) continue;
+
if (!annotationNode.isCompleteParse() && container.deferUntilPostDiet()) {
if (needsHandling(annotation)) container.preHandle(annotation, annotationNode);
continue;
@@ -202,12 +249,16 @@ public class HandlerLibrary {
/**
* Will call all registered {@link EclipseASTVisitor} instances.
*/
- public void callASTVisitors(EclipseAST ast) {
- for (EclipseASTVisitor visitor : visitorHandlers) try {
- ast.traverse(visitor);
- } catch (Throwable t) {
- error((CompilationUnitDeclaration) ast.top().get(),
- String.format("Lombok visitor handler %s failed", visitor.getClass()), t);
+ public void callASTVisitors(EclipseAST ast, long priority, boolean isCompleteParse) {
+ for (VisitorContainer container : visitorHandlers) {
+ if (!isCompleteParse && container.deferUntilPostDiet()) continue;
+ if (priority != container.getPriority()) continue;
+ try {
+ ast.traverse(container.visitor);
+ } catch (Throwable t) {
+ error((CompilationUnitDeclaration) ast.top().get(),
+ String.format("Lombok visitor handler %s failed", container.visitor.getClass()), t);
+ }
}
}
}
diff --git a/src/core/lombok/eclipse/TransformEclipseAST.java b/src/core/lombok/eclipse/TransformEclipseAST.java
index 89248be1..63783734 100644
--- a/src/core/lombok/eclipse/TransformEclipseAST.java
+++ b/src/core/lombok/eclipse/TransformEclipseAST.java
@@ -165,41 +165,42 @@ public class TransformEclipseAST {
* then handles any PrintASTs.
*/
public void go() {
- ast.traverse(new AnnotationVisitor(true));
- handlers.callASTVisitors(ast);
- ast.traverse(new AnnotationVisitor(false));
+ for (Long d : handlers.getPriorities()) {
+ ast.traverse(new AnnotationVisitor(d));
+ handlers.callASTVisitors(ast, d, ast.isCompleteParse());
+ }
}
private static class AnnotationVisitor extends EclipseASTAdapter {
- private final boolean skipPrintAst;
+ private final long priority;
- public AnnotationVisitor(boolean skipAllButPrintAST) {
- this.skipPrintAst = skipAllButPrintAST;
+ public AnnotationVisitor(long priority) {
+ this.priority = priority;
}
@Override public void visitAnnotationOnField(FieldDeclaration field, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
- handlers.handleAnnotation(top, annotationNode, annotation, skipPrintAst);
+ handlers.handleAnnotation(top, annotationNode, annotation, priority);
}
@Override public void visitAnnotationOnMethodArgument(Argument arg, AbstractMethodDeclaration method, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
- handlers.handleAnnotation(top, annotationNode, annotation, skipPrintAst);
+ handlers.handleAnnotation(top, annotationNode, annotation, priority);
}
@Override public void visitAnnotationOnLocal(LocalDeclaration local, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
- handlers.handleAnnotation(top, annotationNode, annotation, skipPrintAst);
+ handlers.handleAnnotation(top, annotationNode, annotation, priority);
}
@Override public void visitAnnotationOnMethod(AbstractMethodDeclaration method, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
- handlers.handleAnnotation(top, annotationNode, annotation, skipPrintAst);
+ handlers.handleAnnotation(top, annotationNode, annotation, priority);
}
@Override public void visitAnnotationOnType(TypeDeclaration type, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
- handlers.handleAnnotation(top, annotationNode, annotation, skipPrintAst);
+ handlers.handleAnnotation(top, annotationNode, annotation, priority);
}
}
}
diff --git a/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java b/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java
index 30408118..3d30e8fe 100644
--- a/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java
+++ b/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java
@@ -26,13 +26,17 @@ import java.util.List;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.mangosdk.spi.ProviderFor;
import lombok.core.AnnotationValues;
+import lombok.core.HandlerPriority;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.experimental.ExtensionMethod;
// This handler just does some additional error checking; the real work is done in the agent.
+@ProviderFor(EclipseAnnotationHandler.class)
+@HandlerPriority(66560) // 2^16 + 2^10; we must run AFTER HandleVal which is at 2^16
public class HandleExtensionMethod extends EclipseAnnotationHandler<ExtensionMethod> {
@Override public void handle(AnnotationValues<ExtensionMethod> annotation, Annotation ast, EclipseNode annotationNode) {
TypeDeclaration typeDecl = null;
diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
index e1dd8460..2cdfdd4d 100644
--- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
@@ -25,6 +25,7 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import lombok.AccessLevel;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
+import lombok.core.HandlerPriority;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.experimental.FieldDefaults;
@@ -42,6 +43,7 @@ import org.mangosdk.spi.ProviderFor;
* Handles the {@code lombok.FieldDefaults} annotation for eclipse.
*/
@ProviderFor(EclipseAnnotationHandler.class)
+@HandlerPriority(-512) //-2^9; to ensure @Setter and such pick up on messing with the fields' 'final' state, run earlier.
public class HandleFieldDefaults extends EclipseAnnotationHandler<FieldDefaults> {
public boolean generateFieldDefaultsForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) {
if (checkForTypeLevelFieldDefaults) {
diff --git a/src/core/lombok/eclipse/handlers/HandlePrintAST.java b/src/core/lombok/eclipse/handlers/HandlePrintAST.java
index a9678f0c..da6fa2a2 100644
--- a/src/core/lombok/eclipse/handlers/HandlePrintAST.java
+++ b/src/core/lombok/eclipse/handlers/HandlePrintAST.java
@@ -30,6 +30,7 @@ import org.mangosdk.spi.ProviderFor;
import lombok.Lombok;
import lombok.core.AnnotationValues;
+import lombok.core.HandlerPriority;
import lombok.core.PrintAST;
import lombok.eclipse.DeferUntilPostDiet;
import lombok.eclipse.EclipseASTVisitor;
@@ -41,6 +42,7 @@ import lombok.eclipse.EclipseNode;
*/
@ProviderFor(EclipseAnnotationHandler.class)
@DeferUntilPostDiet
+@HandlerPriority(536870912) // 2^29; this handler is customarily run at the very end.
public class HandlePrintAST extends EclipseAnnotationHandler<PrintAST> {
public void handle(AnnotationValues<PrintAST> annotation, Annotation ast, EclipseNode annotationNode) {
PrintStream stream = System.out;
diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java
index 56b3effd..e7849952 100644
--- a/src/core/lombok/eclipse/handlers/HandleVal.java
+++ b/src/core/lombok/eclipse/handlers/HandleVal.java
@@ -22,6 +22,7 @@
package lombok.eclipse.handlers;
import lombok.val;
+import lombok.core.HandlerPriority;
import lombok.eclipse.DeferUntilPostDiet;
import lombok.eclipse.EclipseASTAdapter;
import lombok.eclipse.EclipseASTVisitor;
@@ -38,6 +39,7 @@ import org.mangosdk.spi.ProviderFor;
*/
@ProviderFor(EclipseASTVisitor.class)
@DeferUntilPostDiet
+@HandlerPriority(65536) // 2^16; resolution needs to work, so if the RHS expression is i.e. a call to a generated getter, we have to run after that getter has been generated.
public class HandleVal extends EclipseASTAdapter {
@Override public void visitLocal(EclipseNode localNode, LocalDeclaration local) {
if (!EclipseHandlerUtil.typeMatches(val.class, localNode, local.type)) return;
diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java
index 9b3edabf..a1eb24ff 100644
--- a/src/core/lombok/eclipse/handlers/HandleValue.java
+++ b/src/core/lombok/eclipse/handlers/HandleValue.java
@@ -21,11 +21,14 @@
*/
package lombok.eclipse.handlers;
+import static lombok.eclipse.handlers.EclipseHandlerUtil.hasAnnotation;
import lombok.AccessLevel;
-import lombok.experimental.Value;
import lombok.core.AnnotationValues;
+import lombok.core.HandlerPriority;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
+import lombok.experimental.NonFinal;
+import lombok.experimental.Value;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
@@ -36,6 +39,7 @@ import org.mangosdk.spi.ProviderFor;
* Handles the {@code lombok.Value} annotation for eclipse.
*/
@ProviderFor(EclipseAnnotationHandler.class)
+@HandlerPriority(-512) //-2^9; to ensure @EqualsAndHashCode and such pick up on this handler making the class final and messing with the fields' access levels, run earlier.
public class HandleValue extends EclipseAnnotationHandler<Value> {
public void handle(AnnotationValues<Value> annotation, Annotation ast, EclipseNode annotationNode) {
Value ann = annotation.getInstance();
@@ -52,6 +56,11 @@ public class HandleValue extends EclipseAnnotationHandler<Value> {
return;
}
+ // Make class final.
+ if (!hasAnnotation(NonFinal.class, typeNode)) typeDecl.modifiers |= ClassFileConstants.AccFinal;
+
+ new HandleFieldDefaults().generateFieldDefaultsForType(typeNode, annotationNode, AccessLevel.PRIVATE, true, true);
+
//Careful: Generate the public static constructor (if there is one) LAST, so that any attempt to
//'find callers' on the annotation node will find callers of the constructor, which is by far the
//most useful of the many methods built by @Value. This trick won't work for the non-static constructor,
@@ -62,7 +71,6 @@ public class HandleValue extends EclipseAnnotationHandler<Value> {
new HandleWither().generateWitherForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode);
new HandleToString().generateToStringForType(typeNode, annotationNode);
- new HandleFieldDefaults().generateFieldDefaultsForType(typeNode, annotationNode, AccessLevel.PRIVATE, true, true);
new HandleConstructor().generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), true, ast);
}
}