From 261758b4448b3d48ff2f48926ffcb8ea66121603 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 8 Feb 2022 06:02:05 +0100 Subject: [implements #1456] accessors can now be made final via `@Accessors`. --- src/core/lombok/ConfigurationKeys.java | 11 ++- src/core/lombok/core/AnnotationValues.java | 23 +++++- src/core/lombok/core/handlers/HandlerUtil.java | 10 ++- .../eclipse/handlers/EclipseHandlerUtil.java | 94 +++++++++++++++++++-- .../lombok/eclipse/handlers/HandleAccessors.java | 3 +- src/core/lombok/eclipse/handlers/HandleGetter.java | 10 ++- src/core/lombok/eclipse/handlers/HandleSetter.java | 12 ++- src/core/lombok/eclipse/handlers/HandleWith.java | 12 ++- src/core/lombok/eclipse/handlers/HandleWithBy.java | 12 ++- src/core/lombok/experimental/Accessors.java | 17 +++- .../lombok/javac/handlers/HandleAccessors.java | 3 +- src/core/lombok/javac/handlers/HandleGetter.java | 16 ++-- src/core/lombok/javac/handlers/HandleSetter.java | 21 +++-- src/core/lombok/javac/handlers/HandleWith.java | 13 ++- src/core/lombok/javac/handlers/HandleWithBy.java | 11 ++- .../lombok/javac/handlers/JavacHandlerUtil.java | 96 ++++++++++++++++++++-- 16 files changed, 302 insertions(+), 62 deletions(-) (limited to 'src/core/lombok') diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 457246e7..22d5a4c5 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2021 The Project Lombok Authors. + * Copyright (C) 2013-2022 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 @@ -550,7 +550,7 @@ public class ConfigurationKeys { * * For any class without an {@code @Accessors} that explicitly defines the {@code prefix} option, this list of prefixes is used. */ - public static final ConfigurationKey> ACCESSORS_PREFIX = new ConfigurationKey>("lombok.accessors.prefix", "Strip this field prefix, like 'f' or 'm_', from the names of generated getters and setters.") {}; + public static final ConfigurationKey> ACCESSORS_PREFIX = new ConfigurationKey>("lombok.accessors.prefix", "Strip this field prefix, like 'f' or 'm_', from the names of generated getters, setters, and with-ers.") {}; /** * lombok configuration: {@code lombok.accessors.chain} = {@code true} | {@code false}. @@ -566,6 +566,13 @@ public class ConfigurationKeys { */ public static final ConfigurationKey ACCESSORS_FLUENT = new ConfigurationKey("lombok.accessors.fluent", "Generate getters and setters using only the field name (no get/set prefix) (default: false).") {}; + /** + * lombok configuration: {@code lombok.accessors.makeFinal} = {@code true} | {@code false}. + * + * Unless an explicit {@code @Accessors} that explicitly defines the {@code makeFinal} option, this value is used (default = false). + */ + public static final ConfigurationKey ACCESSORS_MAKE_FINAL = new ConfigurationKey("lombok.accessors.makeFinal", "Generate getters, setters and with-ers with the 'final' modifier (default: false).") {}; + /** * lombok configuration: {@code lombok.accessors.capitalization} = {@code basic} | {@code beanspec}. * diff --git a/src/core/lombok/core/AnnotationValues.java b/src/core/lombok/core/AnnotationValues.java index f5db553c..390e9b71 100644 --- a/src/core/lombok/core/AnnotationValues.java +++ b/src/core/lombok/core/AnnotationValues.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2013 The Project Lombok Authors. + * Copyright (C) 2009-2022 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 @@ -550,4 +550,25 @@ public class AnnotationValues { result.append(typeName); return result.toString(); } + + /** + * Creates an amalgamation where any values in this AnnotationValues that aren't explicit are 'enriched' by explicitly set stuff from {@code defaults}. + * Note that this code may modify self and then returns self, or it returns defaults - do not rely on immutability nor on getting self. + */ + public AnnotationValues integrate(AnnotationValues defaults) { + if (values.isEmpty()) return defaults; + for (Map.Entry entry : defaults.values.entrySet()) { + if (!entry.getValue().isExplicit) continue; + AnnotationValue existingValue = values.get(entry.getKey()); + if (existingValue != null && existingValue.isExplicit) continue; + values.put(entry.getKey(), entry.getValue()); + } + return this; + } + + /** Returns {@code true} if the annotation has zero parameters. */ + public boolean isMarking() { + for (AnnotationValue v : values.values()) if (v.isExplicit) return false; + return true; + } } diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index 2415b750..039ce870 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2021 The Project Lombok Authors. + * Copyright (C) 2013-2022 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 @@ -555,6 +555,14 @@ public class HandlerUtil { return chain || fluent; } + public static boolean shouldMakeFinal0(AnnotationValues accessors, AST ast) { + boolean isExplicit = accessors.isExplicit("makeFinal"); + if (isExplicit) return accessors.getAsBoolean("makeFinal"); + Boolean config = ast.readConfiguration(ConfigurationKeys.ACCESSORS_MAKE_FINAL); + if (config != null) return config.booleanValue(); + return false; + } + @SuppressWarnings({"all", "unchecked", "deprecation"}) public static final List INVALID_ON_BUILDERS = Collections.unmodifiableList( Arrays.asList( diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 6483a749..65e2c5c8 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2022 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 @@ -1631,6 +1631,14 @@ public class EclipseHandlerUtil { return HandlerUtil.toAllGetterNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean); } + /** + * Translates the given field into all possible getter names. + * Convenient wrapper around {@link HandlerUtil#toAllGetterNames(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static List toAllGetterNames(EclipseNode field, boolean isBoolean, AnnotationValues accessors) { + return HandlerUtil.toAllGetterNames(field.getAst(), accessors, field.getName(), isBoolean); + } + /** * @return the likely getter name for the stated field. (e.g. private boolean foo; to isFoo). * @@ -1640,6 +1648,15 @@ public class EclipseHandlerUtil { return HandlerUtil.toGetterName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean); } + /** + * @return the likely getter name for the stated field. (e.g. private boolean foo; to isFoo). + * + * Convenient wrapper around {@link HandlerUtil#toGetterName(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static String toGetterName(EclipseNode field, boolean isBoolean, AnnotationValues accessors) { + return HandlerUtil.toGetterName(field.getAst(), accessors, field.getName(), isBoolean); + } + /** * Translates the given field into all possible setter names. * Convenient wrapper around {@link HandlerUtil#toAllSetterNames(lombok.core.AnnotationValues, CharSequence, boolean)}. @@ -1648,6 +1665,14 @@ public class EclipseHandlerUtil { return HandlerUtil.toAllSetterNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean); } + /** + * Translates the given field into all possible setter names. + * Convenient wrapper around {@link HandlerUtil#toAllSetterNames(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static java.util.List toAllSetterNames(EclipseNode field, boolean isBoolean, AnnotationValues accessors) { + return HandlerUtil.toAllSetterNames(field.getAst(), accessors, field.getName(), isBoolean); + } + /** * @return the likely setter name for the stated field. (e.g. private boolean foo; to setFoo). * @@ -1657,6 +1682,15 @@ public class EclipseHandlerUtil { return HandlerUtil.toSetterName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean); } + /** + * @return the likely setter name for the stated field. (e.g. private boolean foo; to setFoo). + * + * Convenient wrapper around {@link HandlerUtil#toSetterName(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static String toSetterName(EclipseNode field, boolean isBoolean, AnnotationValues accessors) { + return HandlerUtil.toSetterName(field.getAst(), accessors, field.getName(), isBoolean); + } + /** * Translates the given field into all possible with names. * Convenient wrapper around {@link HandlerUtil#toAllWithNames(lombok.core.AnnotationValues, CharSequence, boolean)}. @@ -1665,6 +1699,14 @@ public class EclipseHandlerUtil { return HandlerUtil.toAllWithNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean); } + /** + * Translates the given field into all possible with names. + * Convenient wrapper around {@link HandlerUtil#toAllWithNames(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static java.util.List toAllWithNames(EclipseNode field, boolean isBoolean, AnnotationValues accessors) { + return HandlerUtil.toAllWithNames(field.getAst(), accessors, field.getName(), isBoolean); + } + /** * Translates the given field into all possible withBy names. * Convenient wrapper around {@link HandlerUtil#toAllWithByNames(lombok.core.AnnotationValues, CharSequence, boolean)}. @@ -1673,6 +1715,14 @@ public class EclipseHandlerUtil { return HandlerUtil.toAllWithByNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean); } + /** + * Translates the given field into all possible withBy names. + * Convenient wrapper around {@link HandlerUtil#toAllWithByNames(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static java.util.List toAllWithByNames(EclipseNode field, boolean isBoolean, AnnotationValues accessors) { + return HandlerUtil.toAllWithByNames(field.getAst(), accessors, field.getName(), isBoolean); + } + /** * @return the likely with name for the stated field. (e.g. private boolean foo; to withFoo). * @@ -1682,6 +1732,15 @@ public class EclipseHandlerUtil { return HandlerUtil.toWithName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean); } + /** + * @return the likely with name for the stated field. (e.g. private boolean foo; to withFoo). + * + * Convenient wrapper around {@link HandlerUtil#toWithName(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static String toWithName(EclipseNode field, boolean isBoolean, AnnotationValues accessors) { + return HandlerUtil.toWithName(field.getAst(), accessors, field.getName(), isBoolean); + } + /** * @return the likely withBy name for the stated field. (e.g. private boolean foo; to withFooBy). * @@ -1691,13 +1750,28 @@ public class EclipseHandlerUtil { return HandlerUtil.toWithByName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean); } + /** + * @return the likely withBy name for the stated field. (e.g. private boolean foo; to withFooBy). + * + * Convenient wrapper around {@link HandlerUtil#toWithByName(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static String toWithByName(EclipseNode field, boolean isBoolean, AnnotationValues accessors) { + return HandlerUtil.toWithByName(field.getAst(), accessors, field.getName(), isBoolean); + } + + /** + * When generating a setter/getter/wither, should it be made final? + */ + public static boolean shouldMakeFinal(EclipseNode field, AnnotationValues accessors) { + if ((((FieldDeclaration) field.get()).modifiers & ClassFileConstants.AccStatic) != 0) return false; + return shouldMakeFinal0(accessors, field.getAst()); + } /** * When generating a setter, the setter either returns void (beanspec) or Self (fluent). * This method scans for the {@code Accessors} annotation and associated config properties to figure that out. */ - public static boolean shouldReturnThis(EclipseNode field) { + public static boolean shouldReturnThis(EclipseNode field, AnnotationValues accessors) { if ((((FieldDeclaration) field.get()).modifiers & ClassFileConstants.AccStatic) != 0) return false; - AnnotationValues accessors = EclipseHandlerUtil.getAccessorsForField(field); return shouldReturnThis0(accessors, field.getAst()); } @@ -1760,9 +1834,12 @@ public class EclipseHandlerUtil { } public static AnnotationValues getAccessorsForField(EclipseNode field) { + AnnotationValues values = null; + for (EclipseNode node : field.down()) { if (annotationTypeMatches(Accessors.class, node)) { - return createAnnotation(Accessors.class, node); + values = createAnnotation(Accessors.class, node); + break; } } @@ -1770,15 +1847,16 @@ public class EclipseHandlerUtil { while (current != null) { for (EclipseNode node : current.down()) { if (annotationTypeMatches(Accessors.class, node)) { - return createAnnotation(Accessors.class, node); + AnnotationValues onType = createAnnotation(Accessors.class, node); + values = values == null ? onType : values.integrate(onType); } } current = current.up(); } - return AnnotationValues.of(Accessors.class, field); + return values == null ? AnnotationValues.of(Accessors.class, field) : values; } - + public static EclipseNode upToTypeNode(EclipseNode node) { if (node == null) throw new NullPointerException("node"); while (node != null && !(node.get() instanceof TypeDeclaration)) node = node.up(); @@ -2823,7 +2901,7 @@ public class EclipseHandlerUtil { if (!sectionBased) { out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), JavadocTag.RETURN); } - return shouldReturnThis(node) ? addReturnsThisIfNeeded(out) : out; + return shouldReturnThis(node, EclipseHandlerUtil.getAccessorsForField(node)) ? addReturnsThisIfNeeded(out) : out; } } diff --git a/src/core/lombok/eclipse/handlers/HandleAccessors.java b/src/core/lombok/eclipse/handlers/HandleAccessors.java index 6a92dee2..3bb63aa6 100644 --- a/src/core/lombok/eclipse/handlers/HandleAccessors.java +++ b/src/core/lombok/eclipse/handlers/HandleAccessors.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2021 The Project Lombok Authors. + * Copyright (C) 2014-2022 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 @@ -39,5 +39,6 @@ public class HandleAccessors extends EclipseAnnotationHandler { // Accessors itself is handled by HandleGetter/Setter; this is just to ensure that usages are flagged if requested. handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.ACCESSORS_FLAG_USAGE, "@Accessors"); + if (annotation.isMarking()) annotationNode.addWarning("Accessors on its own does nothing. Set at least one parameter"); } } diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index 7f8fdef2..31236d21 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2022 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 @@ -34,6 +34,7 @@ import java.util.Map; import lombok.AccessLevel; import lombok.ConfigurationKeys; +import lombok.experimental.Accessors; import lombok.experimental.Delegate; import lombok.spi.Provides; import lombok.Getter; @@ -190,7 +191,8 @@ public class HandleGetter extends EclipseAnnotationHandler { TypeReference fieldType = copyType(field.type, source); boolean isBoolean = isBoolean(fieldType); - String getterName = toGetterName(fieldNode, isBoolean); + AnnotationValues accessors = getAccessorsForField(fieldNode); + String getterName = toGetterName(fieldNode, isBoolean, accessors); if (getterName == null) { errorNode.addWarning("Not generating getter for this field: It does not fit your @Accessors prefix list."); @@ -199,7 +201,7 @@ public class HandleGetter extends EclipseAnnotationHandler { int modifier = toEclipseModifier(level) | (field.modifiers & ClassFileConstants.AccStatic); - for (String altName : toAllGetterNames(fieldNode, isBoolean)) { + for (String altName : toAllGetterNames(fieldNode, isBoolean, accessors)) { switch (methodExists(altName, fieldNode, false, 0)) { case EXISTS_BY_LOMBOK: return; @@ -247,7 +249,9 @@ public class HandleGetter extends EclipseAnnotationHandler { statements = createSimpleGetterBody(source, fieldNode); } + AnnotationValues accessors = getAccessorsForField(fieldNode); MethodDeclaration method = new MethodDeclaration(parent.compilationResult); + if (shouldMakeFinal(fieldNode, accessors)) modifier |= ClassFileConstants.AccFinal; method.modifiers = modifier; method.returnType = returnType; method.annotations = null; diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index 0fdd058f..fda1651d 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2022 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 @@ -37,6 +37,7 @@ import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.experimental.Accessors; import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.ASTNode; @@ -150,8 +151,9 @@ public class HandleSetter extends EclipseAnnotationHandler { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); TypeReference fieldType = copyType(field.type, source); boolean isBoolean = isBoolean(fieldType); - String setterName = toSetterName(fieldNode, isBoolean); - boolean shouldReturnThis = shouldReturnThis(fieldNode); + AnnotationValues accessors = getAccessorsForField(fieldNode); + String setterName = toSetterName(fieldNode, isBoolean, accessors); + boolean shouldReturnThis = shouldReturnThis(fieldNode, accessors); if (setterName == null) { fieldNode.addWarning("Not generating setter for this field: It does not fit your @Accessors prefix list."); @@ -160,7 +162,7 @@ public class HandleSetter extends EclipseAnnotationHandler { int modifier = toEclipseModifier(level) | (field.modifiers & ClassFileConstants.AccStatic); - for (String altName : toAllSetterNames(fieldNode, isBoolean)) { + for (String altName : toAllSetterNames(fieldNode, isBoolean, accessors)) { switch (methodExists(altName, fieldNode, false, 1)) { case EXISTS_BY_LOMBOK: return; @@ -206,6 +208,8 @@ public class HandleSetter extends EclipseAnnotationHandler { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; MethodDeclaration method = new MethodDeclaration(parent.compilationResult); + AnnotationValues accessors = getAccessorsForField(fieldNode); + if (shouldMakeFinal(fieldNode, accessors)) modifier |= ClassFileConstants.AccFinal; method.modifiers = modifier; if (returnType != null) { method.returnType = returnType; diff --git a/src/core/lombok/eclipse/handlers/HandleWith.java b/src/core/lombok/eclipse/handlers/HandleWith.java index bfad682b..153f0c4a 100644 --- a/src/core/lombok/eclipse/handlers/HandleWith.java +++ b/src/core/lombok/eclipse/handlers/HandleWith.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2021 The Project Lombok Authors. + * Copyright (C) 2012-2022 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 @@ -38,6 +38,7 @@ import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.experimental.Accessors; import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.ASTNode; @@ -169,7 +170,8 @@ public class HandleWith extends EclipseAnnotationHandler { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); TypeReference fieldType = copyType(field.type, source); boolean isBoolean = isBoolean(fieldType); - String withName = toWithName(fieldNode, isBoolean); + AnnotationValues accessors = getAccessorsForField(fieldNode); + String withName = toWithName(fieldNode, isBoolean, accessors); if (withName == null) { fieldNode.addWarning("Not generating a with method for this field: It does not fit your @Accessors prefix list."); @@ -191,7 +193,7 @@ public class HandleWith extends EclipseAnnotationHandler { return; } - for (String altName : toAllWithNames(fieldNode, isBoolean)) { + for (String altName : toAllWithNames(fieldNode, isBoolean, accessors)) { switch (methodExists(altName, fieldNode, false, 1)) { case EXISTS_BY_LOMBOK: return; @@ -222,7 +224,9 @@ public class HandleWith extends EclipseAnnotationHandler { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; MethodDeclaration method = new MethodDeclaration(parent.compilationResult); - if (makeAbstract) modifier = modifier | ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody; + AnnotationValues accessors = getAccessorsForField(fieldNode); + if (makeAbstract) modifier |= ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody; + if (shouldMakeFinal(fieldNode, accessors)) modifier |= ClassFileConstants.AccFinal; method.modifiers = modifier; method.returnType = cloneSelfType(fieldNode, source); if (method.returnType == null) return null; diff --git a/src/core/lombok/eclipse/handlers/HandleWithBy.java b/src/core/lombok/eclipse/handlers/HandleWithBy.java index a8d13a84..5ab3cf81 100644 --- a/src/core/lombok/eclipse/handlers/HandleWithBy.java +++ b/src/core/lombok/eclipse/handlers/HandleWithBy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 The Project Lombok Authors. + * Copyright (C) 2020-2022 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 @@ -61,6 +61,7 @@ import lombok.core.handlers.HandlerUtil.FieldAccess; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.experimental.Accessors; import lombok.experimental.WithBy; import lombok.spi.Provides; @@ -169,7 +170,8 @@ public class HandleWithBy extends EclipseAnnotationHandler { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); TypeReference fieldType = copyType(field.type, source); boolean isBoolean = isBoolean(fieldType); - String withName = toWithByName(fieldNode, isBoolean); + AnnotationValues accessors = getAccessorsForField(fieldNode); + String withName = toWithByName(fieldNode, isBoolean, accessors); if (withName == null) { fieldNode.addWarning("Not generating a withXBy method for this field: It does not fit your @Accessors prefix list."); @@ -191,7 +193,7 @@ public class HandleWithBy extends EclipseAnnotationHandler { return; } - for (String altName : toAllWithByNames(fieldNode, isBoolean)) { + for (String altName : toAllWithByNames(fieldNode, isBoolean, accessors)) { switch (methodExists(altName, fieldNode, false, 1)) { case EXISTS_BY_LOMBOK: return; @@ -242,7 +244,9 @@ public class HandleWithBy extends EclipseAnnotationHandler { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; MethodDeclaration method = new MethodDeclaration(parent.compilationResult); - if (makeAbstract) modifier = modifier | ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody; + AnnotationValues accessors = getAccessorsForField(fieldNode); + if (makeAbstract) modifier |= ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody; + if (shouldMakeFinal(fieldNode, accessors)) modifier |= ClassFileConstants.AccFinal; method.modifiers = modifier; method.returnType = cloneSelfType(fieldNode, source); if (method.returnType == null) return null; diff --git a/src/core/lombok/experimental/Accessors.java b/src/core/lombok/experimental/Accessors.java index dc9ae4b0..394fe5c4 100644 --- a/src/core/lombok/experimental/Accessors.java +++ b/src/core/lombok/experimental/Accessors.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2017 The Project Lombok Authors. + * Copyright (C) 2012-2022 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 @@ -27,11 +27,11 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * A container for settings for the generation of getters and setters. + * A container for settings for the generation of getters, setters and "with"-ers. *

* Complete documentation is found at the project lombok features page for @Accessors. *

- * Using this annotation does nothing by itself; an annotation that makes lombok generate getters and setters, + * Using this annotation does nothing by itself; an annotation that makes lombok generate getters, setters, or "with"-ers * such as {@link lombok.Setter} or {@link lombok.Data} is also required. */ @Target({ElementType.TYPE, ElementType.FIELD}) @@ -39,7 +39,8 @@ import java.lang.annotation.Target; public @interface Accessors { /** * If true, accessors will be named after the field and not include a {@code get} or {@code set} - * prefix. If true and {@code chain} is omitted, {@code chain} defaults to {@code true}. + * prefix. If true and {@code chain} is omitted, {@code chain} defaults to {@code true}.
+ * NB: This setting has no effect on {@code @With}; they always get a "with" prefix.
* default: false * * @return Whether or not to make fluent methods (named {@code fieldName()}, not for example {@code setFieldName}). @@ -54,6 +55,14 @@ public @interface Accessors { */ boolean chain() default false; + /** + * If true, generated accessors will be marked {@code final}. + * default: false + * + * @return Whether or not accessors should be marked {@code final}. + */ + boolean makeFinal() default false; + /** * If present, only fields with any of the stated prefixes are given the getter/setter treatment. * Note that a prefix only counts if the next character is NOT a lowercase character or the last diff --git a/src/core/lombok/javac/handlers/HandleAccessors.java b/src/core/lombok/javac/handlers/HandleAccessors.java index 60466d78..ac0ace4f 100644 --- a/src/core/lombok/javac/handlers/HandleAccessors.java +++ b/src/core/lombok/javac/handlers/HandleAccessors.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2021 The Project Lombok Authors. + * Copyright (C) 2012-2022 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 @@ -44,5 +44,6 @@ public class HandleAccessors extends JavacAnnotationHandler { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.ACCESSORS_FLAG_USAGE, "@Accessors"); deleteAnnotationIfNeccessary(annotationNode, Accessors.class); + if (annotation.isMarking()) annotationNode.addWarning("Accessors on its own does nothing. Set at least one parameter"); } } diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 7a7e41f9..86eb9fda 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2022 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 @@ -33,6 +33,7 @@ import java.util.Map; import lombok.AccessLevel; import lombok.ConfigurationKeys; +import lombok.experimental.Accessors; import lombok.experimental.Delegate; import lombok.Getter; import lombok.core.AST.Kind; @@ -169,7 +170,7 @@ public class HandleGetter extends JavacAnnotationHandler { return; } - JCVariableDecl fieldDecl = (JCVariableDecl)fieldNode.get(); + JCVariableDecl fieldDecl = (JCVariableDecl) fieldNode.get(); if (lazy) { if ((fieldDecl.mods.flags & Flags.PRIVATE) == 0 || (fieldDecl.mods.flags & Flags.FINAL) == 0) { @@ -186,14 +187,15 @@ public class HandleGetter extends JavacAnnotationHandler { } } - String methodName = toGetterName(fieldNode); + AnnotationValues accessors = getAccessorsForField(fieldNode); + String methodName = toGetterName(fieldNode, accessors); if (methodName == null) { source.addWarning("Not generating getter for this field: It does not fit your @Accessors prefix list."); return; } - for (String altName : toAllGetterNames(fieldNode)) { + for (String altName : toAllGetterNames(fieldNode, accessors)) { switch (methodExists(altName, fieldNode, false, 0)) { case EXISTS_BY_LOMBOK: return; @@ -221,8 +223,10 @@ public class HandleGetter extends JavacAnnotationHandler { // Remember the type; lazy will change it JCExpression methodType = cloneType(treeMaker, copyType(treeMaker, fieldNode), source); + AnnotationValues accessors = JavacHandlerUtil.getAccessorsForField(field); // Generate the methodName; lazy will change the field type - Name methodName = field.toName(toGetterName(field)); + Name methodName = field.toName(toGetterName(field, accessors)); + boolean makeFinal = shouldMakeFinal(field, accessors); List statements; JCTree toClearOfMarkers = null; @@ -260,6 +264,7 @@ public class HandleGetter extends JavacAnnotationHandler { } if (isFieldDeprecated(field)) annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.nil())); + if (makeFinal) access |= Flags.FINAL; JCMethodDecl decl = recursiveSetGeneratedBy(treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType, methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source); @@ -270,7 +275,6 @@ public class HandleGetter extends JavacAnnotationHandler { } } decl.mods.annotations = decl.mods.annotations.appendList(delegates); - if (addSuppressWarningsUnchecked) { ListBuffer suppressions = new ListBuffer(); if (!Boolean.FALSE.equals(field.getAst().readConfiguration(ConfigurationKeys.ADD_SUPPRESSWARNINGS_ANNOTATIONS))) { diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index 1b675e8c..04fa8b77 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2022 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 @@ -31,6 +31,7 @@ import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.Setter; import lombok.core.AST.Kind; +import lombok.experimental.Accessors; import lombok.core.AnnotationValues; import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; @@ -146,8 +147,9 @@ public class HandleSetter extends JavacAnnotationHandler { return; } + AnnotationValues accessors = JavacHandlerUtil.getAccessorsForField(fieldNode); JCVariableDecl fieldDecl = (JCVariableDecl) fieldNode.get(); - String methodName = toSetterName(fieldNode); + String methodName = toSetterName(fieldNode, accessors); if (methodName == null) { fieldNode.addWarning("Not generating setter for this field: It does not fit your @Accessors prefix list."); @@ -159,7 +161,7 @@ public class HandleSetter extends JavacAnnotationHandler { return; } - for (String altName : toAllSetterNames(fieldNode)) { + for (String altName : toAllSetterNames(fieldNode, accessors)) { switch (methodExists(altName, fieldNode, false, 1)) { case EXISTS_BY_LOMBOK: return; @@ -184,9 +186,11 @@ public class HandleSetter extends JavacAnnotationHandler { } public static JCMethodDecl createSetter(long access, JavacNode field, JavacTreeMaker treeMaker, JavacNode source, List onMethod, List onParam) { - String setterName = toSetterName(field); - boolean returnThis = shouldReturnThis(field); - return createSetter(access, false, field, treeMaker, setterName, null, null, returnThis, source, onMethod, onParam); + AnnotationValues accessors = JavacHandlerUtil.getAccessorsForField(field); + String setterName = toSetterName(field, accessors); + boolean returnThis = shouldReturnThis(field, accessors); + JCMethodDecl setter = createSetter(access, false, field, treeMaker, setterName, null, null, returnThis, source, onMethod, onParam); + return setter; } public static JCMethodDecl createSetter(long access, boolean deprecate, JavacNode field, JavacTreeMaker treeMaker, String setterName, Name paramName, Name booleanFieldToSet, boolean shouldReturnThis, JavacNode source, List onMethod, List onParam) { @@ -198,8 +202,7 @@ public class HandleSetter extends JavacAnnotationHandler { returnStatement = treeMaker.Return(treeMaker.Ident(field.toName("this"))); } - JCMethodDecl d = createSetter(access, deprecate, field, treeMaker, setterName, paramName, booleanFieldToSet, returnType, returnStatement, source, onMethod, onParam); - return d; + return createSetter(access, deprecate, field, treeMaker, setterName, paramName, booleanFieldToSet, returnType, returnStatement, source, onMethod, onParam); } public static JCMethodDecl createSetterWithRecv(long access, boolean deprecate, JavacNode field, JavacTreeMaker treeMaker, String setterName, Name paramName, Name booleanFieldToSet, boolean shouldReturnThis, JavacNode source, List onMethod, List onParam, JCVariableDecl recv) { @@ -270,6 +273,8 @@ public class HandleSetter extends JavacAnnotationHandler { annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.nil())); } + AnnotationValues accessors = JavacHandlerUtil.getAccessorsForField(field); + if (shouldMakeFinal(field, accessors)) access |= Flags.FINAL; JCMethodDecl methodDef; if (recv != null && treeMaker.hasMethodDefWithRecvParam()) { methodDef = treeMaker.MethodDefWithRecvParam(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType, diff --git a/src/core/lombok/javac/handlers/HandleWith.java b/src/core/lombok/javac/handlers/HandleWith.java index 47f78b1e..c7fa0531 100644 --- a/src/core/lombok/javac/handlers/HandleWith.java +++ b/src/core/lombok/javac/handlers/HandleWith.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2021 The Project Lombok Authors. + * Copyright (C) 2012-2022 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 @@ -33,6 +33,7 @@ import lombok.With; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.configuration.CheckerFrameworkVersion; +import lombok.experimental.Accessors; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; @@ -158,8 +159,9 @@ public class HandleWith extends JavacAnnotationHandler { return; } + AnnotationValues accessors = getAccessorsForField(fieldNode); JCVariableDecl fieldDecl = (JCVariableDecl) fieldNode.get(); - String methodName = toWithName(fieldNode); + String methodName = toWithName(fieldNode, accessors); if (methodName == null) { fieldNode.addWarning("Not generating a withX method for this field: It does not fit your @Accessors prefix list."); @@ -187,7 +189,7 @@ public class HandleWith extends JavacAnnotationHandler { return; } - for (String altName : toAllWithNames(fieldNode)) { + for (String altName : toAllWithNames(fieldNode, accessors)) { switch (methodExists(altName, fieldNode, false, 1)) { case EXISTS_BY_LOMBOK: return; @@ -282,7 +284,10 @@ public class HandleWith extends JavacAnnotationHandler { if (isFieldDeprecated(field)) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.nil())); - if (makeAbstract) access = access | Flags.ABSTRACT; + if (makeAbstract) access |= Flags.ABSTRACT; + AnnotationValues accessors = JavacHandlerUtil.getAccessorsForField(field); + boolean makeFinal = shouldMakeFinal(field, accessors); + if (makeFinal) access |= Flags.FINAL; JCMethodDecl decl = recursiveSetGeneratedBy(maker.MethodDef(maker.Modifiers(access, annsOnMethod), methodName, returnType, methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source); copyJavadoc(field, decl, CopyJavadoc.WITH); diff --git a/src/core/lombok/javac/handlers/HandleWithBy.java b/src/core/lombok/javac/handlers/HandleWithBy.java index 4ba4337e..ff67fd9f 100644 --- a/src/core/lombok/javac/handlers/HandleWithBy.java +++ b/src/core/lombok/javac/handlers/HandleWithBy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 The Project Lombok Authors. + * Copyright (C) 2020-2022 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 @@ -34,6 +34,7 @@ import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.LombokImmutableList; import lombok.core.configuration.CheckerFrameworkVersion; +import lombok.experimental.Accessors; import lombok.experimental.WithBy; import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; @@ -158,8 +159,9 @@ public class HandleWithBy extends JavacAnnotationHandler { return; } + AnnotationValues accessors = JavacHandlerUtil.getAccessorsForField(fieldNode); JCVariableDecl fieldDecl = (JCVariableDecl) fieldNode.get(); - String methodName = toWithByName(fieldNode); + String methodName = toWithByName(fieldNode, accessors); if (methodName == null) { fieldNode.addWarning("Not generating a withXBy method for this field: It does not fit your @Accessors prefix list."); @@ -181,7 +183,7 @@ public class HandleWithBy extends JavacAnnotationHandler { return; } - for (String altName : toAllWithByNames(fieldNode)) { + for (String altName : toAllWithByNames(fieldNode, accessors)) { switch (methodExists(altName, fieldNode, false, 1)) { case EXISTS_BY_LOMBOK: return; @@ -326,6 +328,9 @@ public class HandleWithBy extends JavacAnnotationHandler { if (isFieldDeprecated(field)) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.nil())); if (makeAbstract) access = access | Flags.ABSTRACT; + AnnotationValues accessors = JavacHandlerUtil.getAccessorsForField(field); + boolean makeFinal = shouldMakeFinal(field, accessors); + if (makeFinal) access |= Flags.FINAL; createRelevantNonNullAnnotation(source, param); JCMethodDecl decl = recursiveSetGeneratedBy(maker.MethodDef(maker.Modifiers(access, annsOnMethod), methodName, returnType, methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source); diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index d3532f79..53a518b4 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2021 The Project Lombok Authors. + * Copyright (C) 2009-2022 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 @@ -572,6 +572,14 @@ public class JavacHandlerUtil { return HandlerUtil.toAllGetterNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); } + /** + * Translates the given field into all possible getter names. + * Convenient wrapper around {@link HandlerUtil#toAllGetterNames(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static java.util.List toAllGetterNames(JavacNode field, AnnotationValues accessors) { + return HandlerUtil.toAllGetterNames(field.getAst(), accessors, field.getName(), isBoolean(field)); + } + /** * @return the likely getter name for the stated field. (e.g. private boolean foo; to isFoo). * @@ -581,6 +589,15 @@ public class JavacHandlerUtil { return HandlerUtil.toGetterName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); } + /** + * @return the likely getter name for the stated field. (e.g. private boolean foo; to isFoo). + * + * Convenient wrapper around {@link HandlerUtil#toGetterName(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static String toGetterName(JavacNode field, AnnotationValues accessors) { + return HandlerUtil.toGetterName(field.getAst(), accessors, field.getName(), isBoolean(field)); + } + /** * Translates the given field into all possible setter names. * Convenient wrapper around {@link HandlerUtil#toAllSetterNames(lombok.core.AnnotationValues, CharSequence, boolean)}. @@ -589,6 +606,14 @@ public class JavacHandlerUtil { return HandlerUtil.toAllSetterNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); } + /** + * Translates the given field into all possible setter names. + * Convenient wrapper around {@link HandlerUtil#toAllSetterNames(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static java.util.List toAllSetterNames(JavacNode field, AnnotationValues accessors) { + return HandlerUtil.toAllSetterNames(field.getAst(), accessors, field.getName(), isBoolean(field)); + } + /** * @return the likely setter name for the stated field. (e.g. private boolean foo; to setFoo). * @@ -598,6 +623,15 @@ public class JavacHandlerUtil { return HandlerUtil.toSetterName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); } + /** + * @return the likely setter name for the stated field. (e.g. private boolean foo; to setFoo). + * + * Convenient wrapper around {@link HandlerUtil#toSetterName(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static String toSetterName(JavacNode field, AnnotationValues accessors) { + return HandlerUtil.toSetterName(field.getAst(), accessors, field.getName(), isBoolean(field)); + } + /** * Translates the given field into all possible with names. * Convenient wrapper around {@link HandlerUtil#toAllWithNames(lombok.core.AnnotationValues, CharSequence, boolean)}. @@ -606,6 +640,14 @@ public class JavacHandlerUtil { return HandlerUtil.toAllWithNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); } + /** + * Translates the given field into all possible with names. + * Convenient wrapper around {@link HandlerUtil#toAllWithNames(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static java.util.List toAllWithNames(JavacNode field, AnnotationValues accessors) { + return HandlerUtil.toAllWithNames(field.getAst(), accessors, field.getName(), isBoolean(field)); + } + /** * Translates the given field into all possible withBy names. * Convenient wrapper around {@link HandlerUtil#toAllWithByNames(lombok.core.AnnotationValues, CharSequence, boolean)}. @@ -614,6 +656,14 @@ public class JavacHandlerUtil { return HandlerUtil.toAllWithByNames(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); } + /** + * Translates the given field into all possible withBy names. + * Convenient wrapper around {@link HandlerUtil#toAllWithByNames(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static java.util.List toAllWithByNames(JavacNode field, AnnotationValues accessors) { + return HandlerUtil.toAllWithByNames(field.getAst(), accessors, field.getName(), isBoolean(field)); + } + /** * @return the likely with name for the stated field. (e.g. private boolean foo; to withFoo). * @@ -623,6 +673,15 @@ public class JavacHandlerUtil { return HandlerUtil.toWithName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); } + /** + * @return the likely with name for the stated field. (e.g. private boolean foo; to withFoo). + * + * Convenient wrapper around {@link HandlerUtil#toWithName(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static String toWithName(JavacNode field, AnnotationValues accessors) { + return HandlerUtil.toWithName(field.getAst(), accessors, field.getName(), isBoolean(field)); + } + /** * @return the likely withBy name for the stated field. (e.g. private boolean foo; to withFooBy). * @@ -632,18 +691,34 @@ public class JavacHandlerUtil { return HandlerUtil.toWithByName(field.getAst(), getAccessorsForField(field), field.getName(), isBoolean(field)); } + /** + * @return the likely withBy name for the stated field. (e.g. private boolean foo; to withFooBy). + * + * Convenient wrapper around {@link HandlerUtil#toWithByName(lombok.core.AnnotationValues, CharSequence, boolean)}. + */ + public static String toWithByName(JavacNode field, AnnotationValues accessors) { + return HandlerUtil.toWithByName(field.getAst(), accessors, field.getName(), isBoolean(field)); + } + /** * When generating a setter, the setter either returns void (beanspec) or Self (fluent). * This method scans for the {@code Accessors} annotation to figure that out. */ - public static boolean shouldReturnThis(JavacNode field) { + public static boolean shouldReturnThis(JavacNode field, AnnotationValues accessors) { if ((((JCVariableDecl) field.get()).mods.flags & Flags.STATIC) != 0) return false; - AnnotationValues accessors = JavacHandlerUtil.getAccessorsForField(field); - return HandlerUtil.shouldReturnThis0(accessors, field.getAst()); } + /** + * When generating a setter/getter/wither, should it be made final? + */ + public static boolean shouldMakeFinal(JavacNode field, AnnotationValues accessors) { + if ((((JCVariableDecl) field.get()).mods.flags & Flags.STATIC) != 0) return false; + + return HandlerUtil.shouldMakeFinal0(accessors, field.getAst()); + } + public static JCExpression cloneSelfType(JavacNode childOfType) { JavacNode typeNode = childOfType; JavacTreeMaker maker = childOfType.getTreeMaker(); @@ -696,9 +771,12 @@ public class JavacHandlerUtil { } public static AnnotationValues getAccessorsForField(JavacNode field) { + AnnotationValues values = null; + for (JavacNode node : field.down()) { if (annotationTypeMatches(Accessors.class, node)) { - return createAnnotation(Accessors.class, node); + values = createAnnotation(Accessors.class, node); + break; } } @@ -706,13 +784,15 @@ public class JavacHandlerUtil { while (current != null) { for (JavacNode node : current.down()) { if (annotationTypeMatches(Accessors.class, node)) { - return createAnnotation(Accessors.class, node); + AnnotationValues onType = createAnnotation(Accessors.class, node); + values = values == null ? onType : values.integrate(onType); + break; } } current = current.up(); } - return AnnotationValues.of(Accessors.class, field); + return values == null ? AnnotationValues.of(Accessors.class, field) : values; } /** @@ -2185,7 +2265,7 @@ public class JavacHandlerUtil { Javac.setDocComment(cu, n, javadoc); } }); - return shouldReturnThis(node) ? addReturnsThisIfNeeded(out) : out; + return shouldReturnThis(node, JavacHandlerUtil.getAccessorsForField(node)) ? addReturnsThisIfNeeded(out) : out; } } -- cgit