aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/eclipse/handlers
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2013-07-16 00:51:31 +0200
committerReinier Zwitserloot <reinier@zwitserloot.com>2013-07-16 00:51:31 +0200
commit7af9add9996f2efab6cccc50c5503b3457534930 (patch)
treebd224bd341da31e1b5aba5e718f43b6fd1227e8d /src/core/lombok/eclipse/handlers
parentec0cc4348cf71d872b796d0733fb64fc576ef5df (diff)
downloadlombok-7af9add9996f2efab6cccc50c5503b3457534930.tar.gz
lombok-7af9add9996f2efab6cccc50c5503b3457534930.tar.bz2
lombok-7af9add9996f2efab6cccc50c5503b3457534930.zip
* Fixed issues with @FieldDefaults and @Value (you can NOT override
@Value's final-by-default and private-by-default with it; now appropriate warnings are emitted) * Builder now errors out on presence of most lombok annotations on an explicit builder class. * Builder now takes @FieldDefaults/@Value into account. * Builder on type now generates the constructor as package private instead of private to avoid synthetic accessor constructors. * added a bunch of test cases. * added a test case feature: If the expected file is omitted entirely but there are expected messages, the differences in the output itself are ignored. * streamlined checking for boolean-ness (removed some duplicate code) * added 'fluent' and 'chain' to @Builder.
Diffstat (limited to 'src/core/lombok/eclipse/handlers')
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java35
-rw-r--r--src/core/lombok/eclipse/handlers/HandleBuilder.java30
-rw-r--r--src/core/lombok/eclipse/handlers/HandleFieldDefaults.java10
-rw-r--r--src/core/lombok/eclipse/handlers/HandleGetter.java2
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSetter.java2
-rw-r--r--src/core/lombok/eclipse/handlers/HandleWither.java2
6 files changed, 69 insertions, 12 deletions
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 364ce0a5..9bd634f7 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -22,6 +22,7 @@
package lombok.eclipse.handlers;
import static lombok.eclipse.Eclipse.*;
+import static lombok.core.TransformationsUtil.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -296,6 +297,29 @@ public class EclipseHandlerUtil {
}
+ public static void sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(EclipseNode typeNode, EclipseNode errorNode) {
+ List<String> disallowed = null;
+ for (EclipseNode child : typeNode.down()) {
+ for (Class<? extends java.lang.annotation.Annotation> annType : INVALID_ON_BUILDERS) {
+ if (annotationTypeMatches(annType, child)) {
+ if (disallowed == null) disallowed = new ArrayList<String>();
+ disallowed.add(annType.getSimpleName());
+ }
+ }
+ }
+
+ int size = disallowed == null ? 0 : disallowed.size();
+ if (size == 0) return;
+ if (size == 1) {
+ errorNode.addError("@" + disallowed.get(0) + " is not allowed on builder classes.");
+ return;
+ }
+ StringBuilder out = new StringBuilder();
+ for (String a : disallowed) out.append("@").append(a).append(", ");
+ out.setLength(out.length() - 2);
+ errorNode.addError(out.append(" are not allowed on builder classes.").toString());
+ }
+
public static Annotation copyAnnotation(Annotation annotation, ASTNode source) {
int pS = source.sourceStart, pE = source.sourceEnd;
@@ -845,15 +869,20 @@ public class EclipseHandlerUtil {
private static final Object MARKER = new Object();
static void registerCreatedLazyGetter(FieldDeclaration field, char[] methodName, TypeReference returnType) {
- if (!nameEquals(returnType.getTypeName(), "boolean") || returnType.dimensions() > 0) return;
- generatedLazyGettersWithPrimitiveBoolean.put(field, MARKER);
+ if (isBoolean(returnType)) {
+ generatedLazyGettersWithPrimitiveBoolean.put(field, MARKER);
+ }
+ }
+
+ public static boolean isBoolean(TypeReference typeReference) {
+ return nameEquals(typeReference.getTypeName(), "boolean") && typeReference.dimensions() == 0;
}
private static GetterMethod findGetter(EclipseNode field) {
FieldDeclaration fieldDeclaration = (FieldDeclaration) field.get();
boolean forceBool = generatedLazyGettersWithPrimitiveBoolean.containsKey(fieldDeclaration);
TypeReference fieldType = fieldDeclaration.type;
- boolean isBoolean = forceBool || (nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0);
+ boolean isBoolean = forceBool || isBoolean(fieldType);
EclipseNode typeNode = field.up();
for (String potentialGetterName : toAllGetterNames(field, isBoolean)) {
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
index e2bf5fe2..70110a9c 100644
--- a/src/core/lombok/eclipse/handlers/HandleBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -58,13 +58,17 @@ import org.mangosdk.spi.ProviderFor;
import lombok.AccessLevel;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
+import lombok.core.HandlerPriority;
+import lombok.core.TransformationsUtil;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists;
import lombok.experimental.Builder;
+import lombok.experimental.NonFinal;
@ProviderFor(EclipseAnnotationHandler.class)
+@HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes.
public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
@Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
long p = (long) ast.sourceStart << 32 | ast.sourceEnd;
@@ -99,14 +103,23 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
if (parent.get() instanceof TypeDeclaration) {
tdParent = parent;
TypeDeclaration td = (TypeDeclaration) tdParent.get();
- new HandleConstructor().generateAllArgsConstructor(tdParent, AccessLevel.PRIVATE, null, SkipIfConstructorExists.I_AM_BUILDER, Collections.<Annotation>emptyList(), ast);
+ List<EclipseNode> fields = new ArrayList<EclipseNode>();
+ @SuppressWarnings("deprecation")
+ boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation(lombok.experimental.Value.class, parent));
for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent)) {
FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
+ // final fields with an initializer cannot be written to, so they can't be 'builderized'. Unfortunately presence of @Value makes
+ // non-final fields final, but @Value's handler hasn't done this yet, so we have to do this math ourselves.
+ // Value will only skip making a field final if it has an explicit @NonFinal annotation, so we check for that.
+ if (fd.initialization != null && valuePresent && !hasAnnotation(NonFinal.class, fieldNode)) continue;
namesOfParameters.add(fd.name);
typesOfParameters.add(fd.type);
+ fields.add(fieldNode);
}
+ new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, fields, null, SkipIfConstructorExists.I_AM_BUILDER, true, Collections.<Annotation>emptyList(), ast);
+
returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
typeParams = td.typeParameters;
thrownExceptions = null;
@@ -181,11 +194,15 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
EclipseNode builderType = findInnerClass(tdParent, builderClassName);
- if (builderType == null) builderType = makeBuilderClass(tdParent, builderClassName, typeParams, ast);
+ if (builderType == null) {
+ builderType = makeBuilderClass(tdParent, builderClassName, typeParams, ast);
+ } else {
+ sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode);
+ }
List<EclipseNode> fieldNodes = addFieldsToBuilder(builderType, namesOfParameters, typesOfParameters, ast);
List<AbstractMethodDeclaration> newMethods = new ArrayList<AbstractMethodDeclaration>();
for (EclipseNode fieldNode : fieldNodes) {
- MethodDeclaration newMethod = makeSetterMethodForBuilder(builderType, fieldNode, ast);
+ MethodDeclaration newMethod = makeSetterMethodForBuilder(builderType, fieldNode, ast, builderInstance.fluent(), builderInstance.chain());
if (newMethod != null) newMethods.add(newMethod);
}
@@ -315,7 +332,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
private static final AbstractMethodDeclaration[] EMPTY = {};
- private MethodDeclaration makeSetterMethodForBuilder(EclipseNode builderType, EclipseNode fieldNode, ASTNode source) {
+ private MethodDeclaration makeSetterMethodForBuilder(EclipseNode builderType, EclipseNode fieldNode, ASTNode source, boolean fluent, boolean chain) {
TypeDeclaration td = (TypeDeclaration) builderType.get();
AbstractMethodDeclaration[] existing = td.methods;
if (existing == null) existing = EMPTY;
@@ -329,7 +346,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
if (Arrays.equals(name, existingName)) return null;
}
- return HandleSetter.createSetter(td, fieldNode, fieldNode.getName(), true, ClassFileConstants.AccPublic,
+ boolean isBoolean = isBoolean(fd.type);
+ String setterName = fluent ? fieldNode.getName() : TransformationsUtil.toSetterName(null, fieldNode.getName(), isBoolean);
+
+ return HandleSetter.createSetter(td, fieldNode, setterName, chain, ClassFileConstants.AccPublic,
source, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList());
}
diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
index 0d21fc08..d6d839cc 100644
--- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
@@ -43,7 +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.
+@HandlerPriority(-2048) //-2^11; to ensure @Value picks 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) {
@@ -112,6 +112,14 @@ public class HandleFieldDefaults extends EclipseAnnotationHandler<FieldDefaults>
return;
}
+ if (level == AccessLevel.PACKAGE) {
+ annotationNode.addError("Setting 'level' to PACKAGE does nothing. To force fields as package private, use the @PackagePrivate annotation on the field.");
+ }
+
+ if (!makeFinal && annotation.isExplicit("makeFinal")) {
+ annotationNode.addError("Setting 'makeFinal' to false does nothing. To force fields to be non-final, use the @NonFinal annotation on the field.");
+ }
+
if (node == null) return;
generateFieldDefaultsForType(node, annotationNode, level, makeFinal, false);
diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java
index 760c595e..787f6f6c 100644
--- a/src/core/lombok/eclipse/handlers/HandleGetter.java
+++ b/src/core/lombok/eclipse/handlers/HandleGetter.java
@@ -187,7 +187,7 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> {
}
TypeReference fieldType = copyType(field.type, source);
- boolean isBoolean = nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0;
+ boolean isBoolean = isBoolean(fieldType);
String getterName = toGetterName(fieldNode, isBoolean);
if (getterName == null) {
diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java
index ae846a4e..3bfcc51c 100644
--- a/src/core/lombok/eclipse/handlers/HandleSetter.java
+++ b/src/core/lombok/eclipse/handlers/HandleSetter.java
@@ -159,7 +159,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
TypeReference fieldType = copyType(field.type, source);
- boolean isBoolean = nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0;
+ boolean isBoolean = isBoolean(fieldType);
String setterName = toSetterName(fieldNode, isBoolean);
boolean shouldReturnThis = shouldReturnThis(fieldNode);
diff --git a/src/core/lombok/eclipse/handlers/HandleWither.java b/src/core/lombok/eclipse/handlers/HandleWither.java
index 9d74cbd1..27fbc635 100644
--- a/src/core/lombok/eclipse/handlers/HandleWither.java
+++ b/src/core/lombok/eclipse/handlers/HandleWither.java
@@ -160,7 +160,7 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> {
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
TypeReference fieldType = copyType(field.type, source);
- boolean isBoolean = nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0;
+ boolean isBoolean = isBoolean(fieldType);
String witherName = toWitherName(fieldNode, isBoolean);
if (witherName == null) {