Skip to content

Commit

Permalink
fix(circular): Supports circular type reference on declaring method.
Browse files Browse the repository at this point in the history
Closes #408
  • Loading branch information
GerardPaligot committed Nov 18, 2015
1 parent 0a6fd04 commit ac7b4a9
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 8 deletions.
26 changes: 18 additions & 8 deletions src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,11 @@ public <T> CtTypeReference<T> getTypeReference(TypeBinding binding) {
if (!JDTTreeBuilder.this.context.isGenericTypeExplicit) {
isImplicit = true;
}
ref.addActualTypeArgument(getTypeReference(b));
if (bindingCache.containsKey(b)) {
ref.addActualTypeArgument(getCtCircularTypeReference(b));
} else {
ref.addActualTypeArgument(getTypeReference(b));
}
isImplicit = false;
}
}
Expand Down Expand Up @@ -545,6 +549,7 @@ public <T> CtTypeReference<T> getTypeReference(TypeBinding binding) {
return getTypeReference(((CaptureBinding) b).wildcard);
} else if (b.superclass != null && b.firstBound == b.superclass) {
bounds = false;
bindingCache.put(binding, ref);
((CtTypeParameterReference) ref).addBound(getTypeReference(b.superclass));
bounds = oldBounds;
}
Expand Down Expand Up @@ -586,13 +591,7 @@ public <T> CtTypeReference<T> getTypeReference(TypeBinding binding) {

if (((WildcardBinding) binding).bound != null && ref instanceof CtTypeParameterReference) {
if (bindingCache.containsKey(((WildcardBinding) binding).bound)) {
final CtCircularTypeReference circularRef = factory.Internal().createCircularTypeReference();
final CtTypeReference originalRef = bindingCache.get(((WildcardBinding) binding).bound);
circularRef.setPackage(originalRef.getPackage());
circularRef.setSimpleName(originalRef.getSimpleName());
circularRef.setDeclaringType(originalRef.getDeclaringType());
circularRef.setActualTypeArguments(originalRef.getActualTypeArguments());
circularRef.setTypeAnnotations(originalRef.getTypeAnnotations());
final CtCircularTypeReference circularRef = getCtCircularTypeReference(((WildcardBinding) binding).bound);
((CtTypeParameterReference) ref).addBound(circularRef);
} else {
((CtTypeParameterReference) ref).addBound(getTypeReference(((WildcardBinding) binding).bound));
Expand Down Expand Up @@ -671,6 +670,17 @@ public <T> CtTypeReference<T> getTypeReference(TypeBinding binding) {
return (CtTypeReference<T>) ref;
}

private CtCircularTypeReference getCtCircularTypeReference(TypeBinding b) {
final CtCircularTypeReference circularRef = factory.Internal().createCircularTypeReference();
final CtTypeReference originalRef = bindingCache.get(b);
circularRef.setPackage(originalRef.getPackage());
circularRef.setSimpleName(originalRef.getSimpleName());
circularRef.setDeclaringType(originalRef.getDeclaringType());
circularRef.setActualTypeArguments(originalRef.getActualTypeArguments());
circularRef.setTypeAnnotations(originalRef.getTypeAnnotations());
return circularRef;
}

private void addTypeAnnotationFromBindingToReference(TypeBinding resolvedType, CtTypeReference<?> reference) {
if (resolvedType.hasTypeAnnotations()) {
final AnnotationBinding[] typeAnnotations = resolvedType.getTypeAnnotations();
Expand Down
26 changes: 26 additions & 0 deletions src/test/java/spoon/test/reference/TypeReferenceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import spoon.compiler.SpoonResource;
import spoon.compiler.SpoonResourceHelper;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtInterface;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtType;
import spoon.reflect.factory.Factory;
import spoon.reflect.internal.CtCircularTypeReference;
Expand All @@ -18,6 +20,7 @@
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.ReferenceTypeFilter;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.test.reference.testclasses.EnumValue;

import java.util.Collection;
import java.util.List;
Expand Down Expand Up @@ -230,6 +233,29 @@ public boolean matches(CtInvocation<?> element) {
assertTrue(circularRef instanceof CtCircularTypeReference);
}

@Test
public void testRecursiveTypeReferenceInGenericType() throws Exception {
final Launcher launcher = new Launcher();
launcher.addInputResource("./src/test/java/spoon/test/reference/testclasses/EnumValue.java");
launcher.setSourceOutputDirectory("./target/spoon-test");
launcher.run();

final CtClass<EnumValue> aClass = launcher.getFactory().Class().get(EnumValue.class);
final CtMethod<?> asEnum = aClass.getMethodsByName("asEnum").get(0);

final CtTypeParameterReference genericType = (CtTypeParameterReference) asEnum.getFormalTypeParameters().get(0);
assertNotNull(genericType);
assertEquals(1, genericType.getBounds().size());

final CtTypeReference<?> extendsGeneric = genericType.getBounds().get(0);
assertNotNull(extendsGeneric);
assertEquals(1, extendsGeneric.getActualTypeArguments().size());

final CtTypeReference circularRef = extendsGeneric.getActualTypeArguments().get(0);
assertNotNull(circularRef);
assertTrue(circularRef instanceof CtCircularTypeReference);
}

class A {
class Tacos<K> {
}
Expand Down
16 changes: 16 additions & 0 deletions src/test/java/spoon/test/reference/testclasses/EnumValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package spoon.test.reference.testclasses;

public class EnumValue {

public EnumValue() {
}

public <T extends Enum<T>> T asEnum() //StackOverflow when referenced
{
return null;
}

public Object unwrap() {
return asEnum();
}
}

0 comments on commit ac7b4a9

Please sign in to comment.