mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 22:16:11 +00:00
* Added priorities to handlers, along with implementation of the priority system for javac and ecj.
* @Value now makes the class itself final by default.
This commit is contained in:
1 parent
70317c7384
commit
1be7da7601
20 files changed
+274
-174
No files matched your search
@@ -0,0 +1,18 @@
|
||||
package lombok.core;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface HandlerPriority {
|
||||
int value();
|
||||
|
||||
/**
|
||||
* This can be used to differentiate 2 handlers with the same value to be at a different handler priority anyway.
|
||||
* <strong>DO NOT USE THIS</strong> unless someone has been crowding out the numbers and there's no room left.
|
||||
*/
|
||||
int subValue() default 0;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -35,12 +35,14 @@ import java.lang.annotation.Target;
|
||||
* <li>Generates withers for all fields (except final fields that are initialized in the field declaration itself)
|
||||
* <li>Generates a constructor for each argument
|
||||
* <li>Adds {@code private} and {@code final} to each field.
|
||||
* <li>Makes the class itself final.
|
||||
* </ul>
|
||||
*
|
||||
* In other words, {@code @Value} is a shorthand for {@code @Getter @Wither @FieldDefaults(makeFinal=true,level=AccessLevel.PRIVATE) @EqualsAndHashCode @ToString @AllArgsConstructor}.
|
||||
* In other words, {@code @Value} is a shorthand for:<br />
|
||||
* {@code final @Getter @Wither @FieldDefaults(makeFinal=true,level=AccessLevel.PRIVATE) @EqualsAndHashCode @ToString @AllArgsConstructor}.
|
||||
* <p>
|
||||
* If any method to be generated already exists (in name - the return type or parameters are not relevant), then
|
||||
* that method will not be generated by the Data annotation.
|
||||
* If any method to be generated already exists (in name and parameter c ount - the return type or parameter types are not relevant), then
|
||||
* that method will not be generated by the Value annotation.
|
||||
* <p>
|
||||
* The generated constructor will have 1 parameter for each field. The generated toString will print all fields,
|
||||
* while the generated hashCode and equals take into account all non-transient fields.<br>
|
||||
|
||||
@@ -25,14 +25,17 @@ 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 javax.annotation.processing.Messager;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import lombok.core.PrintAST;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.core.SpiLoadUtil;
|
||||
import lombok.core.TypeLibrary;
|
||||
import lombok.core.TypeResolver;
|
||||
@@ -52,9 +55,8 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
public class HandlerLibrary {
|
||||
private final TypeLibrary typeLibrary = new TypeLibrary();
|
||||
private final Map<String, AnnotationHandlerContainer<?>> annotationHandlers = new HashMap<String, AnnotationHandlerContainer<?>>();
|
||||
private final Collection<JavacASTVisitor> visitorHandlers = new ArrayList<JavacASTVisitor>();
|
||||
private final Collection<VisitorContainer> visitorHandlers = new ArrayList<VisitorContainer>();
|
||||
private final Messager messager;
|
||||
private int phase = 0;
|
||||
|
||||
/**
|
||||
* Creates a new HandlerLibrary that will report any problems or errors to the provided messager.
|
||||
@@ -64,22 +66,53 @@ public class HandlerLibrary {
|
||||
this.messager = messager;
|
||||
}
|
||||
|
||||
private static class VisitorContainer {
|
||||
private final JavacASTVisitor visitor;
|
||||
private final long priority;
|
||||
|
||||
VisitorContainer(JavacASTVisitor visitor) {
|
||||
this.visitor = visitor;
|
||||
HandlerPriority hp = visitor.getClass().getAnnotation(HandlerPriority.class);
|
||||
this.priority = hp == null ? 0L : (((long)hp.value()) << 32) + hp.subValue();
|
||||
}
|
||||
|
||||
public long getPriority() {
|
||||
return priority;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AnnotationHandlerContainer<T extends Annotation> {
|
||||
private JavacAnnotationHandler<T> handler;
|
||||
private Class<T> annotationClass;
|
||||
private final JavacAnnotationHandler<T> handler;
|
||||
private final Class<T> annotationClass;
|
||||
private final long priority;
|
||||
|
||||
AnnotationHandlerContainer(JavacAnnotationHandler<T> handler, Class<T> annotationClass) {
|
||||
this.handler = handler;
|
||||
this.annotationClass = annotationClass;
|
||||
}
|
||||
|
||||
public boolean isResolutionBased() {
|
||||
return handler.getClass().isAnnotationPresent(ResolutionBased.class);
|
||||
HandlerPriority hp = handler.getClass().getAnnotation(HandlerPriority.class);
|
||||
this.priority = hp == null ? 0L : (((long)hp.value()) << 32) + hp.subValue();
|
||||
}
|
||||
|
||||
public void handle(final JavacNode node) {
|
||||
handler.handle(JavacHandlerUtil.createAnnotation(annotationClass, node), (JCAnnotation)node.get(), node);
|
||||
}
|
||||
|
||||
public long getPriority() {
|
||||
return priority;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,6 +130,8 @@ public class HandlerLibrary {
|
||||
System.err.println("Lombok isn't running due to misconfigured SPI files: " + e);
|
||||
}
|
||||
|
||||
library.calculatePriorities();
|
||||
|
||||
return library;
|
||||
}
|
||||
|
||||
@@ -120,7 +155,7 @@ public class HandlerLibrary {
|
||||
private static void loadVisitorHandlers(HandlerLibrary lib) throws IOException {
|
||||
//No, that seemingly superfluous reference to JavacASTVisitor's classloader is not in fact superfluous!
|
||||
for (JavacASTVisitor visitor : SpiLoadUtil.findServices(JavacASTVisitor.class, JavacASTVisitor.class.getClassLoader())) {
|
||||
lib.visitorHandlers.add(visitor);
|
||||
lib.visitorHandlers.add(new VisitorContainer(visitor));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,24 +206,15 @@ public class HandlerLibrary {
|
||||
* @param node The Lombok AST Node representing the Annotation AST Node.
|
||||
* @param annotation 'node.get()' - convenience parameter.
|
||||
*/
|
||||
public void handleAnnotation(JCCompilationUnit unit, JavacNode node, JCAnnotation annotation) {
|
||||
public void handleAnnotation(JCCompilationUnit unit, JavacNode node, JCAnnotation annotation, long priority) {
|
||||
TypeResolver resolver = new TypeResolver(node.getPackageDeclaration(), node.getImportStatements());
|
||||
String rawType = annotation.annotationType.toString();
|
||||
for (String fqn : resolver.findTypeMatches(node, typeLibrary, rawType)) {
|
||||
boolean isPrintAST = fqn.equals(PrintAST.class.getName());
|
||||
if (isPrintAST && phase != 2) continue;
|
||||
if (!isPrintAST && phase == 2) continue;
|
||||
AnnotationHandlerContainer<?> container = annotationHandlers.get(fqn);
|
||||
if (container == null) continue;
|
||||
|
||||
try {
|
||||
if (container.isResolutionBased() && phase == 1) {
|
||||
if (checkAndSetHandled(annotation)) container.handle(node);
|
||||
}
|
||||
if (!container.isResolutionBased() && phase == 0) {
|
||||
if (checkAndSetHandled(annotation)) container.handle(node);
|
||||
}
|
||||
if (container.annotationClass == PrintAST.class && phase == 2) {
|
||||
if (container.getPriority() == priority) {
|
||||
if (checkAndSetHandled(annotation)) container.handle(node);
|
||||
}
|
||||
} catch (AnnotationValueDecodeFail fail) {
|
||||
@@ -204,29 +230,11 @@ public class HandlerLibrary {
|
||||
/**
|
||||
* Will call all registered {@link JavacASTVisitor} instances.
|
||||
*/
|
||||
public void callASTVisitors(JavacAST ast) {
|
||||
for (JavacASTVisitor visitor : visitorHandlers) try {
|
||||
boolean isResolutionBased = visitor.getClass().isAnnotationPresent(ResolutionBased.class);
|
||||
if (!isResolutionBased && phase == 0) ast.traverse(visitor);
|
||||
if (isResolutionBased && phase == 1) ast.traverse(visitor);
|
||||
public void callASTVisitors(JavacAST ast, long priority) {
|
||||
for (VisitorContainer container : visitorHandlers) try {
|
||||
if (container.getPriority() == priority) ast.traverse(container.visitor);
|
||||
} catch (Throwable t) {
|
||||
javacError(String.format("Lombok visitor handler %s failed", visitor.getClass()), t);
|
||||
javacError(String.format("Lombok visitor handler %s failed", container.visitor.getClass()), t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lombok does not currently support triggering annotations in a specified order; the order is essentially
|
||||
* random right now. As a temporary hack we've identified 3 important phases.
|
||||
*/
|
||||
public void setPreResolutionPhase() {
|
||||
phase = 0;
|
||||
}
|
||||
|
||||
public void setPostResolutionPhase() {
|
||||
phase = 1;
|
||||
}
|
||||
|
||||
public void setPrintASTPhase() {
|
||||
phase = 2;
|
||||
}
|
||||
}
|
||||
@@ -22,10 +22,10 @@
|
||||
package lombok.javac;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.annotation.processing.Messager;
|
||||
|
||||
|
||||
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
@@ -43,7 +43,11 @@ public class JavacTransformer {
|
||||
this.handlers = HandlerLibrary.load(messager);
|
||||
}
|
||||
|
||||
public void transform(boolean postResolution, Context context, java.util.List<JCCompilationUnit> compilationUnitsRaw) {
|
||||
public SortedSet<Long> getPriorities() {
|
||||
return handlers.getPriorities();
|
||||
}
|
||||
|
||||
public void transform(long priority, Context context, java.util.List<JCCompilationUnit> compilationUnitsRaw) {
|
||||
List<JCCompilationUnit> compilationUnits;
|
||||
if (compilationUnitsRaw instanceof List<?>) {
|
||||
compilationUnits = (List<JCCompilationUnit>)compilationUnitsRaw;
|
||||
@@ -58,54 +62,44 @@ public class JavacTransformer {
|
||||
|
||||
for (JCCompilationUnit unit : compilationUnits) asts.add(new JavacAST(messager, context, unit));
|
||||
|
||||
if (!postResolution) {
|
||||
handlers.setPreResolutionPhase();
|
||||
for (JavacAST ast : asts) {
|
||||
ast.traverse(new AnnotationVisitor());
|
||||
handlers.callASTVisitors(ast);
|
||||
}
|
||||
}
|
||||
|
||||
if (postResolution) {
|
||||
handlers.setPostResolutionPhase();
|
||||
for (JavacAST ast : asts) {
|
||||
ast.traverse(new AnnotationVisitor());
|
||||
handlers.callASTVisitors(ast);
|
||||
}
|
||||
|
||||
handlers.setPrintASTPhase();
|
||||
for (JavacAST ast : asts) {
|
||||
ast.traverse(new AnnotationVisitor());
|
||||
}
|
||||
for (JavacAST ast : asts) {
|
||||
ast.traverse(new AnnotationVisitor(priority));
|
||||
handlers.callASTVisitors(ast, priority);
|
||||
}
|
||||
|
||||
for (JavacAST ast : asts) if (ast.isChanged()) LombokOptions.markChanged(context, (JCCompilationUnit) ast.top().get());
|
||||
}
|
||||
|
||||
private class AnnotationVisitor extends JavacASTAdapter {
|
||||
private final long priority;
|
||||
|
||||
AnnotationVisitor(long priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
@Override public void visitAnnotationOnType(JCClassDecl type, JavacNode annotationNode, JCAnnotation annotation) {
|
||||
JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get();
|
||||
handlers.handleAnnotation(top, annotationNode, annotation);
|
||||
handlers.handleAnnotation(top, annotationNode, annotation, priority);
|
||||
}
|
||||
|
||||
@Override public void visitAnnotationOnField(JCVariableDecl field, JavacNode annotationNode, JCAnnotation annotation) {
|
||||
JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get();
|
||||
handlers.handleAnnotation(top, annotationNode, annotation);
|
||||
handlers.handleAnnotation(top, annotationNode, annotation, priority);
|
||||
}
|
||||
|
||||
@Override public void visitAnnotationOnMethod(JCMethodDecl method, JavacNode annotationNode, JCAnnotation annotation) {
|
||||
JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get();
|
||||
handlers.handleAnnotation(top, annotationNode, annotation);
|
||||
handlers.handleAnnotation(top, annotationNode, annotation, priority);
|
||||
}
|
||||
|
||||
@Override public void visitAnnotationOnMethodArgument(JCVariableDecl argument, JCMethodDecl method, JavacNode annotationNode, JCAnnotation annotation) {
|
||||
JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get();
|
||||
handlers.handleAnnotation(top, annotationNode, annotation);
|
||||
handlers.handleAnnotation(top, annotationNode, annotation, priority);
|
||||
}
|
||||
|
||||
@Override public void visitAnnotationOnLocal(JCVariableDecl local, JavacNode annotationNode, JCAnnotation annotation) {
|
||||
JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get();
|
||||
handlers.handleAnnotation(top, annotationNode, annotation);
|
||||
handlers.handleAnnotation(top, annotationNode, annotation, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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
|
||||
* 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.javac;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marker to indicate a handler is to be called after all the non-resolution based visitors.
|
||||
* NB: Temporary solution - will be rewritten to a different style altogether in a future release.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ResolutionBased {
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2010 The Project Lombok Authors.
|
||||
* Copyright (C) 2009-2012 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
|
||||
@@ -30,8 +30,10 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Messager;
|
||||
@@ -80,6 +82,14 @@ public class Processor extends AbstractProcessor {
|
||||
placePostCompileAndDontMakeForceRoundDummiesHook();
|
||||
transformer = new JavacTransformer(procEnv.getMessager());
|
||||
trees = Trees.instance(procEnv);
|
||||
SortedSet<Long> p = transformer.getPriorities();
|
||||
if (p.isEmpty()) {
|
||||
this.priorityLevels = new long[] {0L};
|
||||
} else {
|
||||
this.priorityLevels = new long[p.size()];
|
||||
int i = 0;
|
||||
for (Long prio : p) this.priorityLevels[i++] = prio;
|
||||
}
|
||||
}
|
||||
|
||||
private void placePostCompileAndDontMakeForceRoundDummiesHook() {
|
||||
@@ -204,47 +214,72 @@ public class Processor extends AbstractProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private final IdentityHashMap<JCCompilationUnit, Void> rootsAtPhase0 = new IdentityHashMap<JCCompilationUnit, Void>();
|
||||
private final IdentityHashMap<JCCompilationUnit, Void> rootsAtPhase1 = new IdentityHashMap<JCCompilationUnit, Void>();
|
||||
private int dummyCount = 0;
|
||||
private final IdentityHashMap<JCCompilationUnit, Long> roots = new IdentityHashMap<JCCompilationUnit, Long>();
|
||||
private long[] priorityLevels;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (roundEnv.processingOver()) return false;
|
||||
|
||||
if (!rootsAtPhase0.isEmpty()) {
|
||||
ArrayList<JCCompilationUnit> cus = new ArrayList<JCCompilationUnit>(rootsAtPhase0.keySet());
|
||||
transformer.transform(true, processingEnv.getContext(), cus);
|
||||
rootsAtPhase1.putAll(rootsAtPhase0);
|
||||
rootsAtPhase0.clear();
|
||||
}
|
||||
// We have: A sorted set of all priority levels: 'priorityLevels'
|
||||
|
||||
// Step 1: Take all CUs which aren't already in the map. Give them the first priority level.
|
||||
|
||||
for (Element element : roundEnv.getRootElements()) {
|
||||
JCCompilationUnit unit = toUnit(element);
|
||||
if (unit != null) {
|
||||
if (!rootsAtPhase1.containsKey(unit)) rootsAtPhase0.put(unit, null);
|
||||
}
|
||||
if (unit == null) continue;
|
||||
if (roots.containsKey(unit)) continue;
|
||||
roots.put(unit, priorityLevels[0]);
|
||||
}
|
||||
|
||||
if (!rootsAtPhase0.isEmpty()) {
|
||||
ArrayList<JCCompilationUnit> cus = new ArrayList<JCCompilationUnit>(rootsAtPhase0.keySet());
|
||||
transformer.transform(false, processingEnv.getContext(), cus);
|
||||
JavacFiler filer = (JavacFiler) processingEnv.getFiler();
|
||||
if (!filer.newFiles()) {
|
||||
try {
|
||||
JavaFileObject dummy = filer.createSourceFile("lombok.dummy.ForceNewRound" + (dummyCount++));
|
||||
Writer w = dummy.openWriter();
|
||||
w.close();
|
||||
} catch (Exception e) {
|
||||
processingEnv.getMessager().printMessage(Kind.WARNING,
|
||||
"Can't force a new processing round. Lombok features that require resolution won't work.");
|
||||
// Step 2: For all CUs (in the map, not the roundEnv!), run them across all handlers at their current prio level.
|
||||
|
||||
for (long prio : priorityLevels) {
|
||||
List<JCCompilationUnit> cusForThisRound = new ArrayList<JCCompilationUnit>();
|
||||
for (Map.Entry<JCCompilationUnit, Long> entry : roots.entrySet()) {
|
||||
Long prioOfCu = entry.getValue();
|
||||
if (prioOfCu == null || prioOfCu != prio) continue;
|
||||
cusForThisRound.add(entry.getKey());
|
||||
}
|
||||
transformer.transform(prio, processingEnv.getContext(), cusForThisRound);
|
||||
}
|
||||
|
||||
// Step 3: Push up all CUs to the next level. Set level to null if there is no next level.
|
||||
|
||||
boolean nextRoundNeeded = false;
|
||||
for (int i = priorityLevels.length - 1; i >= 0; i--) {
|
||||
Long curLevel = priorityLevels[i];
|
||||
Long nextLevel = (i == priorityLevels.length - 1) ? null : priorityLevels[i + 1];
|
||||
for (Map.Entry<JCCompilationUnit, Long> entry : roots.entrySet()) {
|
||||
if (curLevel.equals(entry.getValue())) {
|
||||
entry.setValue(nextLevel);
|
||||
if (nextLevel != null) nextRoundNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: If ALL values are null, quit. Else, force new round.
|
||||
|
||||
if (nextRoundNeeded) forceNewRound((JavacFiler) processingEnv.getFiler());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int dummyCount = 0;
|
||||
private void forceNewRound(JavacFiler filer) {
|
||||
if (!filer.newFiles()) {
|
||||
try {
|
||||
JavaFileObject dummy = filer.createSourceFile("lombok.dummy.ForceNewRound" + (dummyCount++));
|
||||
Writer w = dummy.openWriter();
|
||||
w.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
processingEnv.getMessager().printMessage(Kind.WARNING,
|
||||
"Can't force a new processing round. Lombok won't work.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JCCompilationUnit toUnit(Element element) {
|
||||
TreePath path = trees == null ? null : trees.getPath(element);
|
||||
if (path == null) return null;
|
||||
|
||||
@@ -43,11 +43,11 @@ import javax.lang.model.type.TypeMirror;
|
||||
import lombok.Delegate;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.javac.FindTypeVarScanner;
|
||||
import lombok.javac.JavacAnnotationHandler;
|
||||
import lombok.javac.JavacNode;
|
||||
import lombok.javac.JavacResolution;
|
||||
import lombok.javac.ResolutionBased;
|
||||
import lombok.javac.JavacResolution.TypeNotConvertibleException;
|
||||
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
@@ -75,7 +75,7 @@ import com.sun.tools.javac.util.ListBuffer;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
@ProviderFor(JavacAnnotationHandler.class)
|
||||
@ResolutionBased
|
||||
@HandlerPriority(65536) //2^16; to make sure that we also delegate generated methods.
|
||||
public class HandleDelegate extends JavacAnnotationHandler<Delegate> {
|
||||
private static final List<String> METHODS_IN_OBJECT = Collections.unmodifiableList(Arrays.asList(
|
||||
"hashCode()",
|
||||
|
||||
@@ -31,10 +31,10 @@ import java.util.List;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.experimental.ExtensionMethod;
|
||||
import lombok.javac.JavacAnnotationHandler;
|
||||
import lombok.javac.JavacNode;
|
||||
import lombok.javac.ResolutionBased;
|
||||
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
@@ -60,7 +60,7 @@ import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
* Handles the {@link ExtensionMethod} annotation for javac.
|
||||
*/
|
||||
@ProviderFor(JavacAnnotationHandler.class)
|
||||
@ResolutionBased
|
||||
@HandlerPriority(66560) // 2^16 + 2^10; we must run AFTER HandleVal which is at 2^16
|
||||
public class HandleExtensionMethod extends JavacAnnotationHandler<ExtensionMethod> {
|
||||
@Override
|
||||
public void handle(final AnnotationValues<ExtensionMethod> annotation, final JCAnnotation source, final JavacNode annotationNode) {
|
||||
@@ -83,9 +83,6 @@ public class HandleExtensionMethod extends JavacAnnotationHandler<ExtensionMetho
|
||||
final List<Extension> extensions = getExtensions(annotationNode, extensionProviders);
|
||||
if (extensions.isEmpty()) return;
|
||||
|
||||
// call HandleVal explicitly to ensure val gets handled before @ExtensionMethdod gets handled.
|
||||
// TODO maybe we should prioritize lombok handler
|
||||
annotationNode.traverse(new HandleVal());
|
||||
new ExtensionMethodReplaceVisitor(annotationNode, extensions, suppressBaseMethods).replace();
|
||||
|
||||
annotationNode.rebuild();
|
||||
|
||||
@@ -25,6 +25,7 @@ import static lombok.javac.handlers.JavacHandlerUtil.*;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import lombok.experimental.NonFinal;
|
||||
import lombok.experimental.PackagePrivate;
|
||||
@@ -43,6 +44,7 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
* Handles the {@code lombok.FieldDefaults} annotation for eclipse.
|
||||
*/
|
||||
@ProviderFor(JavacAnnotationHandler.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 JavacAnnotationHandler<FieldDefaults> {
|
||||
public boolean generateFieldDefaultsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) {
|
||||
if (checkForTypeLevelFieldDefaults) {
|
||||
|
||||
@@ -44,7 +44,6 @@ import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
public class HandleLog {
|
||||
|
||||
private HandleLog() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.sun.tools.javac.tree.JCTree.JCAnnotation;
|
||||
|
||||
import lombok.Lombok;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.core.PrintAST;
|
||||
import lombok.javac.JavacASTVisitor;
|
||||
import lombok.javac.JavacAnnotationHandler;
|
||||
@@ -40,6 +41,7 @@ import lombok.javac.JavacNode;
|
||||
* Handles the {@code lombok.core.PrintAST} annotation for javac.
|
||||
*/
|
||||
@ProviderFor(JavacAnnotationHandler.class)
|
||||
@HandlerPriority(536870912) // 2^29; this handler is customarily run at the very end.
|
||||
public class HandlePrintAST extends JavacAnnotationHandler<PrintAST> {
|
||||
@Override public void handle(AnnotationValues<PrintAST> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
PrintStream stream = System.out;
|
||||
|
||||
@@ -24,11 +24,11 @@ package lombok.javac.handlers;
|
||||
import static lombok.javac.handlers.JavacHandlerUtil.*;
|
||||
|
||||
import lombok.val;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.javac.JavacASTAdapter;
|
||||
import lombok.javac.JavacASTVisitor;
|
||||
import lombok.javac.JavacNode;
|
||||
import lombok.javac.JavacResolution;
|
||||
import lombok.javac.ResolutionBased;
|
||||
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
@@ -44,7 +44,7 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.util.List;
|
||||
|
||||
@ProviderFor(JavacASTVisitor.class)
|
||||
@ResolutionBased
|
||||
@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 JavacASTAdapter {
|
||||
@Override public void visitLocal(JavacNode localNode, JCVariableDecl local) {
|
||||
if (local.vartype == null || (!local.vartype.toString().equals("val") && !local.vartype.toString().equals("lombok.val"))) return;
|
||||
|
||||
@@ -24,18 +24,23 @@ package lombok.javac.handlers;
|
||||
import static lombok.javac.handlers.JavacHandlerUtil.*;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.experimental.NonFinal;
|
||||
import lombok.experimental.Value;
|
||||
import lombok.javac.JavacAnnotationHandler;
|
||||
import lombok.javac.JavacNode;
|
||||
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
|
||||
/**
|
||||
* Handles the {@code lombok.Value} annotation for javac.
|
||||
*/
|
||||
@ProviderFor(JavacAnnotationHandler.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 JavacAnnotationHandler<Value> {
|
||||
@Override public void handle(AnnotationValues<Value> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
deleteAnnotationIfNeccessary(annotationNode, Value.class);
|
||||
@@ -49,12 +54,16 @@ public class HandleValue extends JavacAnnotationHandler<Value> {
|
||||
|
||||
String staticConstructorName = annotation.getInstance().staticConstructor();
|
||||
|
||||
if (!hasAnnotationAndDeleteIfNeccessary(NonFinal.class, typeNode)) {
|
||||
((JCClassDecl) typeNode.get()).mods.flags |= Flags.FINAL;
|
||||
}
|
||||
new HandleFieldDefaults().generateFieldDefaultsForType(typeNode, annotationNode, AccessLevel.PRIVATE, true, true);
|
||||
|
||||
// TODO move this to the end OR move it to the top in eclipse.
|
||||
new HandleConstructor().generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, staticConstructorName, true, annotationNode);
|
||||
new HandleGetter().generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user