diff options
author | Roel Spilker <r.spilker@gmail.com> | 2020-06-18 22:08:25 +0200 |
---|---|---|
committer | Roel Spilker <r.spilker@gmail.com> | 2020-06-18 22:08:25 +0200 |
commit | 39d2c280fbaced63f5697481af6b37ab81891798 (patch) | |
tree | 148dd9e4b3798e78b59105b2a5535b396c723aec | |
parent | c4db4e124c5081602802f88b7ebe564c8af3aac8 (diff) | |
download | lombok-39d2c280fbaced63f5697481af6b37ab81891798.tar.gz lombok-39d2c280fbaced63f5697481af6b37ab81891798.tar.bz2 lombok-39d2c280fbaced63f5697481af6b37ab81891798.zip |
Fixes #1543: in equals, by default first compare the primitives
-rw-r--r-- | doc/changelog.markdown | 3 | ||||
-rw-r--r-- | src/core/lombok/EqualsAndHashCode.java | 4 | ||||
-rw-r--r-- | src/core/lombok/core/LombokNode.java | 1 | ||||
-rw-r--r-- | src/core/lombok/core/handlers/InclusionExclusionUtils.java | 18 | ||||
-rw-r--r-- | src/core/lombok/eclipse/EclipseNode.java | 19 | ||||
-rwxr-xr-x | src/core/lombok/eclipse/handlers/HandleBuilder.java | 2 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleSuperBuilder.java | 2 | ||||
-rw-r--r-- | src/core/lombok/javac/JavacNode.java | 20 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleBuilder.java | 2 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleSuperBuilder.java | 2 | ||||
-rw-r--r-- | test/transform/resource/after-delombok/BuilderDefaults.java | 8 | ||||
-rw-r--r-- | test/transform/resource/after-delombok/EqualsAndHashCodeRank.java | 6 | ||||
-rw-r--r-- | test/transform/resource/after-ecj/BuilderDefaults.java | 10 | ||||
-rw-r--r-- | test/transform/resource/after-ecj/EqualsAndHashCodeRank.java | 18 |
14 files changed, 74 insertions, 41 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 00545483..af77d480 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,6 +2,8 @@ Lombok Changelog ---------------- ### v1.18.13 "Edgy Guinea Pig" +* PERFORMANCE: The generated equals method will first compare primitives. Manual re-ordering is possible using `@Include(rank=n)`. [Pull Request #2485](https://github.com/rzwitserloot/lombok/pull/2485), [Issue #1543](https://github.com/rzwitserloot/lombok/issues/1543) +* IMPROBABLE BREAKING CHANGE: The generated hashcode has changed for classes that include both primitive fields and reference fields. * PLATFORM: Added support for compiling projects with OpenJ9 [Pull Request #2437](https://github.com/rzwitserloot/lombok/pull/2437) * BREAKING CHANGE: mapstruct users should now add a dependency to lombok-mapstruct-binding. This solves compiling modules with lombok (and mapstruct). * FEATURE: Similar to `@Builder`, you can now configure a `@SuperBuilder`'s 'setter' prefixes via `@SuperBuilder(setterPrefix = "set")` for example. We still discourage doing this. [Pull Request #2357](https://github.com/rzwitserloot/lombok/pull/2357). @@ -14,6 +16,7 @@ Lombok Changelog * BUGFIX: Javac sets incorrect annotated type on with methods. [Issue #2463](https://github.com/rzwitserloot/lombok/issues/2463) * FEATURE: `@Jacksonized` on a `@Builder` or `@SuperBuilder` will configure [Jackson](https://github.com/FasterXML/jackson) to use this builder when deserializing. [Pull Request #2387](https://github.com/rzwitserloot/lombok/pull/2387) thanks to __@JanRieke__. [@Jacksonized documentation](https://projectlombok.org/features/experimental/Jacksonized). + ### v1.18.12 (February 1st, 2020) * PLATFORM: Support for JDK13 (including `yield` in switch expressions, as well as delombok having a nicer style for arrow-style switch blocks, and text blocks). * PLATFORM: Support for JDK14 (including `pattern match` instanceof expressions). diff --git a/src/core/lombok/EqualsAndHashCode.java b/src/core/lombok/EqualsAndHashCode.java index 02596f24..2f53bdec 100644 --- a/src/core/lombok/EqualsAndHashCode.java +++ b/src/core/lombok/EqualsAndHashCode.java @@ -125,7 +125,9 @@ public @interface EqualsAndHashCode { /** * Higher ranks are considered first. Members of the same rank are considered in the order they appear in the source file. - * + * + * If not explicitly set, the {@code default} rank for primitives is 1000. + * * @return ordering within the generating {@code equals} and {@code hashCode} methods; higher numbers are considered first. */ int rank() default 0; diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java index e52cd5b3..46054077 100644 --- a/src/core/lombok/core/LombokNode.java +++ b/src/core/lombok/core/LombokNode.java @@ -288,6 +288,7 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A, public abstract boolean isStatic(); public abstract boolean isFinal(); public abstract boolean isTransient(); + public abstract boolean isPrimitive(); public abstract boolean isEnumMember(); public abstract boolean isEnumType(); diff --git a/src/core/lombok/core/handlers/InclusionExclusionUtils.java b/src/core/lombok/core/handlers/InclusionExclusionUtils.java index c50da1cc..609a5e36 100644 --- a/src/core/lombok/core/handlers/InclusionExclusionUtils.java +++ b/src/core/lombok/core/handlers/InclusionExclusionUtils.java @@ -76,11 +76,13 @@ public class InclusionExclusionUtils { private final L node; private final I inc; private final boolean defaultInclude; + private final boolean explicitRank; - public Included(L node, I inc, boolean defaultInclude) { + public Included(L node, I inc, boolean defaultInclude, boolean explicitRank) { this.node = node; this.inc = inc; this.defaultInclude = defaultInclude; + this.explicitRank = explicitRank; } public L getNode() { @@ -94,6 +96,10 @@ public class InclusionExclusionUtils { public boolean isDefaultInclude() { return defaultInclude; } + + public boolean hasExplicitRank() { + return explicitRank; + } } private static String innerAnnName(Class<? extends Annotation> type) { @@ -164,13 +170,13 @@ public class InclusionExclusionUtils { if (n.isEmpty()) n = name; namesToAutoExclude.add(n); } - members.add(new Included<L, I>(child, inc, false)); + members.add(new Included<L, I>(child, inc, false, markInclude.isExplicit("rank"))); continue; } if (onlyExplicitlyIncluded) continue; if (oldIncludes != null) { - if (child.getKind() == Kind.FIELD && oldIncludes.contains(name)) members.add(new Included<L, I>(child, null, false)); + if (child.getKind() == Kind.FIELD && oldIncludes.contains(name)) members.add(new Included<L, I>(child, null, false, false)); continue; } if (child.getKind() != Kind.FIELD) continue; @@ -178,7 +184,7 @@ public class InclusionExclusionUtils { if (child.isTransient() && !includeTransient) continue; if (name.startsWith("$")) continue; if (child.isEnumMember()) continue; - members.add(new Included<L, I>(child, null, true)); + members.add(new Included<L, I>(child, null, true, false)); } /* delete default-included fields with the same name as an explicit inclusion */ { @@ -219,8 +225,8 @@ public class InclusionExclusionUtils { Collections.sort(members, new Comparator<Included<L, EqualsAndHashCode.Include>>() { @Override public int compare(Included<L, EqualsAndHashCode.Include> a, Included<L, EqualsAndHashCode.Include> b) { - int ra = a.getInc() == null ? 0 : a.getInc().rank(); - int rb = b.getInc() == null ? 0 : b.getInc().rank(); + int ra = a.hasExplicitRank() ? a.getInc().rank() : a.node.isPrimitive() ? 1000 : 0; + int rb = b.hasExplicitRank() ? b.getInc().rank() : b.node.isPrimitive() ? 1000 : 0; return compareRankOrPosition(ra, rb, a.getNode(), b.getNode()); } diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java index 9db491f5..5aa29466 100644 --- a/src/core/lombok/eclipse/EclipseNode.java +++ b/src/core/lombok/eclipse/EclipseNode.java @@ -23,10 +23,6 @@ package lombok.eclipse; import java.util.List; -import lombok.core.AnnotationValues; -import lombok.core.AST.Kind; -import lombok.eclipse.handlers.EclipseHandlerUtil; - import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -36,11 +32,16 @@ import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.Initializer; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.eclipse.handlers.EclipseHandlerUtil; + /** * Eclipse specific version of the LombokNode class. */ @@ -264,6 +265,16 @@ public class EclipseNode extends lombok.core.LombokNode<EclipseAST, EclipseNode, return (ClassFileConstants.AccFinal & f) != 0; } + @Override public boolean isPrimitive() { + if (node instanceof FieldDeclaration && !isEnumMember()) { + return Eclipse.isPrimitive(((FieldDeclaration) node).type); + } + if (node instanceof MethodDeclaration) { + return Eclipse.isPrimitive(((MethodDeclaration) node).returnType); + } + return false; + } + @Override public boolean isTransient() { if (getKind() != Kind.FIELD) return false; Integer i = getModifiers(); diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index b8e88522..f848469f 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -485,7 +485,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>(); for (BuilderFieldData bfd : builderFields) { for (EclipseNode f : bfd.createdFields) { - fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true)); + fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true, false)); } } MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, false, ast, FieldAccess.ALWAYS_FIELD); diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 7c8e4ea3..cc4d55be 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -354,7 +354,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>(); for (BuilderFieldData bfd : builderFields) { for (EclipseNode f : bfd.createdFields) { - fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true)); + fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true, false)); } } // Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder. diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java index 19bbeae3..08d22d98 100644 --- a/src/core/lombok/javac/JavacNode.java +++ b/src/core/lombok/javac/JavacNode.java @@ -27,10 +27,6 @@ import java.util.List; import javax.lang.model.element.Element; import javax.tools.Diagnostic; -import lombok.core.AnnotationValues; -import lombok.core.AST.Kind; -import lombok.javac.handlers.JavacHandlerUtil; - import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.model.JavacTypes; @@ -43,8 +39,12 @@ import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCModifiers; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.Name; + +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.javac.handlers.JavacHandlerUtil; /** * Javac specific version of the LombokNode class. @@ -345,6 +345,16 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre return mods != null && (Flags.ENUM & mods.flags) != 0; } + @Override public boolean isPrimitive() { + if (node instanceof JCVariableDecl && !isEnumMember()) { + return Javac.isPrimitive(((JCVariableDecl) node).vartype); + } + if (node instanceof JCMethodDecl) { + return Javac.isPrimitive(((JCMethodDecl) node).restype); + } + return false; + } + @Override public boolean isTransient() { if (getKind() != Kind.FIELD) return false; JCModifiers mods = getModifiers(); diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 95be28f3..7e87ce11 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -435,7 +435,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { java.util.List<Included<JavacNode, ToString.Include>> fieldNodes = new ArrayList<Included<JavacNode, ToString.Include>>(); for (BuilderFieldData bfd : builderFields) { for (JavacNode f : bfd.createdFields) { - fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true)); + fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true, false)); } } diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 4cd64b77..f6bf9e1f 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -304,7 +304,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { java.util.List<Included<JavacNode, ToString.Include>> fieldNodes = new ArrayList<Included<JavacNode, ToString.Include>>(); for (BuilderFieldData bfd : builderFields) { for (JavacNode f : bfd.createdFields) { - fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true)); + fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true, false)); } } diff --git a/test/transform/resource/after-delombok/BuilderDefaults.java b/test/transform/resource/after-delombok/BuilderDefaults.java index 5a563024..42b751ce 100644 --- a/test/transform/resource/after-delombok/BuilderDefaults.java +++ b/test/transform/resource/after-delombok/BuilderDefaults.java @@ -85,10 +85,10 @@ public final class BuilderDefaults { if (!(o instanceof BuilderDefaults)) return false; final BuilderDefaults other = (BuilderDefaults) o; if (this.getX() != other.getX()) return false; + if (this.getZ() != other.getZ()) return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; - if (this.getZ() != other.getZ()) return false; return true; } @java.lang.Override @@ -97,10 +97,10 @@ public final class BuilderDefaults { final int PRIME = 59; int result = 1; result = result * PRIME + this.getX(); - final java.lang.Object $name = this.getName(); - result = result * PRIME + ($name == null ? 43 : $name.hashCode()); final long $z = this.getZ(); result = result * PRIME + (int) ($z >>> 32 ^ $z); + final java.lang.Object $name = this.getName(); + result = result * PRIME + ($name == null ? 43 : $name.hashCode()); return result; } @java.lang.Override @@ -108,4 +108,4 @@ public final class BuilderDefaults { public java.lang.String toString() { return "BuilderDefaults(x=" + this.getX() + ", name=" + this.getName() + ", z=" + this.getZ() + ")"; } -} +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeRank.java b/test/transform/resource/after-delombok/EqualsAndHashCodeRank.java index ad2ddbb1..fcf371b6 100644 --- a/test/transform/resource/after-delombok/EqualsAndHashCodeRank.java +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeRank.java @@ -9,9 +9,9 @@ public class EqualsAndHashCodeRank { if (!(o instanceof EqualsAndHashCodeRank)) return false; final EqualsAndHashCodeRank other = (EqualsAndHashCodeRank) o; if (!other.canEqual((java.lang.Object) this)) return false; - if (this.b != other.b) return false; if (this.a != other.a) return false; if (this.c != other.c) return false; + if (this.b != other.b) return false; return true; } @java.lang.SuppressWarnings("all") @@ -23,9 +23,9 @@ public class EqualsAndHashCodeRank { public int hashCode() { final int PRIME = 59; int result = 1; - result = result * PRIME + this.b; result = result * PRIME + this.a; result = result * PRIME + this.c; + result = result * PRIME + this.b; return result; } -} +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/BuilderDefaults.java b/test/transform/resource/after-ecj/BuilderDefaults.java index 46f55bef..c9be219d 100644 --- a/test/transform/resource/after-ecj/BuilderDefaults.java +++ b/test/transform/resource/after-ecj/BuilderDefaults.java @@ -72,25 +72,25 @@ public final @Value @Builder class BuilderDefaults { final BuilderDefaults other = (BuilderDefaults) o; if ((this.getX() != other.getX())) return false; + if ((this.getZ() != other.getZ())) + return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); if (((this$name == null) ? (other$name != null) : (! this$name.equals(other$name)))) return false; - if ((this.getZ() != other.getZ())) - return false; return true; } public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 59; int result = 1; result = ((result * PRIME) + this.getX()); - final java.lang.Object $name = this.getName(); - result = ((result * PRIME) + (($name == null) ? 43 : $name.hashCode())); final long $z = this.getZ(); result = ((result * PRIME) + (int) ($z ^ ($z >>> 32))); + final java.lang.Object $name = this.getName(); + result = ((result * PRIME) + (($name == null) ? 43 : $name.hashCode())); return result; } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { return (((((("BuilderDefaults(x=" + this.getX()) + ", name=") + this.getName()) + ", z=") + this.getZ()) + ")"); } -} +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/EqualsAndHashCodeRank.java b/test/transform/resource/after-ecj/EqualsAndHashCodeRank.java index 1ea899a8..ef221261 100644 --- a/test/transform/resource/after-ecj/EqualsAndHashCodeRank.java +++ b/test/transform/resource/after-ecj/EqualsAndHashCodeRank.java @@ -7,18 +7,18 @@ public @EqualsAndHashCode class EqualsAndHashCodeRank { super(); } public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { - if (o == this) + if ((o == this)) return true; - if (!(o instanceof EqualsAndHashCodeRank)) + if ((! (o instanceof EqualsAndHashCodeRank))) return false; final EqualsAndHashCodeRank other = (EqualsAndHashCodeRank) o; - if (!other.canEqual((java.lang.Object) this)) + if ((! other.canEqual((java.lang.Object) this))) return false; - if (this.b != other.b) + if ((this.a != other.a)) return false; - if (this.a != other.a) + if ((this.c != other.c)) return false; - if (this.c != other.c) + if ((this.b != other.b)) return false; return true; } @@ -28,9 +28,9 @@ public @EqualsAndHashCode class EqualsAndHashCodeRank { public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { final int PRIME = 59; int result = 1; - result = result * PRIME + this.b; - result = result * PRIME + this.a; - result = result * PRIME + this.c; + result = ((result * PRIME) + this.a); + result = ((result * PRIME) + this.c); + result = ((result * PRIME) + this.b); return result; } } |