aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/changelog.markdown1
-rw-r--r--src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java70
-rw-r--r--src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java36
-rw-r--r--test/transform/resource/after-delombok/DataOnLocalClass.java2
-rw-r--r--test/transform/resource/after-delombok/EqualsAndHashCodeNestedShadow.java56
-rw-r--r--test/transform/resource/after-ecj/DataOnLocalClass.java2
-rw-r--r--test/transform/resource/after-ecj/EqualsAndHashCodeNestedShadow.java58
-rw-r--r--test/transform/resource/before/EqualsAndHashCodeNestedShadow.java15
8 files changed, 190 insertions, 50 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown
index bad185fa..1f5218d9 100644
--- a/doc/changelog.markdown
+++ b/doc/changelog.markdown
@@ -6,6 +6,7 @@ Lombok Changelog
* FEATURE: Generated classes, methods and fields can now also annotated with `@lombok.Generated` [Issue #1014](https://github.com/rzwitserloot/lombok/issues/1014)<br>
* PLATFORM: Lombok can now be used together with other annotation processors that are looking for lombok-generated methods, but only if lombok is the first annotation processor executed. The most commonly used annotation processor affected by this change is [MapStruct](http://mapstruct.org/); we've worked with the mapstruct team specifically to allow any order. Other annotation processors might follow the framework we've built to make this possible; point the authors of any such processor to us and we'll get it sorted [MapStruct issue #510](https://github.com/mapstruct/mapstruct/issues/510) [Lombok issue #973](https://github.com/rzwitserloot/lombok/issues/973)
* PLATFORM: Eclipse: Refactor script 'rename field' when lombok has also generated getters and/or setters for this field is nicer now [Issue #210](https://github.com/rzwitserloot/lombok/issues/210)
+* BUGFIX: Something you never encountered. [Issue #1274](https://github.com/rzwitserloot/lombok/issues/1274)
### 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.
diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
index a56eee89..bc25ae2a 100644
--- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
@@ -67,6 +67,7 @@ import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NameReference;
import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
@@ -458,7 +459,14 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
return assignment;
}
- public TypeReference createTypeReference(EclipseNode type, long p) {
+ /**
+ * @param type Type to 'copy' into a typeref
+ * @param p position
+ * @param addWildcards If false, all generics are cut off. If true, replaces all genericparams with a ?.
+ * @return
+ */
+ public TypeReference createTypeReference(EclipseNode type, long p, ASTNode source, boolean addWildcards) {
+ int pS = source.sourceStart; int pE = source.sourceEnd;
List<String> list = new ArrayList<String>();
list.add(type.getName());
EclipseNode tNode = type.up();
@@ -468,21 +476,44 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
}
Collections.reverse(list);
- if (list.size() == 1) return new SingleTypeReference(list.get(0).toCharArray(), p);
+ TypeDeclaration typeDecl = (TypeDeclaration) type.get();
+ int typeParamCount = typeDecl.typeParameters == null ? 0 : typeDecl.typeParameters.length;
+ if (typeParamCount == 0) addWildcards = false;
+ TypeReference[] typeArgs = null;
+ if (addWildcards) {
+ typeArgs = new TypeReference[typeParamCount];
+ for (int i = 0; i < typeParamCount; i++) {
+ typeArgs[i] = new Wildcard(Wildcard.UNBOUND);
+ typeArgs[i].sourceStart = pS; typeArgs[i].sourceEnd = pE;
+ setGeneratedBy(typeArgs[i], source);
+ }
+ }
+
+ if (list.size() == 1) {
+ if (addWildcards) {
+ return new ParameterizedSingleTypeReference(list.get(0).toCharArray(), typeArgs, 0, p);
+ } else {
+ return new SingleTypeReference(list.get(0).toCharArray(), p);
+ }
+ }
long[] ps = new long[list.size()];
char[][] tokens = new char[list.size()][];
for (int i = 0; i < list.size(); i++) {
ps[i] = p;
tokens[i] = list.get(i).toCharArray();
}
-
- return new QualifiedTypeReference(tokens, ps);
+ if (addWildcards) {
+ TypeReference[][] typeArgs2 = new TypeReference[tokens.length][];
+ typeArgs2[typeArgs2.length - 1] = typeArgs;
+ return new ParameterizedQualifiedTypeReference(tokens, typeArgs2, 0, ps);
+ } else {
+ return new QualifiedTypeReference(tokens, ps);
+ }
}
public MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess, boolean needsCanEqual, List<Annotation> onParam) {
int pS = source.sourceStart; int pE = source.sourceEnd;
long p = (long)pS << 32 | pE;
- TypeDeclaration typeDecl = (TypeDeclaration)type.get();
MethodDeclaration method = new MethodDeclaration(
((CompilationUnitDeclaration) type.top().get()).compilationResult);
@@ -528,7 +559,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p);
setGeneratedBy(oRef, source);
- TypeReference typeReference = createTypeReference(type, p);
+ TypeReference typeReference = createTypeReference(type, p, source, false);
setGeneratedBy(typeReference, source);
InstanceOfExpression instanceOf = new InstanceOfExpression(oRef, typeReference);
@@ -551,30 +582,15 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
char[] otherName = "other".toCharArray();
- /* MyType<?> other = (MyType<?>) o; */ {
+ /* Outer.Inner.MyType<?> other = (Outer.Inner.MyType<?>) o; */ {
if (!fields.isEmpty() || needsCanEqual) {
LocalDeclaration other = new LocalDeclaration(otherName, pS, pE);
other.modifiers |= ClassFileConstants.AccFinal;
setGeneratedBy(other, source);
- char[] typeName = typeDecl.name;
- TypeReference targetType;
- if (typeDecl.typeParameters == null || typeDecl.typeParameters.length == 0) {
- targetType = new SingleTypeReference(typeName, p);
- setGeneratedBy(targetType, source);
- other.type = new SingleTypeReference(typeName, p);
- setGeneratedBy(other.type, source);
- } else {
- TypeReference[] typeArgs = new TypeReference[typeDecl.typeParameters.length];
- for (int i = 0; i < typeArgs.length; i++) {
- typeArgs[i] = new Wildcard(Wildcard.UNBOUND);
- typeArgs[i].sourceStart = pS; typeArgs[i].sourceEnd = pE;
- setGeneratedBy(typeArgs[i], source);
- }
- targetType = new ParameterizedSingleTypeReference(typeName, typeArgs, 0, p);
- setGeneratedBy(targetType, source);
- other.type = new ParameterizedSingleTypeReference(typeName, copyTypes(typeArgs, source), 0, p);
- setGeneratedBy(other.type, source);
- }
+ TypeReference targetType = createTypeReference(type, p, source, true);
+ setGeneratedBy(targetType, source);
+ other.type = createTypeReference(type, p, source, true);
+ setGeneratedBy(other.type, source);
NameReference oRef = new SingleNameReference(new char[] { 'o' }, p);
setGeneratedBy(oRef, source);
other.initialization = makeCastExpression(oRef, targetType, source);
@@ -772,7 +788,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
SingleNameReference otherRef = new SingleNameReference(otherName, p);
setGeneratedBy(otherRef, source);
- TypeReference typeReference = createTypeReference(type, p);
+ TypeReference typeReference = createTypeReference(type, p, source, false);
setGeneratedBy(typeReference, source);
InstanceOfExpression instanceOf = new InstanceOfExpression(otherRef, typeReference);
diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
index f34b4f6b..8e868bca 100644
--- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
@@ -363,7 +363,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
return maker.TypeCast(maker.TypeIdent(CTC_INT), maker.Parens(xorBits));
}
- public JCExpression createTypeReference(JavacNode type) {
+ public JCExpression createTypeReference(JavacNode type, boolean addWildcards) {
java.util.List<String> list = new ArrayList<String>();
list.add(type.getName());
JavacNode tNode = type.up();
@@ -372,20 +372,28 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
tNode = tNode.up();
}
Collections.reverse(list);
+ JCClassDecl typeDecl = (JCClassDecl) type.get();
JavacTreeMaker maker = type.getTreeMaker();
+
JCExpression chain = maker.Ident(type.toName(list.get(0)));
for (int i = 1; i < list.size(); i++) {
chain = maker.Select(chain, type.toName(list.get(i)));
}
- return chain;
+ if (!addWildcards || typeDecl.typarams.length() == 0) return chain;
+
+ ListBuffer<JCExpression> wildcards = new ListBuffer<JCExpression>();
+ for (int i = 0 ; i < typeDecl.typarams.length() ; i++) {
+ wildcards.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null));
+ }
+
+ return maker.TypeApply(chain, wildcards.toList());
}
public JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) {
JavacTreeMaker maker = typeNode.getTreeMaker();
- JCClassDecl type = (JCClassDecl) typeNode.get();
Name oName = typeNode.toName("o");
Name otherName = typeNode.toName("other");
@@ -408,27 +416,13 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
/* if (!(o instanceof Outer.Inner.MyType)) return false; */ {
- JCUnary notInstanceOf = maker.Unary(CTC_NOT, maker.Parens(maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode))));
+ JCUnary notInstanceOf = maker.Unary(CTC_NOT, maker.Parens(maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode, false))));
statements.append(maker.If(notInstanceOf, returnBool(maker, false), null));
}
- /* MyType<?> other = (MyType<?>) o; */ {
+ /* Outer.Inner.MyType<?> other = (Outer.Inner.MyType<?>) o; */ {
if (!fields.isEmpty() || needsCanEqual) {
- final JCExpression selfType1, selfType2;
- ListBuffer<JCExpression> wildcards1 = new ListBuffer<JCExpression>();
- ListBuffer<JCExpression> wildcards2 = new ListBuffer<JCExpression>();
- for (int i = 0 ; i < type.typarams.length() ; i++) {
- wildcards1.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null));
- wildcards2.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null));
- }
-
- if (type.typarams.isEmpty()) {
- selfType1 = maker.Ident(type.name);
- selfType2 = maker.Ident(type.name);
- } else {
- selfType1 = maker.TypeApply(maker.Ident(type.name), wildcards1.toList());
- selfType2 = maker.TypeApply(maker.Ident(type.name), wildcards2.toList());
- }
+ final JCExpression selfType1 = createTypeReference(typeNode, true), selfType2 = createTypeReference(typeNode, true);
statements.append(
maker.VarDef(maker.Modifiers(finalFlag), otherName, selfType1, maker.TypeCast(selfType2, maker.Ident(oName))));
@@ -533,7 +527,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(flags, onParam), otherName, objectType, null));
JCBlock body = maker.Block(0, List.<JCStatement>of(
- maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode)))));
+ maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode, false)))));
return recursiveSetGeneratedBy(maker.MethodDef(mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext());
}
diff --git a/test/transform/resource/after-delombok/DataOnLocalClass.java b/test/transform/resource/after-delombok/DataOnLocalClass.java
index 90ae7649..9fe16070 100644
--- a/test/transform/resource/after-delombok/DataOnLocalClass.java
+++ b/test/transform/resource/after-delombok/DataOnLocalClass.java
@@ -97,7 +97,7 @@ class DataOnLocalClass2 {
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof Local.InnerLocal)) return false;
- final InnerLocal other = (InnerLocal) o;
+ final Local.InnerLocal other = (Local.InnerLocal) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$name = this.getName();
final java.lang.Object other$name = other.getName();
diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeNestedShadow.java b/test/transform/resource/after-delombok/EqualsAndHashCodeNestedShadow.java
new file mode 100644
index 00000000..ac687d84
--- /dev/null
+++ b/test/transform/resource/after-delombok/EqualsAndHashCodeNestedShadow.java
@@ -0,0 +1,56 @@
+interface EqualsAndHashCodeNestedShadow {
+ interface Foo {
+ }
+ class Bar {
+ public static class Foo extends Bar implements EqualsAndHashCodeNestedShadow.Foo {
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ @javax.annotation.Generated("lombok")
+ public boolean equals(final java.lang.Object o) {
+ if (o == this) return true;
+ if (!(o instanceof EqualsAndHashCodeNestedShadow.Bar.Foo)) return false;
+ final EqualsAndHashCodeNestedShadow.Bar.Foo other = (EqualsAndHashCodeNestedShadow.Bar.Foo) o;
+ if (!other.canEqual((java.lang.Object) this)) return false;
+ return true;
+ }
+ @java.lang.SuppressWarnings("all")
+ @javax.annotation.Generated("lombok")
+ protected boolean canEqual(final java.lang.Object other) {
+ return other instanceof EqualsAndHashCodeNestedShadow.Bar.Foo;
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ @javax.annotation.Generated("lombok")
+ public int hashCode() {
+ int result = 1;
+ return result;
+ }
+ }
+ }
+ class Baz {
+ public static class Foo<T> extends Bar implements EqualsAndHashCodeNestedShadow.Foo {
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ @javax.annotation.Generated("lombok")
+ public boolean equals(final java.lang.Object o) {
+ if (o == this) return true;
+ if (!(o instanceof EqualsAndHashCodeNestedShadow.Baz.Foo)) return false;
+ final EqualsAndHashCodeNestedShadow.Baz.Foo<?> other = (EqualsAndHashCodeNestedShadow.Baz.Foo<?>) o;
+ if (!other.canEqual((java.lang.Object) this)) return false;
+ return true;
+ }
+ @java.lang.SuppressWarnings("all")
+ @javax.annotation.Generated("lombok")
+ protected boolean canEqual(final java.lang.Object other) {
+ return other instanceof EqualsAndHashCodeNestedShadow.Baz.Foo;
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ @javax.annotation.Generated("lombok")
+ public int hashCode() {
+ int result = 1;
+ return result;
+ }
+ }
+ }
+}
diff --git a/test/transform/resource/after-ecj/DataOnLocalClass.java b/test/transform/resource/after-ecj/DataOnLocalClass.java
index 9d6bced1..a86837e3 100644
--- a/test/transform/resource/after-ecj/DataOnLocalClass.java
+++ b/test/transform/resource/after-ecj/DataOnLocalClass.java
@@ -73,7 +73,7 @@ class DataOnLocalClass2 {
return true;
if ((! (o instanceof Local.InnerLocal)))
return false;
- final InnerLocal other = (InnerLocal) o;
+ final Local.InnerLocal other = (Local.InnerLocal) o;
if ((! other.canEqual((java.lang.Object) this)))
return false;
final java.lang.Object this$name = this.getName();
diff --git a/test/transform/resource/after-ecj/EqualsAndHashCodeNestedShadow.java b/test/transform/resource/after-ecj/EqualsAndHashCodeNestedShadow.java
new file mode 100644
index 00000000..5af6e9d8
--- /dev/null
+++ b/test/transform/resource/after-ecj/EqualsAndHashCodeNestedShadow.java
@@ -0,0 +1,58 @@
+interface EqualsAndHashCodeNestedShadow {
+ interface Foo {
+ }
+ class Bar {
+ public static @lombok.EqualsAndHashCode(callSuper = false) class Foo extends Bar implements EqualsAndHashCodeNestedShadow.Foo {
+ public Foo() {
+ super();
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") boolean equals(final java.lang.Object o) {
+ if ((o == this))
+ return true;
+ if ((! (o instanceof EqualsAndHashCodeNestedShadow.Bar.Foo)))
+ return false;
+ final EqualsAndHashCodeNestedShadow.Bar.Foo other = (EqualsAndHashCodeNestedShadow.Bar.Foo) o;
+ if ((! other.canEqual((java.lang.Object) this)))
+ return false;
+ return true;
+ }
+ protected @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") boolean canEqual(final java.lang.Object other) {
+ return (other instanceof EqualsAndHashCodeNestedShadow.Bar.Foo);
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") int hashCode() {
+ int result = 1;
+ return result;
+ }
+ }
+ Bar() {
+ super();
+ }
+ }
+ class Baz {
+ public static @lombok.EqualsAndHashCode(callSuper = false) class Foo<T> extends Bar implements EqualsAndHashCodeNestedShadow.Foo {
+ public Foo() {
+ super();
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") boolean equals(final java.lang.Object o) {
+ if ((o == this))
+ return true;
+ if ((! (o instanceof EqualsAndHashCodeNestedShadow.Baz.Foo)))
+ return false;
+ final EqualsAndHashCodeNestedShadow.Baz.Foo<?> other = (EqualsAndHashCodeNestedShadow.Baz.Foo<?>) o;
+ if ((! other.canEqual((java.lang.Object) this)))
+ return false;
+ return true;
+ }
+ protected @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") boolean canEqual(final java.lang.Object other) {
+ return (other instanceof EqualsAndHashCodeNestedShadow.Baz.Foo);
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") int hashCode() {
+ int result = 1;
+ return result;
+ }
+ }
+ Baz() {
+ super();
+ }
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/before/EqualsAndHashCodeNestedShadow.java b/test/transform/resource/before/EqualsAndHashCodeNestedShadow.java
new file mode 100644
index 00000000..2b0c4fa3
--- /dev/null
+++ b/test/transform/resource/before/EqualsAndHashCodeNestedShadow.java
@@ -0,0 +1,15 @@
+interface EqualsAndHashCodeNestedShadow {
+ interface Foo {
+ }
+ class Bar {
+ @lombok.EqualsAndHashCode(callSuper=false)
+ public static class Foo extends Bar implements EqualsAndHashCodeNestedShadow.Foo {
+ }
+ }
+
+ class Baz {
+ @lombok.EqualsAndHashCode(callSuper=false)
+ public static class Foo<T> extends Bar implements EqualsAndHashCodeNestedShadow.Foo {
+ }
+ }
+} \ No newline at end of file