mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 00:14:50 +00:00
[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:
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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user