diff options
-rw-r--r-- | src/core/lombok/Builder.java | 7 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleBuilder.java | 19 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleConstructor.java | 6 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/JavacHandlerUtil.java | 21 |
4 files changed, 47 insertions, 6 deletions
diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java index 7a965486..a0b8242f 100644 --- a/src/core/lombok/Builder.java +++ b/src/core/lombok/Builder.java @@ -107,6 +107,13 @@ import java.lang.annotation.Target; @Target({TYPE, METHOD, CONSTRUCTOR}) @Retention(SOURCE) public @interface Builder { + /** + * Marks a given field as being a 'constant' (initialized by the initializing expression during construction and not eligible to be modified as part of {@code @Builder}. + */ + @Target(FIELD) + @Retention(SOURCE) + public @interface Constant {} + /** Name of the method that creates a new builder instance. Default: {@code builder}. */ String builderMethodName() default "builder"; diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 4c670433..5dde551d 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -139,12 +139,21 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>(); @SuppressWarnings("deprecation") boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation(lombok.experimental.Value.class, parent)); - for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent)) { + for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) { JCVariableDecl fd = (JCVariableDecl) 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.init != null && valuePresent && !hasAnnotation(NonFinal.class, fieldNode)) continue; + boolean isFinal = (fd.mods.flags & Flags.FINAL) != 0 || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode)); + JavacNode isConstant = findAnnotation(Builder.Constant.class, fieldNode, true); + + if (fd.init != null && isFinal) { + if (isConstant != null) continue; + } + + if (isConstant != null) { + if (!isFinal && fd.init == null) isConstant.addWarning("@Builder.Constant doesn't do anything unless the field has an initializing expression (' = something;') and is final."); + else if (!isFinal) isConstant.addWarning("@Builder.Constant doesn't do anything unless the field is final."); + else if (fd.init == null) isConstant.addWarning("@Builder.Constant doesn't do anything unless the field has an initializing expression (' = something;')."); + } + BuilderFieldData bfd = new BuilderFieldData(); bfd.rawName = fd.name; bfd.name = removePrefixFromField(fieldNode); diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index 4e90b639..be4af41c 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -151,6 +151,10 @@ public class HandleConstructor { } public static List<JavacNode> findAllFields(JavacNode typeNode) { + return findAllFields(typeNode, false); + } + + public static List<JavacNode> findAllFields(JavacNode typeNode, boolean evenFinalInitialized) { ListBuffer<JavacNode> fields = new ListBuffer<JavacNode>(); for (JavacNode child : typeNode.down()) { if (child.getKind() != Kind.FIELD) continue; @@ -162,7 +166,7 @@ public class HandleConstructor { if ((fieldFlags & Flags.STATIC) != 0) continue; //Skip initialized final fields boolean isFinal = (fieldFlags & Flags.FINAL) != 0; - if (!isFinal || fieldDecl.init == null) fields.append(child); + if (evenFinalInitialized || !isFinal || fieldDecl.init == null) fields.append(child); } return fields.toList(); } diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 56e666f7..6fa60aac 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -191,6 +191,27 @@ public class JavacHandlerUtil { } } + static JavacNode findAnnotation(Class<? extends Annotation> type, JavacNode node, boolean delete) { + if (node == null) return null; + if (type == null) return null; + switch (node.getKind()) { + case ARGUMENT: + case FIELD: + case LOCAL: + case TYPE: + case METHOD: + for (JavacNode child : node.down()) { + if (annotationTypeMatches(type, child)) { + if (delete) deleteAnnotationIfNeccessary(child, type); + return child; + } + } + // intentional fallthrough + default: + return null; + } + } + /** * Checks if the Annotation AST Node provided is likely to be an instance of the provided annotation type. * |