[issue #1615] fixes a bug where equals and hashcode would mess up if both the outer and the inner class have generics, the inner is non-static, and you generate equals/hashcode on the inner.

Note that in general this is just broken; do not put non-static inner classes in generics-carrying classes in the first place!
This commit is contained in:
Reinier Zwitserloot committed 2018-03-20 01:17:35 +01:00
1 parent ae611e1687
commit c08559b016
6 files changed
+121 -31

No files matched your search

@@ -475,47 +475,62 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
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<Integer> genericsCount = addWildcards ? new ArrayList<Integer>() : null;
list.add(type.getName());
if (addWildcards) genericsCount.add(arraySizeOf(((TypeDeclaration) type.get()).typeParameters));
boolean staticContext = (((TypeDeclaration) type.get()).modifiers & Modifier.STATIC) != 0;
EclipseNode tNode = type.up();
while (tNode != null && tNode.getKind() == Kind.TYPE) {
list.add(tNode.getName());
if (addWildcards) genericsCount.add(staticContext ? 0 : arraySizeOf(((TypeDeclaration) tNode.get()).typeParameters));
if (!staticContext) staticContext = (((TypeDeclaration) tNode.get()).modifiers & Modifier.STATIC) != 0;
tNode = tNode.up();
}
Collections.reverse(list);
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 (addWildcards) Collections.reverse(genericsCount);
if (list.size() == 1) {
if (addWildcards) {
return new ParameterizedSingleTypeReference(list.get(0).toCharArray(), typeArgs, 0, p);
} else {
if (!addWildcards || genericsCount.get(0) == 0) {
return new SingleTypeReference(list.get(0).toCharArray(), p);
} else {
return new ParameterizedSingleTypeReference(list.get(0).toCharArray(), wildcardify(pS, pE, source, genericsCount.get(0)), 0, p);
}
}
if (addWildcards) {
addWildcards = false;
for (int i : genericsCount) if (i > 0) addWildcards = true;
}
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();
}
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);
if (!addWildcards) return new QualifiedTypeReference(tokens, ps);
TypeReference[][] typeArgs2 = new TypeReference[tokens.length][];
for (int i = 0; i < tokens.length; i++) typeArgs2[i] = wildcardify(pS, pE, source, genericsCount.get(i));
return new ParameterizedQualifiedTypeReference(tokens, typeArgs2, 0, ps);
}
private TypeReference[] wildcardify(int pS, int pE, ASTNode source, int count) {
if (count == 0) return null;
TypeReference[] typeArgs = new TypeReference[count];
for (int i = 0; i < count; i++) {
typeArgs[i] = new Wildcard(Wildcard.UNBOUND);
typeArgs[i].sourceStart = pS; typeArgs[i].sourceEnd = pE;
setGeneratedBy(typeArgs[i], source);
}
return typeArgs;
}
private int arraySizeOf(Object[] arr) {
return arr == null ? 0 : arr.length;
}
public MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess, boolean needsCanEqual, List<Annotation> onParam) {
@@ -683,7 +698,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
} else /* objects */ {
/* final java.lang.Object this$fieldName = this.fieldName; */
/* final java.lang.Object other$fieldName = other.fieldName; */
/* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false;; */
/* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false; */
char[] thisDollarFieldName = ("this$" + field.getName()).toCharArray();
char[] otherDollarFieldName = ("other$" + field.getName()).toCharArray();
@@ -371,31 +371,44 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
public JCExpression createTypeReference(JavacNode type, boolean addWildcards) {
java.util.List<String> list = new ArrayList<String>();
java.util.List<Integer> genericsCount = addWildcards ? new ArrayList<Integer>() : null;
list.add(type.getName());
if (addWildcards) genericsCount.add(((JCClassDecl) type.get()).typarams.size());
boolean staticContext = (((JCClassDecl) type.get()).getModifiers().flags & Flags.STATIC) != 0;
JavacNode tNode = type.up();
while (tNode != null && tNode.getKind() == Kind.TYPE) {
list.add(tNode.getName());
if (addWildcards) genericsCount.add(staticContext ? 0 : ((JCClassDecl) tNode.get()).typarams.size());
if (!staticContext) staticContext = (((JCClassDecl) tNode.get()).getModifiers().flags & Flags.STATIC) != 0;
tNode = tNode.up();
}
Collections.reverse(list);
JCClassDecl typeDecl = (JCClassDecl) type.get();
if (addWildcards) Collections.reverse(genericsCount);
JavacTreeMaker maker = type.getTreeMaker();
JCExpression chain = maker.Ident(type.toName(list.get(0)));
if (addWildcards) chain = wildcardify(maker, chain, genericsCount.get(0));
for (int i = 1; i < list.size(); i++) {
chain = maker.Select(chain, type.toName(list.get(i)));
if (addWildcards) chain = wildcardify(maker, chain, genericsCount.get(i));
}
if (!addWildcards || typeDecl.typarams.length() == 0) return chain;
return chain;
}
private JCExpression wildcardify(JavacTreeMaker maker, JCExpression expr, int count) {
if (count == 0) return expr;
ListBuffer<JCExpression> wildcards = new ListBuffer<JCExpression>();
for (int i = 0 ; i < typeDecl.typarams.length() ; i++) {
for (int i = 0 ; i < count ; i++) {
wildcards.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null));
}
return maker.TypeApply(chain, wildcards.toList());
return maker.TypeApply(expr, wildcards.toList());
}
public JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) {
@@ -0,0 +1,28 @@
public class EqualsAndHashCodeWithGenericsOnInners<A> {
class Inner<B> {
int x;
@java.lang.Override
@java.lang.SuppressWarnings("all")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof EqualsAndHashCodeWithGenericsOnInners.Inner)) return false;
final EqualsAndHashCodeWithGenericsOnInners<?>.Inner<?> other = (EqualsAndHashCodeWithGenericsOnInners<?>.Inner<?>) o;
if (!other.canEqual((java.lang.Object) this)) return false;
if (this.x != other.x) return false;
return true;
}
@java.lang.SuppressWarnings("all")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof EqualsAndHashCodeWithGenericsOnInners.Inner;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.x;
return result;
}
}
}
@@ -0,0 +1,32 @@
public class EqualsAndHashCodeWithGenericsOnInners<A> {
@lombok.EqualsAndHashCode class Inner<B> {
int x;
Inner() {
super();
}
public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
if ((o == this))
return true;
if ((! (o instanceof EqualsAndHashCodeWithGenericsOnInners.Inner)))
return false;
final EqualsAndHashCodeWithGenericsOnInners<?>.Inner<?> other = (EqualsAndHashCodeWithGenericsOnInners<?>.Inner<?>) o;
if ((! other.canEqual((java.lang.Object) this)))
return false;
if ((this.x != other.x))
return false;
return true;
}
protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) {
return (other instanceof EqualsAndHashCodeWithGenericsOnInners.Inner);
}
public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() {
final int PRIME = 59;
int result = 1;
result = ((result * PRIME) + this.x);
return result;
}
}
public EqualsAndHashCodeWithGenericsOnInners() {
super();
}
}
@@ -1,4 +0,0 @@
public class DataWithGenericsOnInners<A> {
@lombok.Data class Inner<B> {}
}
@@ -0,0 +1,6 @@
public class EqualsAndHashCodeWithGenericsOnInners<A> {
@lombok.EqualsAndHashCode class Inner<B> {
int x;
}
}