diff options
74 files changed, 865 insertions, 107 deletions
diff --git a/buildScripts/eclipse-run-tests.template b/buildScripts/eclipse-run-tests.template index 530341ab..0c00c236 100644 --- a/buildScripts/eclipse-run-tests.template +++ b/buildScripts/eclipse-run-tests.template @@ -20,7 +20,7 @@ <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/lombok/@JAVAC_LOCATION@" path="3" type="2"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/lombok/lib/test/com.google.guava-guava.jar" path="3" type="2"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/lombok/lib/test/com.google.code.findbugs-findbugs.jar" path="3" type="2"/> "/> - <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="lombok"/> </runtimeClasspathEntry> "/> + <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="true" project="lombok"/> </runtimeClasspathEntry> "/> </listAttribute> <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.@JAVA_VERSION@"/> diff --git a/buildScripts/website.ant.xml b/buildScripts/website.ant.xml index aae2285f..19b995d3 100644 --- a/buildScripts/website.ant.xml +++ b/buildScripts/website.ant.xml @@ -155,6 +155,9 @@ such as converting the changelog into HTML, and creating javadoc. <param name="transformationName" value="Singular-snippet" /> </antcall> <antcall target="-integrateSnippet"> + <param name="transformationName" value="experimental/var" /> + </antcall> + <antcall target="-integrateSnippet"> <param name="transformationName" value="experimental/Delegate" /> </antcall> <antcall target="-integrateSnippet"> diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 474ca2f5..d5aa7ba1 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,10 +1,15 @@ Lombok Changelog ---------------- -### v1.16.11 "Edgy Guinea Pig" -* v1.16.10 is the latest release -* BUGFIX: Annotation Processors that use ecj internally (dagger) no longer give linkage errors [Issue #1218](https://github.com/rzwitserloot/lombok/issues/1218) +### v1.16.13 "Edgy Guinea Pig" +* v1.16.12 is the latest stable release of Project Lombok. + +### v1.16.12 (December 5th, 2016) +* FEATURE: `var` is the mutable sister of `val`. For now experimental, and opt-in using `ALLOW` in the flagUsage configuration key. Thanks for the contribution, Bulgakov Alexander. +* CHANGE: `@Value` and `@FieldDefaults` no longer touch static fields [Issue #1254](https://github.com/rzwitserloot/lombok/issues/1254) * BUGFIX: `val` in lambda expressions now work as expected [Issue #911](https://github.com/rzwitserloot/lombok/issues/911) +* BUGFIX: `Getter(lazy=true)` now emits an error message when used on a transient field [Issue #1236](https://github.com/rzwitserloot/lombok/issues/1236) +* BUGFIX: Annotation Processors that use ecj internally (dagger) no longer give linkage errors [Issue #1218](https://github.com/rzwitserloot/lombok/issues/1218) * PLATFORM: Red Hat JBoss Developer Studio is now correctly identified by the installer [Issue #1164](https://github.com/rzwitserloot/lombok/issues/1164) * BUGFIX: delombok: for-loops with initializers that are not local variables would be generated incorrectly [Issue #1076](https://github.com/rzwitserloot/lombok/issues/1076) diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 04decf69..132bde8d 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -283,7 +283,8 @@ public class ConfigurationKeys { * If set, <em>any</em> usage of {@code val} results in a warning / error. */ public static final ConfigurationKey<FlagUsageType> VAL_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.val.flagUsage", "Emit a warning or error if 'val' is used.") {}; - + public static final ConfigurationKey<FlagUsageType> VAR_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.var.flagUsage", "Emit a warning or error if 'var' is used.") {}; + // ##### Extern ##### // ----- Logging ----- diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index 20b10601..4fdb7216 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -30,7 +30,7 @@ public class Version { // ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries). // Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example. // Official builds always end in an even number. (Since 0.10.2). - private static final String VERSION = "1.16.11"; + private static final String VERSION = "1.16.13"; private static final String RELEASE_NAME = "Edgy Guinea Pig"; // private static final String RELEASE_NAME = "Candid Duck"; diff --git a/src/core/lombok/core/configuration/AllowHelper.java b/src/core/lombok/core/configuration/AllowHelper.java new file mode 100644 index 00000000..3873b055 --- /dev/null +++ b/src/core/lombok/core/configuration/AllowHelper.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 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; + +import java.util.Collection; +import java.util.Collections; + +import lombok.ConfigurationKeys; + +public final class AllowHelper { + private final static Collection<? extends ConfigurationKey<?>> ALLOWABLE = Collections.singleton(ConfigurationKeys.VAR_FLAG_USAGE); + + private AllowHelper() { + // Prevent instantiation + } + + public static boolean isAllowable(ConfigurationKey<?> key) { + return ALLOWABLE.contains(key); + } +} diff --git a/src/core/lombok/core/configuration/FlagUsageType.java b/src/core/lombok/core/configuration/FlagUsageType.java index b7053b7c..8717c22b 100644 --- a/src/core/lombok/core/configuration/FlagUsageType.java +++ b/src/core/lombok/core/configuration/FlagUsageType.java @@ -23,5 +23,5 @@ package lombok.core.configuration; /** Used for lombok configuration to flag usages of certain lombok feature. */ public enum FlagUsageType { - WARNING, ERROR; + WARNING, ERROR, ALLOW; } diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index a9a4be78..ef4ac7d6 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -43,6 +43,7 @@ import lombok.core.AST; import lombok.core.AnnotationValues; import lombok.core.JavaIdentifiers; import lombok.core.LombokNode; +import lombok.core.configuration.AllowHelper; import lombok.core.configuration.ConfigurationKey; import lombok.core.configuration.FlagUsageType; import lombok.experimental.Accessors; @@ -97,10 +98,14 @@ public class HandlerUtil { public static void handleFlagUsage(LombokNode<?, ?, ?> node, ConfigurationKey<FlagUsageType> key, String featureName) { FlagUsageType fut = node.getAst().readConfiguration(key); + if (fut == null && AllowHelper.isAllowable(key)) { + node.addError("Use of " + featureName + " is disabled by default. Please add '" + key.getKeyName() + " = " + FlagUsageType.ALLOW + "' to 'lombok.config' if you want to enable is."); + } + if (fut != null) { String msg = "Use of " + featureName + " is flagged according to lombok configuration."; if (fut == FlagUsageType.WARNING) node.addWarning(msg); - else node.addError(msg); + else if (fut == FlagUsageType.ERROR) node.addError(msg); } } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 0ff5a7f6..59d8f587 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1168,9 +1168,8 @@ public class EclipseHandlerUtil { if (params < minArgs || params > maxArgs) continue; } - if (def.annotations != null) for (Annotation anno : def.annotations) { - if (typeMatches(Tolerate.class, node, anno.type)) continue top; - } + + if (isTolerate(node, def)) continue top; return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } @@ -1181,6 +1180,13 @@ public class EclipseHandlerUtil { return MemberExistsResult.NOT_EXISTS; } + public static boolean isTolerate(EclipseNode node, AbstractMethodDeclaration def) { + if (def.annotations != null) for (Annotation anno : def.annotations) { + if (typeMatches(Tolerate.class, node, anno.type)) return true; + } + return false; + } + /** * Checks if there is a (non-default) constructor. In case of multiple constructors (overloading), only * the first constructor decides if EXISTS_BY_USER or EXISTS_BY_LOMBOK is returned. @@ -1198,9 +1204,7 @@ public class EclipseHandlerUtil { if (def instanceof ConstructorDeclaration) { if ((def.bits & ASTNode.IsDefaultConstructor) != 0) continue; - if (def.annotations != null) for (Annotation anno : def.annotations) { - if (typeMatches(Tolerate.class, node, anno.type)) continue top; - } + if (isTolerate(node, def)) continue; return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 4e0c4218..afa03538 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -652,7 +652,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { for (int i = 0; i < len; i++) { if (!(existing[i] instanceof MethodDeclaration)) continue; char[] existingName = existing[i].selector; - if (Arrays.equals(name, existingName)) return; + if (Arrays.equals(name, existingName) && !isTolerate(fieldNode, existing[i])) return; } String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName()); diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 85d1d4ed..a3b0585d 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -48,6 +48,7 @@ import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; +import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; import org.eclipse.jdt.internal.compiler.ast.Assignment; import org.eclipse.jdt.internal.compiler.ast.CharLiteral; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; @@ -381,6 +382,8 @@ public class HandleConstructor { } private static Expression getDefaultExpr(TypeReference type, int s, int e) { + boolean array = type instanceof ArrayTypeReference; + if (array) return new NullLiteral(s, e); char[] lastToken = type.getLastToken(); if (Arrays.equals(TypeConstants.BOOLEAN, lastToken)) return new FalseLiteral(s, e); if (Arrays.equals(TypeConstants.CHAR, lastToken)) return new CharLiteral(new char[] {'\'', '\\', '0', '\''}, s, e); diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java index 5ea5a210..702713fe 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 The Project Lombok Authors. + * Copyright (C) 2012-2016 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 @@ -97,14 +97,16 @@ public class HandleFieldDefaults extends EclipseASTAdapter { if (level != null && level != AccessLevel.NONE) { if ((field.modifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected)) == 0) { if (!hasAnnotation(PackagePrivate.class, fieldNode)) { - field.modifiers |= EclipseHandlerUtil.toEclipseModifier(level); + if ((field.modifiers & ClassFileConstants.AccStatic) == 0) { + field.modifiers |= EclipseHandlerUtil.toEclipseModifier(level); + } } } } if (makeFinal && (field.modifiers & ClassFileConstants.AccFinal) == 0) { if (!hasAnnotation(NonFinal.class, fieldNode)) { - if ((field.modifiers & ClassFileConstants.AccStatic) == 0 || field.initialization != null) { + if ((field.modifiers & ClassFileConstants.AccStatic) == 0) { field.modifiers |= ClassFileConstants.AccFinal; } } diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index 14f2fb72..77d678f2 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -183,6 +183,10 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { errorNode.addError("'lazy' requires the field to be private and final."); return; } + if ((field.modifiers & ClassFileConstants.AccTransient) != 0) { + errorNode.addError("'lazy' is not supported on transient fields."); + return; + } if (field.initialization == null) { errorNode.addError("'lazy' requires field initialization."); return; diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java index d4ae417c..d8901067 100644 --- a/src/core/lombok/eclipse/handlers/HandleVal.java +++ b/src/core/lombok/eclipse/handlers/HandleVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 The Project Lombok Authors. + * Copyright (C) 2010-2016 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 @@ -21,7 +21,8 @@ */ package lombok.eclipse.handlers; -import static lombok.core.handlers.HandlerUtil.*; +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; +import static lombok.eclipse.handlers.EclipseHandlerUtil.typeMatches; import lombok.ConfigurationKeys; import lombok.val; import lombok.core.HandlerPriority; @@ -29,11 +30,14 @@ import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseASTAdapter; import lombok.eclipse.EclipseASTVisitor; import lombok.eclipse.EclipseNode; +import lombok.experimental.var; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.ForStatement; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.NullLiteral; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.mangosdk.spi.ProviderFor; /* @@ -44,8 +48,13 @@ import org.mangosdk.spi.ProviderFor; @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; - handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); + TypeReference type = local.type; + boolean isVal = typeMatches(val.class, localNode, type); + boolean isVar = typeMatches(var.class, localNode, type); + if (!(isVal || isVar)) return; + + if (isVal) handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); + if (isVar) handleFlagUsage(localNode, ConfigurationKeys.VAR_FLAG_USAGE, "var"); boolean variableOfForEach = false; @@ -54,23 +63,30 @@ public class HandleVal extends EclipseASTAdapter { variableOfForEach = fs.elementVariable == local; } + String annotation = isVal ? "val" : "var"; if (local.initialization == null && !variableOfForEach) { - localNode.addError("'val' on a local variable requires an initializer expression"); + localNode.addError("'" + annotation + "' on a local variable requires an initializer expression"); return; } if (local.initialization instanceof ArrayInitializer) { - localNode.addError("'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); + localNode.addError("'" + annotation + "' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); return; } - if (localNode.directUp().get() instanceof ForStatement) { + if (isVal && localNode.directUp().get() instanceof ForStatement) { localNode.addError("'val' is not allowed in old-style for loops"); return; } if (local.initialization != null && local.initialization.getClass().getName().equals("org.eclipse.jdt.internal.compiler.ast.LambdaExpression")) { - localNode.addError("'val' is not allowed with lambda expressions."); + localNode.addError("'" + annotation + "' is not allowed with lambda expressions."); + return; + } + + if(isVar && local.initialization instanceof NullLiteral) { + localNode.addError("variable initializer is 'null'"); + return; } } } diff --git a/src/core/lombok/experimental/FieldDefaults.java b/src/core/lombok/experimental/FieldDefaults.java index dbc4993b..384abda5 100644 --- a/src/core/lombok/experimental/FieldDefaults.java +++ b/src/core/lombok/experimental/FieldDefaults.java @@ -33,9 +33,9 @@ import lombok.AccessLevel; * <p> * Complete documentation is found at <a href="https://projectlombok.org/features/experimental/FieldDefaults.html">the project lombok features page for @FieldDefaults</a>. * <p> - * If {@code makeFinal} is {@code true}, then each field that is not annotated with {@code @NonFinal} will have the {@code final} modifier added. + * If {@code makeFinal} is {@code true}, then each (instance) field that is not annotated with {@code @NonFinal} will have the {@code final} modifier added. * <p> - * If {@code level} is set, then each field that is package private (i.e. no access modifier) and does not have the {@code @PackagePrivate} annotation will + * If {@code level} is set, then each (instance) field that is package private (i.e. no access modifier) and does not have the {@code @PackagePrivate} annotation will * have the appropriate access level modifier added. */ @Target(ElementType.TYPE) diff --git a/src/core/lombok/experimental/NonFinal.java b/src/core/lombok/experimental/NonFinal.java index 0c31dd2a..12a45d22 100644 --- a/src/core/lombok/experimental/NonFinal.java +++ b/src/core/lombok/experimental/NonFinal.java @@ -28,7 +28,7 @@ import java.lang.annotation.Target; /** * Used to indicate the explicit intention for the annotated entity to <em>not</em> be {@code final}. - * Currently used by {@code FieldDefaults} to avoid having it make a field final. + * Currently used by {@code FieldDefaults} and {@code Value} to avoid having it make a field final. */ @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) diff --git a/src/core/lombok/experimental/PackagePrivate.java b/src/core/lombok/experimental/PackagePrivate.java index bfe5638b..42002818 100644 --- a/src/core/lombok/experimental/PackagePrivate.java +++ b/src/core/lombok/experimental/PackagePrivate.java @@ -28,7 +28,7 @@ import java.lang.annotation.Target; /** * Used to indicate the explicit intention for the annotated entity to have the <em>package private</em> access level. - * Currently used by {@code FieldDefaults} to avoid having it make a field one of {@code public}, {@code protected}, or {@code private}. + * Currently used by {@code FieldDefaults} and {@code Value} to avoid having it make a field one of {@code public}, {@code protected}, or {@code private}. */ @Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.SOURCE) diff --git a/src/core/lombok/experimental/var.java b/src/core/lombok/experimental/var.java new file mode 100644 index 00000000..d8de8b19 --- /dev/null +++ b/src/core/lombok/experimental/var.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010-2013 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.experimental; + +/** + * like val but not final + */ +public @interface var { +} diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index b83e3d5f..9c3c9d03 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -608,8 +608,9 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { for (JavacNode child : builderType.down()) { if (child.getKind() != Kind.METHOD) continue; - Name existingName = ((JCMethodDecl) child.get()).name; - if (existingName.equals(fieldName)) return; + JCMethodDecl methodDecl = (JCMethodDecl) child.get(); + Name existingName = methodDecl.name; + if (existingName.equals(fieldName) && !isTolerate(fieldNode, methodDecl)) return; } String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName()); diff --git a/src/core/lombok/javac/handlers/HandleDelegate.java b/src/core/lombok/javac/handlers/HandleDelegate.java index 680e7745..49bef769 100644 --- a/src/core/lombok/javac/handlers/HandleDelegate.java +++ b/src/core/lombok/javac/handlers/HandleDelegate.java @@ -312,7 +312,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { for (TypeMirror param : sig.type.getTypeVariables()) { Name name = ((TypeVar) param).tsym.name; - ListBuffer<JCExpression> bounds = types.getBounds((TypeVar) param).isEmpty() ? null : new ListBuffer<JCExpression>(); + ListBuffer<JCExpression> bounds = new ListBuffer<JCExpression>(); for (Type type : types.getBounds((TypeVar) param)) { bounds.append(JavacResolution.typeToJCTree(type, annotation.getAst(), true)); } diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java index 12c22059..52f6c39c 100644 --- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 The Project Lombok Authors. + * Copyright (C) 2012-2016 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 @@ -84,14 +84,16 @@ public class HandleFieldDefaults extends JavacASTAdapter { if (level != null && level != AccessLevel.NONE) { if ((field.mods.flags & (Flags.PUBLIC | Flags.PRIVATE | Flags.PROTECTED)) == 0) { if (!hasAnnotationAndDeleteIfNeccessary(PackagePrivate.class, fieldNode)) { - field.mods.flags |= toJavacModifier(level); + if ((field.mods.flags & Flags.STATIC) == 0) { + field.mods.flags |= toJavacModifier(level); + } } } } if (makeFinal && (field.mods.flags & Flags.FINAL) == 0) { if (!hasAnnotationAndDeleteIfNeccessary(NonFinal.class, fieldNode)) { - if ((field.mods.flags & Flags.STATIC) == 0 || field.init != null) { + if ((field.mods.flags & Flags.STATIC) == 0) { field.mods.flags |= Flags.FINAL; } } diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index a330dbc1..0a2fe362 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-2016 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 @@ -182,6 +182,10 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { source.addError("'lazy' requires the field to be private and final."); return; } + if ((fieldDecl.mods.flags & Flags.TRANSIENT) != 0) { + source.addError("'lazy' is not supported on transient fields."); + return; + } if (fieldDecl.init == null) { source.addError("'lazy' requires field initialization."); return; diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index 337ab2d7..2976eabe 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 The Project Lombok Authors. + * Copyright (C) 2010-2016 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 @@ -21,11 +21,12 @@ */ package lombok.javac.handlers; -import static lombok.core.handlers.HandlerUtil.*; +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; import static lombok.javac.handlers.JavacHandlerUtil.*; import lombok.ConfigurationKeys; import lombok.val; import lombok.core.HandlerPriority; +import lombok.experimental.var; import lombok.javac.JavacASTAdapter; import lombok.javac.JavacASTVisitor; import lombok.javac.JavacNode; @@ -42,6 +43,7 @@ import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCForLoop; +import com.sun.tools.javac.tree.JCTree.JCLiteral; import com.sun.tools.javac.tree.JCTree.JCNewArray; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; @@ -50,21 +52,31 @@ import com.sun.tools.javac.util.List; @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. @ResolutionResetNeeded public class HandleVal extends JavacASTAdapter { - @Override public void visitLocal(JavacNode localNode, JCVariableDecl local) { + + private static boolean eq(String typeTreeToString, String key) { + return (typeTreeToString.equals(key) || typeTreeToString.equals("lombok." + key)); + } + + @Override + public void visitLocal(JavacNode localNode, JCVariableDecl local) { JCTree typeTree = local.vartype; if (typeTree == null) return; String typeTreeToString = typeTree.toString(); - if (!typeTreeToString.equals("val") && !typeTreeToString.equals("lombok.val")) return; - if (!typeMatches(val.class, localNode, typeTree)) return; - - handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); - + + if (!(eq(typeTreeToString, "val") || eq(typeTreeToString, "var"))) return; + boolean isVal = typeMatches(val.class, localNode, typeTree); + boolean isVar = typeMatches(var.class, localNode, typeTree); + if (!(isVal || isVar)) return; + + if (isVal) handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); + if (isVar) handleFlagUsage(localNode, ConfigurationKeys.VAR_FLAG_USAGE, "var"); + JCTree parentRaw = localNode.directUp().get(); - if (parentRaw instanceof JCForLoop) { + if (isVal && parentRaw instanceof JCForLoop) { localNode.addError("'val' is not allowed in old-style for loops"); return; } - + JCExpression rhsOfEnhancedForLoop = null; if (local.init == null) { if (parentRaw instanceof JCEnhancedForLoop) { @@ -72,21 +84,26 @@ public class HandleVal extends JavacASTAdapter { if (efl.var == local) rhsOfEnhancedForLoop = efl.expr; } } - + + final String annotation = typeTreeToString; if (rhsOfEnhancedForLoop == null && local.init == null) { - localNode.addError("'val' on a local variable requires an initializer expression"); + localNode.addError("'" + annotation + "' on a local variable requires an initializer expression"); return; + } - + if (local.init instanceof JCNewArray && ((JCNewArray)local.init).elemtype == null) { - localNode.addError("'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); + localNode.addError("'" + annotation + "' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })"); return; } - - if (localNode.shouldDeleteLombokAnnotations()) JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, "lombok.val"); - - local.mods.flags |= Flags.FINAL; - + + if (localNode.shouldDeleteLombokAnnotations()) { + JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, val.class.getName()); + JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, var.class.getName()); + } + + if (isVal) local.mods.flags |= Flags.FINAL; + if (!localNode.shouldDeleteLombokAnnotations()) { JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), typeTree, localNode.getContext()); local.mods.annotations = local.mods.annotations == null ? List.of(valAnnotation) : local.mods.annotations.append(valAnnotation); @@ -102,6 +119,9 @@ public class HandleVal extends JavacASTAdapter { try { if (rhsOfEnhancedForLoop == null) { if (local.init.type == null) { + if (isVar && local.init instanceof JCLiteral && ((JCLiteral) local.init).value == null) { + localNode.addError("variable initializer is 'null'"); + } JavacResolution resolver = new JavacResolution(localNode.getContext()); try { type = ((JCExpression) resolver.resolveMethodMember(localNode).get(local.init)).type; @@ -149,7 +169,7 @@ public class HandleVal extends JavacASTAdapter { } localNode.getAst().setChanged(); } catch (JavacResolution.TypeNotConvertibleException e) { - localNode.addError("Cannot use 'val' here because initializer expression does not have a representable type: " + e.getMessage()); + localNode.addError("Cannot use '" + annotation + "' here because initializer expression does not have a representable type: " + e.getMessage()); local.vartype = JavacResolution.createJavaLangObject(localNode.getAst()); } } catch (RuntimeException e) { diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index fdc8a262..efa67604 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -605,10 +605,7 @@ public class JavacHandlerUtil { if (params < minArgs || params > maxArgs) continue; } - List<JCAnnotation> annotations = md.getModifiers().getAnnotations(); - if (annotations != null) for (JCAnnotation anno : annotations) { - if (typeMatches(Tolerate.class, node, anno.getAnnotationType())) continue top; - } + if (isTolerate(node, md)) continue top; return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } @@ -619,6 +616,14 @@ public class JavacHandlerUtil { return MemberExistsResult.NOT_EXISTS; } + public static boolean isTolerate(JavacNode node, JCTree.JCMethodDecl md) { + List<JCAnnotation> annotations = md.getModifiers().getAnnotations(); + if (annotations != null) for (JCTree.JCAnnotation anno : annotations) { + if (typeMatches(Tolerate.class, node, anno.getAnnotationType())) return true; + } + return false; + } + /** * Checks if there is a (non-default) constructor. In case of multiple constructors (overloading), only * the first constructor decides if EXISTS_BY_USER or EXISTS_BY_LOMBOK is returned. @@ -634,10 +639,7 @@ public class JavacHandlerUtil { JCMethodDecl md = (JCMethodDecl) def; if (md.name.contentEquals("<init>")) { if ((md.mods.flags & Flags.GENERATEDCONSTR) != 0) continue; - List<JCAnnotation> annotations = md.getModifiers().getAnnotations(); - if (annotations != null) for (JCAnnotation anno : annotations) { - if (typeMatches(Tolerate.class, node, anno.getAnnotationType())) continue top; - } + if (isTolerate(node, md)) continue; return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; } } diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index 2b8dfbaa..e4dd7b26 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -21,11 +21,6 @@ */ package lombok.eclipse.agent; -import static lombok.eclipse.handlers.EclipseHandlerUtil.*; -import static lombok.eclipse.Eclipse.*; - -import java.lang.reflect.Field; - import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; @@ -43,6 +38,11 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import java.lang.reflect.Field; + +import static lombok.eclipse.Eclipse.poss; +import static lombok.eclipse.handlers.EclipseHandlerUtil.makeType; + public class PatchVal { // This is half of the work for 'val' support - the other half is in PatchValEclipse. This half is enough for ecj. @@ -84,31 +84,44 @@ public class PatchVal { return true; } - public static boolean couldBeVal(TypeReference ref) { + public static boolean couldBe(String key, TypeReference ref) { + String[] keyParts = key.split("\\."); if (ref instanceof SingleTypeReference) { char[] token = ((SingleTypeReference)ref).token; - return matches("val", token); + return matches(keyParts[keyParts.length - 1], token); } if (ref instanceof QualifiedTypeReference) { char[][] tokens = ((QualifiedTypeReference)ref).tokens; - if (tokens == null || tokens.length != 2) return false; - return matches("lombok", tokens[0]) && matches("val", tokens[1]); + if (keyParts.length != tokens.length) return false; + for(int i = 0; i < tokens.length; ++i) { + String part = keyParts[i]; + char[] token = tokens[i]; + if (!matches(part, token)) return false; + } + return true; } return false; } - - private static boolean isVal(TypeReference ref, BlockScope scope) { - if (!couldBeVal(ref)) return false; - + + private static boolean is(TypeReference ref, BlockScope scope, String key) { + if (!couldBe(key, ref)) return false; + TypeBinding resolvedType = ref.resolvedType; if (resolvedType == null) resolvedType = ref.resolveType(scope, false); if (resolvedType == null) return false; char[] pkg = resolvedType.qualifiedPackageName(); char[] nm = resolvedType.qualifiedSourceName(); - return matches("lombok", pkg) && matches("val", nm); + int pkgFullLength = pkg.length > 0 ? pkg.length + 1: 0; + char[] fullName = new char[pkgFullLength + nm.length]; + if(pkg.length > 0) { + System.arraycopy(pkg, 0, fullName, 0, pkg.length); + fullName[pkg.length] = '.'; + } + System.arraycopy(nm, 0, fullName, pkgFullLength, nm.length); + return matches(key, fullName); } public static final class Reflection { @@ -132,13 +145,17 @@ public class PatchVal { if (local == null || !LocalDeclaration.class.equals(local.getClass())) return false; boolean decomponent = false; - if (!isVal(local.type, scope)) return false; + boolean val = isVal(local, scope); + boolean var = isVar(local, scope); + if (!(val || var)) return false; StackTraceElement[] st = new Throwable().getStackTrace(); for (int i = 0; i < st.length - 2 && i < 10; i++) { if (st[i].getClassName().equals("lombok.launch.PatchFixesHider$Val")) { - if (st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") && - st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement")) return false; + boolean valInForStatement = val && + st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") && + st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement"); + if (valInForStatement) return false; break; } } @@ -187,23 +204,33 @@ public class PatchVal { } } - local.modifiers |= ClassFileConstants.AccFinal; + if(val) local.modifiers |= ClassFileConstants.AccFinal; local.annotations = addValAnnotation(local.annotations, local.type, scope); local.type = replacement != null ? replacement : new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(local.type, 3)); return false; } + private static boolean isVar(LocalDeclaration local, BlockScope scope) { + return is(local.type, scope, "lombok.experimental.var"); + } + + private static boolean isVal(LocalDeclaration local, BlockScope scope) { + return is(local.type, scope, "lombok.val"); + } + public static boolean handleValForForEach(ForeachStatement forEach, BlockScope scope) { if (forEach.elementVariable == null) return false; - if (!isVal(forEach.elementVariable.type, scope)) return false; + boolean val = isVal(forEach.elementVariable, scope); + boolean var = isVar(forEach.elementVariable, scope); + if (!(val || var)) return false; TypeBinding component = getForEachComponentType(forEach.collection, scope); if (component == null) return false; TypeReference replacement = makeType(component, forEach.elementVariable.type, false); - forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal; + if (val) forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal; forEach.elementVariable.annotations = addValAnnotation(forEach.elementVariable.annotations, forEach.elementVariable.type, scope); forEach.elementVariable.type = replacement != null ? replacement : new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(forEach.elementVariable.type, 3)); diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java index 7d5f36f4..505eb767 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java @@ -47,6 +47,7 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.parser.Parser; @@ -65,7 +66,9 @@ public class PatchValEclipse { ForeachStatement foreachDecl = (ForeachStatement) astStack[astPtr]; ASTNode init = foreachDecl.collection; if (init == null) return; - if (foreachDecl.elementVariable == null || !PatchVal.couldBeVal(foreachDecl.elementVariable.type)) return; + boolean val = couldBeVal(foreachDecl.elementVariable.type); + boolean var = couldBeVar(foreachDecl.elementVariable.type); + if (foreachDecl.elementVariable == null || !(val || var)) return; try { if (Reflection.iterableCopyField != null) Reflection.iterableCopyField.set(foreachDecl.elementVariable, init); @@ -88,7 +91,9 @@ public class PatchValEclipse { if (!(variableDecl instanceof LocalDeclaration)) return; ASTNode init = variableDecl.initialization; if (init == null) return; - if (!PatchVal.couldBeVal(variableDecl.type)) return; + boolean val = couldBeVal(variableDecl.type); + boolean var = couldBeVar(variableDecl.type); + if (!(val || var)) return; try { if (Reflection.initCopyField != null) Reflection.initCopyField.set(variableDecl, init); @@ -97,6 +102,10 @@ public class PatchValEclipse { } } + private static boolean couldBeVar(TypeReference type) { + return PatchVal.couldBe("lombok.experimental.var", type); + } + public static void addFinalAndValAnnotationToSingleVariableDeclaration(Object converter, SingleVariableDeclaration out, LocalDeclaration in) { @SuppressWarnings("unchecked") List<IExtendedModifier> modifiers = out.modifiers(); addFinalAndValAnnotationToModifierList(converter, modifiers, out.getAST(), in); @@ -115,7 +124,7 @@ public class PatchValEclipse { Annotation valAnnotation = null; for (Annotation ann : in.annotations) { - if (PatchVal.couldBeVal(ann.type)) { + if (couldBeVal(ann.type)) { found = true; valAnnotation = ann; break; @@ -167,6 +176,10 @@ public class PatchValEclipse { } } + private static boolean couldBeVal(TypeReference type) { + return PatchVal.couldBe("lombok.val", type); + } + public static Modifier createModifier(AST ast, ModifierKeyword keyword, int start, int end) { Modifier modifier = null; try { diff --git a/test/core/src/lombok/AbstractRunTests.java b/test/core/src/lombok/AbstractRunTests.java index f564d0dc..d044a39f 100644 --- a/test/core/src/lombok/AbstractRunTests.java +++ b/test/core/src/lombok/AbstractRunTests.java @@ -57,10 +57,16 @@ public abstract class AbstractRunTests { public final FileTester createTester(final DirectoryRunner.TestParams params, final File file) throws IOException { ConfigurationKeysLoader.LoaderLoader.loadAllConfigurationKeys(); - final LombokTestSource sourceDirectives = LombokTestSource.readDirectives(file); - if (sourceDirectives.isIgnore()) return null; - if (!sourceDirectives.versionWithinLimit(params.getVersion())) return null; - if (!sourceDirectives.versionWithinLimit(getClasspathVersion())) return null; + AssertionError directiveFailure = null; + LombokTestSource sourceDirectives = null; + try { + sourceDirectives = LombokTestSource.readDirectives(file); + if (sourceDirectives.isIgnore()) return null; + if (!sourceDirectives.versionWithinLimit(params.getVersion())) return null; + if (!sourceDirectives.versionWithinLimit(getClasspathVersion())) return null; + } catch (AssertionError ae) { + directiveFailure = ae; + } String fileName = file.getName(); final LombokTestSource expected = LombokTestSource.read(params.getAfterDirectory(), params.getMessagesDirectory(), fileName); @@ -68,23 +74,26 @@ public abstract class AbstractRunTests { if (expected.isIgnore()) return null; if (!expected.versionWithinLimit(params.getVersion())) return null; + final LombokTestSource sourceDirectives_ = sourceDirectives; + final AssertionError directiveFailure_ = directiveFailure; return new FileTester() { @Override public void runTest() throws Throwable { + if (directiveFailure_ != null) throw directiveFailure_; LinkedHashSet<CompilerMessage> messages = new LinkedHashSet<CompilerMessage>(); StringWriter writer = new StringWriter(); LombokConfiguration.overrideConfigurationResolverFactory(new ConfigurationResolverFactory() { @Override public ConfigurationResolver createResolver(AST<?, ?, ?> ast) { - return sourceDirectives.getConfiguration(); + return sourceDirectives_.getConfiguration(); } }); - boolean changed = transformCode(messages, writer, file, sourceDirectives.getSpecifiedEncoding(), sourceDirectives.getFormatPreferences()); - boolean forceUnchanged = sourceDirectives.forceUnchanged() || sourceDirectives.isSkipCompareContent(); + boolean changed = transformCode(messages, writer, file, sourceDirectives_.getSpecifiedEncoding(), sourceDirectives_.getFormatPreferences()); + boolean forceUnchanged = sourceDirectives_.forceUnchanged() || sourceDirectives_.isSkipCompareContent(); if (params.expectChanges() && !forceUnchanged && !changed) messages.add(new CompilerMessage(-1, -1, true, "not flagged modified")); if (!params.expectChanges() && changed) messages.add(new CompilerMessage(-1, -1, true, "unexpected modification")); - compare(file.getName(), expected, writer.toString(), messages, params.printErrors(), sourceDirectives.isSkipCompareContent() || expected.isSkipCompareContent()); + compare(file.getName(), expected, writer.toString(), messages, params.printErrors(), sourceDirectives_.isSkipCompareContent() || expected.isSkipCompareContent()); } }; } diff --git a/test/core/src/lombok/LombokTestSource.java b/test/core/src/lombok/LombokTestSource.java index cd7cd166..16f9f49f 100644 --- a/test/core/src/lombok/LombokTestSource.java +++ b/test/core/src/lombok/LombokTestSource.java @@ -130,7 +130,7 @@ public class LombokTestSource { private static final Pattern IGNORE_PATTERN = Pattern.compile("^\\s*ignore\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private static final Pattern UNCHANGED_PATTERN = Pattern.compile("^\\s*unchanged\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); - private static final Pattern SKIP_COMPARE_CONTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?compare[- ]?content\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); + private static final Pattern SKIP_COMPARE_CONTENT_PATTERN = Pattern.compile("^\\s*skip[- ]?compare[- ]?contents?\\s*(?:[-:].*)?$", Pattern.CASE_INSENSITIVE); private LombokTestSource(File file, String content, List<CompilerMessageMatcher> messages, List<String> directives) { this.file = file; diff --git a/test/transform/resource/after-delombok/BuilderWithTolerate.java b/test/transform/resource/after-delombok/BuilderWithTolerate.java new file mode 100644 index 00000000..6dc7e248 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderWithTolerate.java @@ -0,0 +1,59 @@ + +import lombok.experimental.Tolerate; + +public class BuilderWithTolerate { + private final int value; + + public static void main(String[] args) { + BuilderWithTolerate.builder().value("42").build(); + } + + + public static class BuilderWithTolerateBuilder { + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + private int value; + + @Tolerate + public BuilderWithTolerateBuilder value(String s) { + return this.value(Integer.parseInt(s)); + } + + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + BuilderWithTolerateBuilder() { + } + + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public BuilderWithTolerateBuilder value(final int value) { + this.value = value; + return this; + } + + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public BuilderWithTolerate build() { + return new BuilderWithTolerate(value); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public java.lang.String toString() { + return "BuilderWithTolerate.BuilderWithTolerateBuilder(value=" + this.value + ")"; + } + } + + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + BuilderWithTolerate(final int value) { + this.value = value; + } + + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public static BuilderWithTolerateBuilder builder() { + return new BuilderWithTolerateBuilder(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/FieldDefaults.java b/test/transform/resource/after-delombok/FieldDefaults.java index 8a84f442..6f866a9a 100644 --- a/test/transform/resource/after-delombok/FieldDefaults.java +++ b/test/transform/resource/after-delombok/FieldDefaults.java @@ -1,4 +1,5 @@ class FieldDefaults1 { + static int STATIC = 3; final int x; int y; FieldDefaults1(int x) { @@ -6,6 +7,7 @@ class FieldDefaults1 { } } class FieldDefaults2 { + static int STATIC = 3; int x; private int y; }
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/GetterLazyTransient.java b/test/transform/resource/after-delombok/GetterLazyTransient.java new file mode 100644 index 00000000..dbebad90 --- /dev/null +++ b/test/transform/resource/after-delombok/GetterLazyTransient.java @@ -0,0 +1,26 @@ +class GetterLazyTransient { + private final java.util.concurrent.atomic.AtomicReference<java.lang.Object> nonTransientField = new java.util.concurrent.atomic.AtomicReference<java.lang.Object>(); + private final transient int transientField = 2; + private final transient int nonLazyTransientField = 3; + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public int getNonTransientField() { + java.lang.Object value = this.nonTransientField.get(); + if (value == null) { + synchronized (this.nonTransientField) { + value = this.nonTransientField.get(); + if (value == null) { + final int actualValue = 1; + value = actualValue; + this.nonTransientField.set(value); + } + } + } + return (java.lang.Integer) value; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public int getNonLazyTransientField() { + return this.nonLazyTransientField; + } +} diff --git a/test/transform/resource/after-delombok/NoArgsConstructorForce.java b/test/transform/resource/after-delombok/NoArgsConstructorForce.java new file mode 100644 index 00000000..c1127c7c --- /dev/null +++ b/test/transform/resource/after-delombok/NoArgsConstructorForce.java @@ -0,0 +1,14 @@ + +public class NoArgsConstructorForce { + private final int[] i; + private final Object[] o; + private final java.util.List<?>[] fullQualifiedList; + + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public NoArgsConstructorForce() { + this.i = null; + this.o = null; + this.fullQualifiedList = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValNullInit.java b/test/transform/resource/after-delombok/ValNullInit.java new file mode 100644 index 00000000..f0834a63 --- /dev/null +++ b/test/transform/resource/after-delombok/ValNullInit.java @@ -0,0 +1,5 @@ +class ValNullInit { + void method() { + final java.lang.Object x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValueStaticField.java b/test/transform/resource/after-delombok/ValueStaticField.java index cec136f4..b4d60724 100644 --- a/test/transform/resource/after-delombok/ValueStaticField.java +++ b/test/transform/resource/after-delombok/ValueStaticField.java @@ -1,6 +1,6 @@ final class ValueStaticField { - private static int x; - private static final String PASSWORD = "Ken sent me"; + static int x; + static String PASSWORD = "Ken sent me"; @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public ValueStaticField() { diff --git a/test/transform/resource/after-delombok/VarComplex.java b/test/transform/resource/after-delombok/VarComplex.java new file mode 100644 index 00000000..10b33943 --- /dev/null +++ b/test/transform/resource/after-delombok/VarComplex.java @@ -0,0 +1,20 @@ +public class VarComplex { + private String field = ""; + private static final int CONSTANT = 20; + public void testComplex() { + char[] shouldBeCharArray = field.toCharArray(); + int shouldBeInt = CONSTANT; + java.lang.Object lock = new Object(); + synchronized (lock) { + int field = 20; //Shadowing + int inner = 10; + switch (field) { + case 5: + char[] shouldBeCharArray2 = shouldBeCharArray; + int innerInner = inner; + + } + } + java.lang.String shouldBeString = field; //Unshadowing + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/VarInFor.java b/test/transform/resource/after-delombok/VarInFor.java new file mode 100644 index 00000000..363aeeff --- /dev/null +++ b/test/transform/resource/after-delombok/VarInFor.java @@ -0,0 +1,9 @@ +public class VarInFor { + public void enhancedFor() { + int[] list = new int[] {1, 2}; + for (int shouldBeInt : list) { + System.out.println(shouldBeInt); + int shouldBeInt2 = shouldBeInt; + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/VarInForOld.java b/test/transform/resource/after-delombok/VarInForOld.java new file mode 100644 index 00000000..bb510c0b --- /dev/null +++ b/test/transform/resource/after-delombok/VarInForOld.java @@ -0,0 +1,7 @@ +public class VarInForOld { + public void oldFor() { + for (int i = 0; i < 100; ++i) { + System.out.println(i); + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/VarModifier.java b/test/transform/resource/after-delombok/VarModifier.java new file mode 100644 index 00000000..9838cdf7 --- /dev/null +++ b/test/transform/resource/after-delombok/VarModifier.java @@ -0,0 +1,7 @@ +public class VarModifier { + private String field = ""; + public void testComplex() { + final char[] shouldBeFinalCharArray = field.toCharArray(); + char[] shouldBeCharArray = field.toCharArray(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/VarNullInit.java b/test/transform/resource/after-delombok/VarNullInit.java new file mode 100644 index 00000000..8ec2ea73 --- /dev/null +++ b/test/transform/resource/after-delombok/VarNullInit.java @@ -0,0 +1,6 @@ + +public class VarNullInit { + void method() { + java.lang.Object x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/BuilderWithTolerate.java b/test/transform/resource/after-ecj/BuilderWithTolerate.java new file mode 100644 index 00000000..0b9b46a0 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderWithTolerate.java @@ -0,0 +1,34 @@ +import lombok.Builder; +import lombok.experimental.Tolerate; +public @Builder class BuilderWithTolerate { + public static class BuilderWithTolerateBuilder { + private @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") int value; + public @Tolerate BuilderWithTolerateBuilder value(String s) { + return this.value(Integer.parseInt(s)); + } + @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderWithTolerateBuilder() { + super(); + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderWithTolerateBuilder value(final int value) { + this.value = value; + return this; + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderWithTolerate build() { + return new BuilderWithTolerate(value); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") java.lang.String toString() { + return (("BuilderWithTolerate.BuilderWithTolerateBuilder(value=" + this.value) + ")"); + } + } + private final int value; + public static void main(String[] args) { + BuilderWithTolerate.builder().value("42").build(); + } + @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderWithTolerate(final int value) { + super(); + this.value = value; + } + public static @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderWithTolerateBuilder builder() { + return new BuilderWithTolerateBuilder(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/FieldDefaults.java b/test/transform/resource/after-ecj/FieldDefaults.java index e76c1251..a6941b7b 100644 --- a/test/transform/resource/after-ecj/FieldDefaults.java +++ b/test/transform/resource/after-ecj/FieldDefaults.java @@ -1,14 +1,20 @@ @lombok.experimental.FieldDefaults(makeFinal = true) class FieldDefaults1 { + static int STATIC = 3; final int x; @lombok.experimental.NonFinal int y; + <clinit>() { + } FieldDefaults1(int x) { super(); this.x = x; } } @lombok.experimental.FieldDefaults(level = lombok.AccessLevel.PRIVATE) class FieldDefaults2 { + static int STATIC = 3; @lombok.experimental.PackagePrivate int x; private int y; + <clinit>() { + } FieldDefaults2() { super(); } diff --git a/test/transform/resource/after-ecj/GetterLazyTransient.java b/test/transform/resource/after-ecj/GetterLazyTransient.java new file mode 100644 index 00000000..9bc0d9ae --- /dev/null +++ b/test/transform/resource/after-ecj/GetterLazyTransient.java @@ -0,0 +1,28 @@ +class GetterLazyTransient { + private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.lang.Object> nonTransientField = new java.util.concurrent.atomic.AtomicReference<java.lang.Object>(); + private final transient @lombok.Getter(lazy = true) int transientField = 2; + private final transient @lombok.Getter int nonLazyTransientField = 3; + GetterLazyTransient() { + super(); + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") int getNonTransientField() { + java.lang.Object value = this.nonTransientField.get(); + if ((value == null)) + { + synchronized (this.nonTransientField) + { + value = this.nonTransientField.get(); + if ((value == null)) + { + final int actualValue = 1; + value = actualValue; + this.nonTransientField.set(value); + } + } + } + return (java.lang.Integer) value; + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") int getNonLazyTransientField() { + return this.nonLazyTransientField; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/NoArgsConstructorForce.java b/test/transform/resource/after-ecj/NoArgsConstructorForce.java new file mode 100644 index 00000000..d0e69b0d --- /dev/null +++ b/test/transform/resource/after-ecj/NoArgsConstructorForce.java @@ -0,0 +1,12 @@ +import lombok.NoArgsConstructor; +public @NoArgsConstructor(force = true) class NoArgsConstructorForce { + private final int[] i; + private final Object[] o; + private final java.util.List<?>[] fullQualifiedList; + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") NoArgsConstructorForce() { + super(); + this.i = null; + this.o = null; + this.fullQualifiedList = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValNullInit.java b/test/transform/resource/after-ecj/ValNullInit.java new file mode 100644 index 00000000..bd89c023 --- /dev/null +++ b/test/transform/resource/after-ecj/ValNullInit.java @@ -0,0 +1,10 @@ +import lombok.val; + +class ValNullInit { + ValNullInit() { + super(); + } + void method() { + final @val java.lang.Object x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValueStaticField.java b/test/transform/resource/after-ecj/ValueStaticField.java index 4ce84a02..75e337ce 100644 --- a/test/transform/resource/after-ecj/ValueStaticField.java +++ b/test/transform/resource/after-ecj/ValueStaticField.java @@ -1,7 +1,7 @@ import lombok.Value; final @Value class ValueStaticField { - private static int x; - private static final String PASSWORD = "Ken sent me"; + static int x; + static String PASSWORD = "Ken sent me"; <clinit>() { } public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") boolean equals(final java.lang.Object o) { diff --git a/test/transform/resource/after-ecj/VarComplex.java b/test/transform/resource/after-ecj/VarComplex.java new file mode 100644 index 00000000..10c456eb --- /dev/null +++ b/test/transform/resource/after-ecj/VarComplex.java @@ -0,0 +1,26 @@ +import lombok.experimental.var; +public class VarComplex { + private String field = ""; + private static final int CONSTANT = 20; + <clinit>() { + } + public VarComplex() { + super(); + } + public void testComplex() { + @var char[] shouldBeCharArray = field.toCharArray(); + @var int shouldBeInt = CONSTANT; + @var java.lang.Object lock = new Object(); + synchronized (lock) + { + @var int field = 20; + @var int inner = 10; + switch (field) { + case 5 : + @var char[] shouldBeCharArray2 = shouldBeCharArray; + @var int innerInner = inner; + } + } + @var java.lang.String shouldBeString = field; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/VarInFor.java b/test/transform/resource/after-ecj/VarInFor.java new file mode 100644 index 00000000..0192aaed --- /dev/null +++ b/test/transform/resource/after-ecj/VarInFor.java @@ -0,0 +1,14 @@ +import lombok.experimental.var; +public class VarInFor { + public VarInFor() { + super(); + } + public void enhancedFor() { + int[] list = new int[]{1, 2}; + for (@var int shouldBeInt : list) + { + System.out.println(shouldBeInt); + @var int shouldBeInt2 = shouldBeInt; + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/VarInForOld.java b/test/transform/resource/after-ecj/VarInForOld.java new file mode 100644 index 00000000..98fedf03 --- /dev/null +++ b/test/transform/resource/after-ecj/VarInForOld.java @@ -0,0 +1,12 @@ +import lombok.experimental.var; +public class VarInForOld { + public VarInForOld() { + super(); + } + public void oldFor() { + for (@var int i = 0;; (i < 100); ++ i) + { + System.out.println(i); + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/VarModifier.java b/test/transform/resource/after-ecj/VarModifier.java new file mode 100644 index 00000000..d11142ca --- /dev/null +++ b/test/transform/resource/after-ecj/VarModifier.java @@ -0,0 +1,12 @@ +import lombok.experimental.var; +public class VarModifier { + private String field = ""; + public VarModifier() { + super(); + } + public void testComplex() { + final @var char[] shouldBeFinalCharArray = field.toCharArray(); + @var char[] shouldBeCharArray = field.toCharArray(); + + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/VarNullInit.java b/test/transform/resource/after-ecj/VarNullInit.java new file mode 100644 index 00000000..3eb2d506 --- /dev/null +++ b/test/transform/resource/after-ecj/VarNullInit.java @@ -0,0 +1,9 @@ +import lombok.experimental.var; +public class VarNullInit { + public VarNullInit() { + super(); + } + void method() { + @var java.lang.Object x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/BuilderWithTolerate.java b/test/transform/resource/before/BuilderWithTolerate.java new file mode 100644 index 00000000..48fefce5 --- /dev/null +++ b/test/transform/resource/before/BuilderWithTolerate.java @@ -0,0 +1,18 @@ +import lombok.Builder; +import lombok.experimental.Tolerate; + +@Builder +public class BuilderWithTolerate { + private final int value; + + public static void main(String[] args) { + BuilderWithTolerate.builder().value("42").build(); + } + + public static class BuilderWithTolerateBuilder { + @Tolerate + public BuilderWithTolerateBuilder value(String s) { + return this.value(Integer.parseInt(s)); + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/FieldDefaults.java b/test/transform/resource/before/FieldDefaults.java index ffe89734..97389411 100644 --- a/test/transform/resource/before/FieldDefaults.java +++ b/test/transform/resource/before/FieldDefaults.java @@ -1,5 +1,6 @@ @lombok.experimental.FieldDefaults(makeFinal = true) class FieldDefaults1 { + static int STATIC = 3; int x; @lombok.experimental.NonFinal int y; @@ -10,6 +11,7 @@ class FieldDefaults1 { @lombok.experimental.FieldDefaults(level = lombok.AccessLevel.PRIVATE) class FieldDefaults2 { + static int STATIC = 3; @lombok.experimental.PackagePrivate int x; int y; }
\ No newline at end of file diff --git a/test/transform/resource/before/GetterLazyTransient.java b/test/transform/resource/before/GetterLazyTransient.java new file mode 100644 index 00000000..1a913669 --- /dev/null +++ b/test/transform/resource/before/GetterLazyTransient.java @@ -0,0 +1,10 @@ +class GetterLazyTransient { + @lombok.Getter(lazy=true) + private final int nonTransientField = 1; + + @lombok.Getter(lazy=true) + private final transient int transientField = 2; + + @lombok.Getter + private final transient int nonLazyTransientField = 3; +} diff --git a/test/transform/resource/before/NoArgsConstructorForce.java b/test/transform/resource/before/NoArgsConstructorForce.java new file mode 100644 index 00000000..48df1a37 --- /dev/null +++ b/test/transform/resource/before/NoArgsConstructorForce.java @@ -0,0 +1,8 @@ +import lombok.NoArgsConstructor; + +@NoArgsConstructor(force = true) +public class NoArgsConstructorForce { + private final int[] i; + private final Object[] o; + private final java.util.List<?>[] fullQualifiedList; +}
\ No newline at end of file diff --git a/test/transform/resource/before/ValNullInit.java b/test/transform/resource/before/ValNullInit.java new file mode 100644 index 00000000..649bc0cd --- /dev/null +++ b/test/transform/resource/before/ValNullInit.java @@ -0,0 +1,7 @@ +import lombok.val; + +class ValNullInit { + void method() { + val x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarComplex.java b/test/transform/resource/before/VarComplex.java new file mode 100644 index 00000000..bfaa8804 --- /dev/null +++ b/test/transform/resource/before/VarComplex.java @@ -0,0 +1,23 @@ +//CONF: lombok.var.flagUsage = ALLOW +import lombok.experimental.var; + +public class VarComplex { + private String field = ""; + private static final int CONSTANT = 20; + + public void testComplex() { + var shouldBeCharArray = field.toCharArray(); + var shouldBeInt = CONSTANT; + var lock = new Object(); + synchronized (lock) { + var field = 20; //Shadowing + var inner = 10; + switch (field) { + case 5: + var shouldBeCharArray2 = shouldBeCharArray; + var innerInner = inner; + } + } + var shouldBeString = field; //Unshadowing + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarInFor.java b/test/transform/resource/before/VarInFor.java new file mode 100644 index 00000000..cc8c387e --- /dev/null +++ b/test/transform/resource/before/VarInFor.java @@ -0,0 +1,12 @@ +//CONF: lombok.var.flagUsage = ALLOW +import lombok.experimental.var; + +public class VarInFor { + public void enhancedFor() { + int[] list = new int[] {1, 2}; + for (var shouldBeInt : list) { + System.out.println(shouldBeInt); + var shouldBeInt2 = shouldBeInt; + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarInForOld.java b/test/transform/resource/before/VarInForOld.java new file mode 100644 index 00000000..f90aba7f --- /dev/null +++ b/test/transform/resource/before/VarInForOld.java @@ -0,0 +1,10 @@ +//CONF: lombok.var.flagUsage = ALLOW +import lombok.experimental.var; + +public class VarInForOld { + public void oldFor() { + for (var i = 0; i < 100; ++i) { + System.out.println(i); + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarModifier.java b/test/transform/resource/before/VarModifier.java new file mode 100644 index 00000000..7250c1c5 --- /dev/null +++ b/test/transform/resource/before/VarModifier.java @@ -0,0 +1,11 @@ +//CONF: lombok.var.flagUsage = ALLOW +import lombok.experimental.var; + +public class VarModifier { + private String field = ""; + + public void testComplex() { + final var shouldBeFinalCharArray = field.toCharArray(); + var shouldBeCharArray = field.toCharArray(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarNullInit.java b/test/transform/resource/before/VarNullInit.java new file mode 100644 index 00000000..efdc9d9e --- /dev/null +++ b/test/transform/resource/before/VarNullInit.java @@ -0,0 +1,8 @@ +//CONF: lombok.var.flagUsage = ALLOW +import lombok.experimental.var; + +public class VarNullInit { + void method() { + var x = null; + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/VarWarning.java b/test/transform/resource/before/VarWarning.java new file mode 100644 index 00000000..85559587 --- /dev/null +++ b/test/transform/resource/before/VarWarning.java @@ -0,0 +1,10 @@ +//CONF: lombok.var.flagUsage = WARNING +//skip compare contents +import lombok.experimental.var; + +public class VarWarning { + public void isOkay() { + var x = "Warning"; + x.toLowerCase(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/GetterLazyTransient.java.messages b/test/transform/resource/messages-delombok/GetterLazyTransient.java.messages new file mode 100644 index 00000000..8c1873eb --- /dev/null +++ b/test/transform/resource/messages-delombok/GetterLazyTransient.java.messages @@ -0,0 +1 @@ +5 'lazy' is not supported on transient fields.
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/VarNullInit.java.messages b/test/transform/resource/messages-delombok/VarNullInit.java.messages new file mode 100644 index 00000000..190ab7c4 --- /dev/null +++ b/test/transform/resource/messages-delombok/VarNullInit.java.messages @@ -0,0 +1 @@ +6 variable initializer is 'null'
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/VarWarning.java.messages b/test/transform/resource/messages-delombok/VarWarning.java.messages new file mode 100644 index 00000000..48c89581 --- /dev/null +++ b/test/transform/resource/messages-delombok/VarWarning.java.messages @@ -0,0 +1 @@ +7 Use of var is flagged according to lombok configuration
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/GetterLazyTransient.java.messages b/test/transform/resource/messages-ecj/GetterLazyTransient.java.messages new file mode 100644 index 00000000..8c1873eb --- /dev/null +++ b/test/transform/resource/messages-ecj/GetterLazyTransient.java.messages @@ -0,0 +1 @@ +5 'lazy' is not supported on transient fields.
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/VarNullInit.java.messages b/test/transform/resource/messages-ecj/VarNullInit.java.messages new file mode 100644 index 00000000..190ab7c4 --- /dev/null +++ b/test/transform/resource/messages-ecj/VarNullInit.java.messages @@ -0,0 +1 @@ +6 variable initializer is 'null'
\ No newline at end of file diff --git a/test/transform/resource/messages-ecj/VarWarning.java.messages b/test/transform/resource/messages-ecj/VarWarning.java.messages new file mode 100644 index 00000000..48c89581 --- /dev/null +++ b/test/transform/resource/messages-ecj/VarWarning.java.messages @@ -0,0 +1 @@ +7 Use of var is flagged according to lombok configuration
\ No newline at end of file diff --git a/usage_examples/experimental/varExample_post.jpage b/usage_examples/experimental/varExample_post.jpage new file mode 100644 index 00000000..41c022d3 --- /dev/null +++ b/usage_examples/experimental/varExample_post.jpage @@ -0,0 +1,21 @@ +import java.util.ArrayList; +import lombok.var; + +public class ValExample { + public String example() { + ArrayList<String> example = new ArrayList<String>(); + example.add("Hello, World!"); + final String foo = example.get(0); + return foo.toLowerCase(); + } + + public void example2() { + ArrayList<String> list = new ArrayList<String>(); + list.add("zero"); + list.add("one"); + list.add("two"); + for(int i = 0; i < list.size(); ++i) { + System.out.printf("%d: %s\n", i, list.get(i)); + } + } +} diff --git a/usage_examples/experimental/varExample_pre.jpage b/usage_examples/experimental/varExample_pre.jpage new file mode 100644 index 00000000..0786c0df --- /dev/null +++ b/usage_examples/experimental/varExample_pre.jpage @@ -0,0 +1,21 @@ +import java.util.ArrayList; +import lombok.var; + +public class ValExample { + public String example() { + var example = new ArrayList<String>(); + example.add("Hello, World!"); + final var foo = example.get(0); + return foo.toLowerCase(); + } + + public void example2() { + var list = new ArrayList<String>(); + list.add("zero"); + list.add("one"); + list.add("two"); + for(var i = 0; i < list.size(); ++i) { + System.out.printf("%d: %s\n", i, list.get(i)); + } + } +} diff --git a/website/features/Value.html b/website/features/Value.html index 3bae89fc..6c86a77b 100644 --- a/website/features/Value.html +++ b/website/features/Value.html @@ -30,8 +30,8 @@ </p><p> In practice, <code>@Value</code> is shorthand for: <code>final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter</code>, except that explicitly including an implementation of any of the relevant methods simply means that part won't be generated and no warning will be emitted. For example, if you write your own <code>toString</code>, no error occurs, and lombok will not generate a <code>toString</code>. Also, <em>any</em> explicit constructor, no matter the arguments list, implies lombok will not generate a constructor. If you do want lombok to generate the all-args constructor, add <code>@AllArgsConstructor</code> to the class. You can mark any constructor or method with <code>@lombok.experimental.Tolerate</code> to hide them from lombok. </p><p> - It is possible to override the final-by-default and private-by-default behaviour using either an explicit access level on a field, or by using the <code>@NonFinal</code> or <code>@PackagePrivate</code> annotations.<br /> - It is possible to override any default behaviour for any of the 'parts' that make up <code>@Value</code> by explicitly using that annotation. + It is possible to override the final-by-default and private-by-default behavior using either an explicit access level on a field, or by using the <code>@NonFinal</code> or <code>@PackagePrivate</code> annotations.<br /> + It is possible to override any default behavior for any of the 'parts' that make up <code>@Value</code> by explicitly using that annotation. </p> </div> <div class="snippets"> diff --git a/website/features/experimental/Accessors.html b/website/features/experimental/Accessors.html index 434cbdbe..909c0873 100644 --- a/website/features/experimental/Accessors.html +++ b/website/features/experimental/Accessors.html @@ -97,7 +97,7 @@ </div> </div> <div class="footer"> - <a href="index.html">Back to experimental features</a> | <span class="disabled">Previous feature</span> | <a href="ExtensionMethod.html">Next feature (@ExtensionMethod)</a><br /> + <a href="index.html">Back to experimental features</a> | <a href="var.html">Previous feature (var)</a> | <a href="ExtensionMethod.html">Next feature (@ExtensionMethod)</a><br /> <a href="../../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright © 2009-2016 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span> </div> <div style="clear: both;"></div> diff --git a/website/features/experimental/FieldDefaults.html b/website/features/experimental/FieldDefaults.html index 90d5ae6d..a253198b 100644 --- a/website/features/experimental/FieldDefaults.html +++ b/website/features/experimental/FieldDefaults.html @@ -36,10 +36,10 @@ to each field in the annotated class or enum. It can also add <code>final</code> to each field in the annotated class or enum. </p> </p><p> - To add <code>final</code> to each field, use <code>@FieldDefaults(makeFinal=true)</code>. Any non-final field which must remain nonfinal + To add <code>final</code> to each (instance) field, use <code>@FieldDefaults(makeFinal=true)</code>. Any non-final field which must remain nonfinal can be annotated with <code>@NonFinal</code> (also in the <code>lombok.experimental</code> package). </p><p> - To add an access modifier to each field, use <code>@FieldDefaults(level=AccessLevel.PRIVATE)</code>. Any field that does not already have an + To add an access modifier to each (instance) field, use <code>@FieldDefaults(level=AccessLevel.PRIVATE)</code>. Any field that does not already have an access modifier (i.e. any field that looks like package private access) is changed to have the appropriate access modifier. Any package private field which must remain package private can be annotated with <code>@PackagePrivate</code> (also in the <code>lombok.experimental</code> package). </p> diff --git a/website/features/experimental/index.html b/website/features/experimental/index.html index f3893674..4a6d12bb 100644 --- a/website/features/experimental/index.html +++ b/website/features/experimental/index.html @@ -22,6 +22,8 @@ Features that receive positive community feedback and which seem to produce clean, flexible code will eventually become accepted as a core feature and move out of the experimental package. <dl> + <dt><a href="var.html"><code>@var</code></a></dt> + <dd>The same as @val but modifiable.</dd> <dt><a href="Accessors.html"><code>@Accessors</code></a></dt> <dd>A more fluent API for getters and setters.</dd> <dt><a href="ExtensionMethod.html"><code>@ExtensionMethod</code></a></dt> diff --git a/website/features/experimental/var.html b/website/features/experimental/var.html new file mode 100644 index 00000000..dde9c35e --- /dev/null +++ b/website/features/experimental/var.html @@ -0,0 +1,83 @@ +<!DOCTYPE html> +<html><head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <link rel="stylesheet" type="text/css" href="../../logi/reset.css" /> + <link rel="stylesheet" type="text/css" href="../features.css" /> + <link rel="shortcut icon" href="../../favicon.ico" type="image/x-icon" /> + <meta name="description" content="Spice up your java" /> + <title>EXPERIMENTAL – @var</title> +</head><body><div id="pepper"> + <div class="minimumHeight"></div> + <div class="meat"> + <div class="header"><a href="../../index.html">Project Lombok</a></div> + <h1>@var</h1> + <div class="byline">Modifiable local variables with a type inferred by assigning value.</div> + <div class="since"> + <h3>Since</h3> + <p> + @var was introduced as experimental feature in lombok v1.16.12. + </p> + </div> + <div class="experimental"> + <h3>Experimental</h3> + <p> + Experimental because: + <ul> + <li>This feature is very controversial.</li> + <li>There is <a href="http://openjdk.java.net/jeps/286">JEP 286</a> that should make the @var obsolete.</li> + </ul>Current status: <em>uncertain</em> - Currently we feel this feature cannot move out of experimental status. + </div> + <div class="overview"> + <h3>Overview</h3> + <p> + The <code>@var</code> has the same mission as the <a href="../val.html">@val</a> annotation but modifable. + </p> + </div> + <div class="snippets"> + <div class="pre"> + <h3>With Lombok</h3> + <div class="snippet">@HTML_PRE@</div> + </div> + <div class="sep"></div> + <div class="post"> + <h3>Vanilla Java</h3> + <div class="snippet">@HTML_POST@</div> + </div> + </div> + <div style="clear: left;"></div> + <div class="overview confKeys"> + <h3>Supported configuration keys:</h3> + <dl> + <dt><code>lombok.val.flagUsage</code> = [<code>allow</code>] (default: not set)</dt> + <dd><strong>Lombok will flag any usage of <code>var</code> as an error if not configured.</strong></dd> + </dl> + </div> + <div class="overview"> + <h3>Small print</h3><div class="smallprint"> + <p> + For compound types, the most common superclass is inferred, not any shared interfaces. For example, <code>bool ? new HashSet() : new ArrayList()</code> + is an expression with a compound type: The result is both <code>AbstractCollection</code> as well as <code>Serializable</code>. The type inferred will be + <code>AbstractCollection</code>, as that is a class, whereas <code>Serializable</code> is an interface. + </p><p> + In ambiguous cases, <code>java.lang.Object</code> is inferred. + </p> + </div> + </div> + <div class="footer"> + <a href="index.html">Back to experimental features</a> | <span class="disabled">Previous feature</span> | <a href="Accessors.html">Next feature (@Accessors)</a><br /> + <a href="../../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright © 2009-2016 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span> + </div> + <div style="clear: both;"></div> + </div> +</div> +<script type="text/javascript"> + var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); + document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); +</script> +<script type="text/javascript"> + try { + var pageTracker = _gat._getTracker("UA-9884254-1"); + pageTracker._trackPageview(); + } catch(err) {} +</script> +</body></html> |