Skip to content

Commit

Permalink
refactor(api): Changes generics bounds from List to Set. (#659)
Browse files Browse the repository at this point in the history
  • Loading branch information
GerardPaligot authored and monperrus committed May 11, 2016
1 parent 86bd8e0 commit 0b3390f
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 32 deletions.
23 changes: 23 additions & 0 deletions src/main/java/spoon/reflect/factory/TypeFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import static spoon.testing.utils.ModelUtils.createFactory;

Expand Down Expand Up @@ -388,14 +390,35 @@ public CtTypeParameterReference createTypeParameterReference(String name, List<C
* List of bounds saved in the intersection type. The first bound will be the intersection type.
* @param <T>
* Type of the first bound.
* @see #createIntersectionTypeReferenceWithBounds(Set)
*/
@Deprecated
public <T> CtIntersectionTypeReference<T> createIntersectionTypeReference(List<CtTypeReference<?>> bounds) {
final CtIntersectionTypeReference<T> intersectionRef = factory.Core().createIntersectionTypeReference();
CtTypeReference<?> firstBound = factory.Core().clone(bounds.get(0));
intersectionRef.setSimpleName(firstBound.getSimpleName());
intersectionRef.setDeclaringType(firstBound.getDeclaringType());
intersectionRef.setPackage(firstBound.getPackage());
intersectionRef.setActualTypeArguments(firstBound.getActualTypeArguments());
intersectionRef.setBounds(new TreeSet<CtTypeReference<?>>(bounds));
return intersectionRef;
}

/**
* Creates an intersection type reference.
*
* @param bounds
* List of bounds saved in the intersection type. The first bound will be the intersection type.
* @param <T>
* Type of the first bound.
*/
public <T> CtIntersectionTypeReference<T> createIntersectionTypeReferenceWithBounds(Set<CtTypeReference<?>> bounds) {
final CtIntersectionTypeReference<T> intersectionRef = factory.Core().createIntersectionTypeReference();
CtTypeReference<?> firstBound = factory.Core().clone(bounds.toArray(new CtTypeReference<?>[0])[0]);
intersectionRef.setSimpleName(firstBound.getSimpleName());
intersectionRef.setDeclaringType(firstBound.getDeclaringType());
intersectionRef.setPackage(firstBound.getPackage());
intersectionRef.setActualTypeArguments(firstBound.getActualTypeArguments());
intersectionRef.setBounds(bounds);
return intersectionRef;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/
package spoon.reflect.reference;

import java.util.List;
import java.util.Set;

/**
* This interface defines a reference to an intersection type in generics or in casts.
Expand All @@ -28,12 +28,12 @@ public interface CtIntersectionTypeReference<T> extends CtTypeReference<T> {
* T extends Interface1 &amp; Interface2 // CtTypeParameterReference#getBoundingType == Interface1 and getBounds().get(0) == Interface1
* </pre>
*/
List<CtTypeReference<?>> getBounds();
Set<CtTypeReference<?>> getBounds();

/**
* Sets the bounds of the intersection type.
*/
<C extends CtIntersectionTypeReference> C setBounds(List<CtTypeReference<?>> bounds);
<C extends CtIntersectionTypeReference> C setBounds(Set<CtTypeReference<?>> bounds);

/**
* Adds a bound.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,42 +21,41 @@
import spoon.reflect.visitor.CtVisitor;
import spoon.support.reflect.declaration.CtElementImpl;

import java.util.ArrayList;
import java.util.List;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

import static spoon.reflect.ModelElementContainerDefaultCapacities.TYPE_BOUNDS_CONTAINER_DEFAULT_CAPACITY;
import static java.util.Collections.unmodifiableSet;

public class CtIntersectionTypeReferenceImpl<T> extends CtTypeReferenceImpl<T> implements CtIntersectionTypeReference<T> {
List<CtTypeReference<?>> bounds = CtElementImpl.emptyList();
Set<CtTypeReference<?>> bounds = CtElementImpl.emptySet();

@Override
public void accept(CtVisitor visitor) {
visitor.visitCtIntersectionTypeReference(this);
}

@Override
public List<CtTypeReference<?>> getBounds() {
return unmodifiableList(bounds);
public Set<CtTypeReference<?>> getBounds() {
return unmodifiableSet(bounds);
}

@Override
public <C extends CtIntersectionTypeReference> C setBounds(List<CtTypeReference<?>> bounds) {
if (this.bounds == CtElementImpl.<CtTypeReference<?>>emptyList()) {
this.bounds = new ArrayList<CtTypeReference<?>>(TYPE_BOUNDS_CONTAINER_DEFAULT_CAPACITY);
public <C extends CtIntersectionTypeReference> C setBounds(Set<CtTypeReference<?>> bounds) {
if (this.bounds == CtElementImpl.<CtTypeReference<?>>emptySet()) {
this.bounds = new TreeSet<CtTypeReference<?>>(new SourcePositionComparator());
}
this.bounds.clear();
final List<CtTypeReference<?>> newBounds = new ArrayList<CtTypeReference<?>>();
newBounds.addAll(bounds);
for (CtTypeReference<?> bound : newBounds) {
for (CtTypeReference<?> bound : bounds) {
addBound(bound);
}
return (C) this;
}

@Override
public <C extends CtIntersectionTypeReference> C addBound(CtTypeReference<?> bound) {
if (bounds == CtElementImpl.<CtTypeReference<?>>emptyList()) {
bounds = new ArrayList<CtTypeReference<?>>(TYPE_BOUNDS_CONTAINER_DEFAULT_CAPACITY);
if (bounds == CtElementImpl.<CtTypeReference<?>>emptySet()) {
bounds = new TreeSet<CtTypeReference<?>>(new SourcePositionComparator());
}
bound.setParent(this);
bounds.add(bound);
Expand All @@ -67,4 +66,16 @@ public <C extends CtIntersectionTypeReference> C addBound(CtTypeReference<?> bou
public boolean removeBound(CtTypeReference<?> bound) {
return bounds != CtElementImpl.<CtTypeReference<?>>emptyList() && bounds.remove(bound);
}

private class SourcePositionComparator implements Comparator<CtTypeReference<?>> {
@Override
public int compare(CtTypeReference<?> o1, CtTypeReference<?> o2) {
if (o1.getPosition() == null || o2.getPosition() == null) {
return -1;
}
int pos1 = o1.getPosition().getSourceStart();
int pos2 = o2.getPosition().getSourceStart();
return (pos1 < pos2) ? -1 : ((pos1 == pos2) ? 0 : 1);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.TreeSet;

import static spoon.reflect.ModelElementContainerDefaultCapacities.TYPE_TYPE_PARAMETERS_CONTAINER_DEFAULT_CAPACITY;

Expand All @@ -51,7 +52,7 @@ public void accept(CtVisitor visitor) {
@Override
public List<CtTypeReference<?>> getBounds() {
if (getBoundingType() instanceof CtIntersectionTypeReference<?>) {
return getBoundingType().asCtIntersectionTypeReference().getBounds();
return Arrays.asList(getBoundingType().asCtIntersectionTypeReference().getBounds().toArray(new CtTypeReference<?>[0]));
} else if (getBoundingType() != null) {
return Collections.<CtTypeReference<?>>singletonList(getBoundingType());
}
Expand All @@ -70,7 +71,7 @@ public <T extends CtTypeParameterReference> T setBounds(List<CtTypeReference<?>>
return (T) this;
}
if (getBoundingType() instanceof CtIntersectionTypeReference<?>) {
getBoundingType().asCtIntersectionTypeReference().setBounds(bounds);
getBoundingType().asCtIntersectionTypeReference().setBounds(new TreeSet<CtTypeReference<?>>(bounds));
} else if (bounds.size() > 1) {
setBoundingType(getFactory().Type().createIntersectionTypeReference(bounds));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,15 +610,15 @@ public void set(spoon.reflect.code.CtStatement replace) {
}
}

class CtIntersectionTypeReferenceBoundsReplaceListener implements spoon.generating.replace.ReplaceListListener<java.util.List> {
class CtIntersectionTypeReferenceBoundsReplaceListener implements spoon.generating.replace.ReplaceSetListener<java.util.Set> {
private spoon.reflect.reference.CtIntersectionTypeReference element;

CtIntersectionTypeReferenceBoundsReplaceListener(spoon.reflect.reference.CtIntersectionTypeReference element) {
this.element = element;
}

@java.lang.Override
public void set(java.util.List replace) {
public void set(java.util.Set replace) {
this.element.setBounds(replace);
}
}
Expand Down Expand Up @@ -1609,7 +1609,7 @@ public void visitCtTypeParameterReference(final spoon.reflect.reference.CtTypePa

@java.lang.Override
public <T> void visitCtIntersectionTypeReference(final spoon.reflect.reference.CtIntersectionTypeReference<T> reference) {
replaceInListIfExist(reference.getBounds(), new spoon.support.visitor.replace.ReplacementVisitor.CtIntersectionTypeReferenceBoundsReplaceListener(reference));
replaceInSetIfExist(reference.getBounds(), new spoon.support.visitor.replace.ReplacementVisitor.CtIntersectionTypeReferenceBoundsReplaceListener(reference));
}

public <T> void visitCtTypeReference(final spoon.reflect.reference.CtTypeReference<T> reference) {
Expand Down
11 changes: 7 additions & 4 deletions src/test/java/spoon/test/constructor/ConstructorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
import spoon.test.constructor.testclasses.Tacos;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
Expand Down Expand Up @@ -108,9 +110,10 @@ public void testTypeAnnotationWithConstructorsOnFormalType() throws Exception {

assertNotNull(genericT.getBoundingType());
assertTrue(genericT.getBoundingType() instanceof CtIntersectionTypeReference);
CtIntersectionTypeReference<?> bounds = genericT.getBoundingType().asCtIntersectionTypeReference();
CtIntersectionTypeReference<?> boundingType = genericT.getBoundingType().asCtIntersectionTypeReference();

CtTypeReference<?> genericTacos = bounds.getBounds().get(0);
final List<CtTypeReference<?>> bounds = boundingType.getBounds().stream().collect(Collectors.toList());
CtTypeReference<?> genericTacos = bounds.get(0);
assertEquals("Tacos", genericTacos.getSimpleName());
assertEquals(1, genericTacos.getAnnotations().size());

Expand All @@ -121,7 +124,7 @@ public void testTypeAnnotationWithConstructorsOnFormalType() throws Exception {
assertEquals("C", wildcard.getBoundingType().getSimpleName());
assertEquals(1, wildcard.getBoundingType().getAnnotations().size());

assertEquals("Serializable", bounds.getBounds().get(1).getSimpleName());
assertEquals(1, bounds.getBounds().get(1).getAnnotations().size());
assertEquals("Serializable", bounds.get(1).getSimpleName());
assertEquals(1, bounds.get(1).getAnnotations().size());
}
}
13 changes: 7 additions & 6 deletions src/test/java/spoon/test/type/TypeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;

import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertEquals;
Expand Down Expand Up @@ -174,8 +175,8 @@ public void testIntersectionTypeReferenceInGenericsAndCasts() throws Exception {
assertTrue(generic.getBoundingType() instanceof CtIntersectionTypeReference);
assertEquals("java.lang.Runnable & java.io.Serializable", generic.getBoundingType().toString());
final CtIntersectionTypeReference<?> superType = generic.getBoundingType().asCtIntersectionTypeReference();
assertEquals(aPozole.getFactory().Type().createReference(Runnable.class), superType.getBounds().get(0));
assertEquals(aPozole.getFactory().Type().createReference(Serializable.class), superType.getBounds().get(1));
assertEquals(aPozole.getFactory().Type().createReference(Runnable.class), superType.getBounds().stream().collect(Collectors.toList()).get(0));
assertEquals(aPozole.getFactory().Type().createReference(Serializable.class), superType.getBounds().stream().collect(Collectors.toList()).get(1));

// Intersection type in casts.
final List<CtLambda<?>> lambdas = prepare.getElements(new TypeFilter<CtLambda<?>>(CtLambda.class));
Expand All @@ -185,8 +186,8 @@ public void testIntersectionTypeReferenceInGenericsAndCasts() throws Exception {
assertTrue(lambdas.get(0).getTypeCasts().get(0) instanceof CtIntersectionTypeReference);
final CtIntersectionTypeReference<?> intersectionType = lambdas.get(0).getTypeCasts().get(0).asCtIntersectionTypeReference();
assertEquals("java.lang.Runnable & java.io.Serializable", intersectionType.toString());
assertEquals(aPozole.getFactory().Type().createReference(Runnable.class), intersectionType.getBounds().get(0));
assertEquals(aPozole.getFactory().Type().createReference(Serializable.class), intersectionType.getBounds().get(1));
assertEquals(aPozole.getFactory().Type().createReference(Runnable.class), intersectionType.getBounds().stream().collect(Collectors.toList()).get(0));
assertEquals(aPozole.getFactory().Type().createReference(Serializable.class), intersectionType.getBounds().stream().collect(Collectors.toList()).get(1));

canBeBuilt(target, 8, true);
}
Expand Down Expand Up @@ -235,8 +236,8 @@ public void testIntersectionTypeOnTopLevelType() throws Exception {
assertNotNull(ref.getBoundingType());
assertTrue(ref.getBoundingType() instanceof CtIntersectionTypeReference);
assertEquals(2, ref.getBoundingType().asCtIntersectionTypeReference().getBounds().size());
assertEquals(Number.class, ref.getBoundingType().asCtIntersectionTypeReference().getBounds().get(0).getActualClass());
assertEquals(Comparable.class, ref.getBoundingType().asCtIntersectionTypeReference().getBounds().get(1).getActualClass());
assertEquals(Number.class, ref.getBoundingType().asCtIntersectionTypeReference().getBounds().stream().collect(Collectors.toList()).get(0).getActualClass());
assertEquals(Comparable.class, ref.getBoundingType().asCtIntersectionTypeReference().getBounds().stream().collect(Collectors.toList()).get(1).getActualClass());
assertEquals("public class Mole<NUMBER extends java.lang.Number & java.lang.Comparable<NUMBER>> {}", aMole.toString());
}

Expand Down

0 comments on commit 0b3390f

Please sign in to comment.