@Override public Boolean visitDeclared(DeclaredType a, EqualVisitorParam p) { if (p.type.getKind().equals(DECLARED)) { DeclaredType b = (DeclaredType) p.type; Element aElement = a.asElement(); Element bElement = b.asElement(); Set<ComparedElements> newVisiting = visitingSetPlus( p.visiting, aElement, a.getTypeArguments(), bElement, b.getTypeArguments()); if (newVisiting.equals(p.visiting)) { // We're already visiting this pair of elements. // This can happen for example with Enum in Enum<E extends Enum<E>>. Return a // provisional true value since if the Elements are not in fact equal the original // visitor of Enum will discover that. We have to check both Elements being compared // though to avoid missing the fact that one of the types being compared // differs at exactly this point. return true; } return aElement.equals(bElement) && equal(enclosingType(a), enclosingType(b), newVisiting) && equalLists(a.getTypeArguments(), b.getTypeArguments(), newVisiting); } return false; }
@Override public Boolean visitTypeVariable(TypeVariable a, EqualVisitorParam p) { if (p.type.getKind().equals(TYPEVAR)) { TypeVariable b = (TypeVariable) p.type; TypeParameterElement aElement = (TypeParameterElement) a.asElement(); TypeParameterElement bElement = (TypeParameterElement) b.asElement(); Set<ComparedElements> newVisiting = visitingSetPlus(p.visiting, aElement, bElement); if (newVisiting.equals(p.visiting)) { // We're already visiting this pair of elements. // This can happen with our friend Eclipse when looking at <T extends Comparable<T>>. // It incorrectly reports the upper bound of T as T itself. return true; } // We use aElement.getBounds() instead of a.getUpperBound() to avoid having to deal with // the different way intersection types (like <T extends Number & Comparable<T>>) are // represented before and after Java 8. We do have an issue that this code may consider // that <T extends Foo & Bar> is different from <T extends Bar & Foo>, but it's very // hard to avoid that, and not likely to be much of a problem in practice. return equalLists(aElement.getBounds(), bElement.getBounds(), newVisiting) && equal(a.getLowerBound(), b.getLowerBound(), newVisiting) && a.asElement().getSimpleName().equals(b.asElement().getSimpleName()); } return false; }
private Set<ComparedElements> visitingSetPlus( Set<ComparedElements> visiting, Element a, List<? extends TypeMirror> aArguments, Element b, List<? extends TypeMirror> bArguments) { ComparedElements comparedElements = new ComparedElements( a, ImmutableList.<TypeMirror>copyOf(aArguments), b, ImmutableList.<TypeMirror>copyOf(bArguments)); Set<ComparedElements> newVisiting = new HashSet<ComparedElements>(visiting); newVisiting.add(comparedElements); return newVisiting; } }