diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 7375d310..c9ea2572 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -3,6 +3,7 @@ Lombok Changelog ### v1.18.47 "Edgy Guinea Pig" * BUGFIX: `@SneakyThrows` usage on JDK26 no longer results in class files that require `lombok.jar` to be on the runtime classpath (which should not be neccessary). [#4040](https://github.com/projectlombok/lombok/issues/4022). +* FEATURE: New [config key](https://projectlombok.org/features/configuration) `lombok.checkReturnValueAnnotation` (values: `none`, `lombok`; default: `none`) lets lombok generate `@lombok.CheckReturnValue` on generated methods where the return value should not be ignored, such as `@With` methods and `@Builder.build()`. A future lombok release may flip the default to `lombok`. [#4013](https://github.com/projectlombok/lombok/pull/4013). * PROMOTION: `@SuperBuilder` has been promoted to the main package. Otherwise, no changes have been made to the annotation. The old experimental annotation will remain for a few versions, at which point it will be marked as a deprecated annotation. Eventually it'll be removed. If you had `lombok.config` configuration for this annotation, the configuration keys for this feature have been renamed. * OLD-CRUFT: `lombok.experimental.Wither` and `lombok.Delegate` are deprecated remnants; these features were moved (to respectively `lombok.With` and `lombok.experimental.Delegate` over 5 years ago. They are now removed entirely. If your project is dependent on an older version of lombok which still has those; fret not, lombok still processes these annotations. It just no longer includes them in the jar. diff --git a/src/core/lombok/CheckReturnValue.java b/src/core/lombok/CheckReturnValue.java index 1a8f2dcb..0f6ae868 100644 --- a/src/core/lombok/CheckReturnValue.java +++ b/src/core/lombok/CheckReturnValue.java @@ -35,7 +35,7 @@ import java.lang.annotation.Target; * Static analysis tools (Error Prone, IntelliJ, SpotBugs) recognize {@code @CheckReturnValue} * by simple class name, regardless of package, and will warn when the return value is discarded. *

