Skip to content

Commit

Permalink
ArC: fix hash code of TypeAndQualifiers
Browse files Browse the repository at this point in the history
The `TypeAndQualifiers` compound is used as a key in hash maps, which
means its equality and hash code must be consistent. Unfortunately,
the implementation of `equals()` is completely custom, because it
needs to ignore `AnnotationInstance.target`, yet the `hashCode()`
implementation blindly delegates to `AnnotationInstance`. That used
to work, because `AnnotationInstance.hashCode()` ignored the `target`
before, but that has never been a stated contract. A completely custom
implementation of equality should always be accompanied by a custom
implementation of hash code. That's what this commit does.
  • Loading branch information
Ladicek committed Oct 3, 2023
1 parent 9d27563 commit fcbd46d
Showing 1 changed file with 25 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,8 @@ public TypeAndQualifiers(Type type, Set<AnnotationInstance> qualifiers) {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((qualifiers == null) ? 0 : qualifiers.hashCode());
// We cannot use AnnotationInstance#hashCode() as it includes the AnnotationTarget
result = prime * result + annotationSetHashCode(qualifiers);
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
Expand All @@ -409,8 +410,8 @@ public boolean equals(Object obj) {
if (other.qualifiers != null) {
return false;
}
} else if (!qualifiersAreEqual(qualifiers, other.qualifiers)) {
// We cannot use AnnotationInstance#equals() as it requires the exact same annotationTarget instance
} else if (!annotationSetEquals(qualifiers, other.qualifiers)) {
// We cannot use AnnotationInstance#equals() as it requires the exact same AnnotationTarget instance
return false;
}
if (type == null) {
Expand All @@ -423,30 +424,44 @@ public boolean equals(Object obj) {
return true;
}

private boolean qualifiersAreEqual(Set<AnnotationInstance> q1, Set<AnnotationInstance> q2) {
if (q1 == q2) {
private static boolean annotationSetEquals(Set<AnnotationInstance> s1, Set<AnnotationInstance> s2) {
if (s1 == s2) {
return true;
}
if (q1.size() != q2.size()) {
if (s1.size() != s2.size()) {
return false;
}
for (AnnotationInstance a1 : q1) {
for (AnnotationInstance a2 : q2) {
if (!annotationsAreEqual(a1, a2)) {
for (AnnotationInstance a1 : s1) {
for (AnnotationInstance a2 : s2) {
if (!annotationEquals(a1, a2)) {
return false;
}
}
}
return true;
}

private boolean annotationsAreEqual(AnnotationInstance a1, AnnotationInstance a2) {
private static boolean annotationEquals(AnnotationInstance a1, AnnotationInstance a2) {
if (a1 == a2) {
return true;
}
return a1.name().equals(a2.name()) && a1.values().equals(a2.values());
}

private static int annotationSetHashCode(Set<AnnotationInstance> s) {
int result = 1;
for (AnnotationInstance a : s) {
result = 31 * result + annotationHashCode(a);
}
return result;
}

private static int annotationHashCode(AnnotationInstance a) {
int result = a.name().hashCode();
result = 31 * result + a.values().hashCode();
return result;
}

}

}

0 comments on commit fcbd46d

Please sign in to comment.