diff options
author | Reinier Zwitserloot <reinier@zwitserloot.com> | 2012-08-10 18:06:13 +0200 |
---|---|---|
committer | Reinier Zwitserloot <reinier@zwitserloot.com> | 2012-08-10 18:06:13 +0200 |
commit | 1be7da76012b246af24d0515d192bca85d65c823 (patch) | |
tree | 21d9675c00d812c6bbbf76edb80d38b16777740d /src/core/lombok/eclipse | |
parent | 70317c73841d3e83b4b8008b68bea95753a5275f (diff) | |
download | lombok-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')
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); } } |