- * If you want to opt in, you can add {@code lombok.addCheckReturnValueAnnotation = true} to + * If you want to opt in, you can add {@code lombok.checkReturnValueAnnotation = lombok} to * {@code lombok.config}. */ @Target({ElementType.METHOD}) diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 321b1de6..9dafc083 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -25,6 +25,7 @@ import java.util.List; import lombok.core.configuration.CallSuperType; import lombok.core.configuration.CapitalizationStrategy; +import lombok.core.configuration.CheckReturnValueFlavor; import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.configuration.ConfigurationKey; import lombok.core.configuration.FlagUsageType; @@ -91,12 +92,13 @@ public class ConfigurationKeys { public static final ConfigurationKey ADD_LOMBOK_GENERATED_ANNOTATIONS = new ConfigurationKey("lombok.addLombokGeneratedAnnotation", "Generate @lombok.Generated on all generated code (default: true).") {}; /** - * lombok configuration: {@code lombok.addCheckReturnValueAnnotation} = {@code true} | {@code false}. + * lombok configuration: {@code lombok.checkReturnValueAnnotation} = [{@code none} | {@code lombok}]. * - * If {@code true}, lombok generates {@code @lombok.CheckReturnValue} on generated methods where the return value should not be ignored, + * If set to {@code lombok}, lombok generates {@code @lombok.CheckReturnValue} on generated methods where the return value should not be ignored, * such as {@code @With} methods and {@code @Builder}'s {@code build()} method. + * If set to {@code none} (the current default), no such annotation is emitted. A future lombok release may flip the default to {@code lombok}. */ - public static final ConfigurationKey ADD_CHECK_RETURN_VALUE_ANNOTATIONS = new ConfigurationKey("lombok.addCheckReturnValueAnnotation", "Generate @lombok.CheckReturnValue on generated methods where the return value should not be ignored (default: false).") {}; + public static final ConfigurationKey CHECK_RETURN_VALUE_ANNOTATION = new ConfigurationKey("lombok.checkReturnValueAnnotation", "Which @CheckReturnValue annotation flavor to emit on generated methods. Values: none, lombok (default: none).") {}; /** * lombok configuration: {@code lombok.extern.findbugs.addSuppressFBWarnings} = {@code true} | {@code false}. diff --git a/src/core/lombok/core/configuration/CheckReturnValueFlavor.java b/src/core/lombok/core/configuration/CheckReturnValueFlavor.java new file mode 100644 index 00000000..b313ee73 --- /dev/null +++ b/src/core/lombok/core/configuration/CheckReturnValueFlavor.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2026 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.core.configuration; + +/** Used for lombok configuration to select which {@code @CheckReturnValue} annotation flavor to emit on generated methods. */ +public enum CheckReturnValueFlavor { + NONE, LOMBOK; +} diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 8255d1cb..df0bb234 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -116,6 +116,7 @@ import lombok.core.AnnotationValues; import lombok.core.AnnotationValues.AnnotationValue; import lombok.core.LombokImmutableList; import lombok.core.TypeResolver; +import lombok.core.configuration.CheckReturnValueFlavor; import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.configuration.NullAnnotationLibrary; import lombok.core.configuration.NullCheckExceptionType; @@ -2128,8 +2129,15 @@ public class EclipseHandlerUtil { } public static Annotation[] addCheckReturnValue(EclipseNode node, ASTNode source, Annotation[] originalAnnotationArray) { - if (!Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_CHECK_RETURN_VALUE_ANNOTATIONS))) return originalAnnotationArray; - return addAnnotation(source, originalAnnotationArray, LOMBOK_CHECK_RETURN_VALUE); + CheckReturnValueFlavor flavor = node.getAst().readConfiguration(ConfigurationKeys.CHECK_RETURN_VALUE_ANNOTATION); + if (flavor == null) flavor = CheckReturnValueFlavor.NONE; + switch (flavor) { + case LOMBOK: + return addAnnotation(source, originalAnnotationArray, LOMBOK_CHECK_RETURN_VALUE); + case NONE: + default: + return originalAnnotationArray; + } } static Annotation[] addAnnotation(ASTNode source, Annotation[] originalAnnotationArray, char[][] annotationTypeFqn) { diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 722bb436..0f134b8e 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -96,6 +96,7 @@ import lombok.core.AnnotationValues.AnnotationValue; import lombok.core.CleanupTask; import lombok.core.LombokImmutableList; import lombok.core.TypeResolver; +import lombok.core.configuration.CheckReturnValueFlavor; import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.configuration.NullAnnotationLibrary; import lombok.core.configuration.NullCheckExceptionType; @@ -1555,8 +1556,16 @@ public class JavacHandlerUtil { } public static void addCheckReturnValue(JCModifiers mods, JavacNode node, JavacNode source) { - if (!Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_CHECK_RETURN_VALUE_ANNOTATIONS))) return; - addAnnotation(mods, node, source, "lombok.CheckReturnValue", null); + CheckReturnValueFlavor flavor = node.getAst().readConfiguration(ConfigurationKeys.CHECK_RETURN_VALUE_ANNOTATION); + if (flavor == null) flavor = CheckReturnValueFlavor.NONE; + switch (flavor) { + case LOMBOK: + addAnnotation(mods, node, source, "lombok.CheckReturnValue", null); + return; + case NONE: + default: + return; + } } public static void addAnnotation(JCModifiers mods, JavacNode node, JavacNode source, String annotationTypeFqn, JCExpression arg) { diff --git a/test/transform/resource/before/CheckReturnValueBuilder.java b/test/transform/resource/before/CheckReturnValueBuilder.java index a4a904ee..83c9e551 100644 --- a/test/transform/resource/before/CheckReturnValueBuilder.java +++ b/test/transform/resource/before/CheckReturnValueBuilder.java @@ -1,4 +1,4 @@ -//CONF: lombok.addCheckReturnValueAnnotation = true +//CONF: lombok.checkReturnValueAnnotation = lombok @lombok.Builder class CheckReturnValueBuilder { private final int x; diff --git a/test/transform/resource/before/CheckReturnValueOff.java b/test/transform/resource/before/CheckReturnValueOff.java index 3a4aebca..7197fc75 100644 --- a/test/transform/resource/before/CheckReturnValueOff.java +++ b/test/transform/resource/before/CheckReturnValueOff.java @@ -1,4 +1,4 @@ -//CONF: lombok.addCheckReturnValueAnnotation = false +//CONF: lombok.checkReturnValueAnnotation = none import lombok.With; class CheckReturnValueOff { @With final int x; diff --git a/test/transform/resource/before/CheckReturnValueWith.java b/test/transform/resource/before/CheckReturnValueWith.java index 167aaae8..6ed0dba9 100644 --- a/test/transform/resource/before/CheckReturnValueWith.java +++ b/test/transform/resource/before/CheckReturnValueWith.java @@ -1,4 +1,4 @@ -//CONF: lombok.addCheckReturnValueAnnotation = true +//CONF: lombok.checkReturnValueAnnotation = lombok import lombok.With; class CheckReturnValueWith { @With final int x; diff --git a/website/templates/features/configuration.html b/website/templates/features/configuration.html index 6675d61e..a09b0c81 100644 --- a/website/templates/features/configuration.html +++ b/website/templates/features/configuration.html @@ -89,6 +89,12 @@ Many flavors are available: jspecify (recommended), checkerframework (recommended), jakarta, eclipse, jetbrains, netbeans, androidx, findbugs, spring, jml, javax (=JSR305; not recommended), android.support (deprecated within android), or define your own via CUSTOM:fully.qualified.NonNullAnnotation:fully.qualified.NullableAnnotation; if your nullity annotation is solely of the type use style (it annotates types, such as eclipse's and checkerframework's offerings, versus annotating methods and parameters), the format is CUSTOM:TYPE_USE:nonnullanno:nullableanno.
This feature was added in lombok v1.18.12.
+

+ Lombok can add a @CheckReturnValue annotation to generated methods whose return value should not be ignored, such as withX methods and @Builder's build() method. Static analysis tools (IntelliJ, Error Prone, SpotBugs) will then warn when callers discard the result. By default, no such annotation is added. Enable with: +

    +
  1. lombok.checkReturnValueAnnotation = <flavor>
  2. +
+ Currently the only non-none flavor is lombok, which emits @lombok.CheckReturnValue. A future lombok release may flip the default to lombok.

Lombok can be configured to add @lombok.Generated annotations to all generated nodes where possible; useful for JaCoCo (which has built in support), or other style checkers and code coverage tools: