Skip to content

Commit

Permalink
add getTypeParameterDeclaration
Browse files Browse the repository at this point in the history
  • Loading branch information
monperrus committed Apr 2, 2017
1 parent 96c68bf commit acd4f24
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/main/java/spoon/reflect/factory/TypeFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ public CtTypeParameterReference createReference(CtTypeParameter type) {
ref.addAnnotation(ctAnnotation.clone());
}
ref.setSimpleName(type.getSimpleName());

ref.setParent(type);
return ref;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,27 @@ public interface CtTypeParameterReference extends CtTypeReference<Object> {
*/
<T extends CtTypeParameterReference> T setBoundingType(CtTypeReference<?> superType);

// overriding the return type
/**
* Returns the {@link CtTypeParameter}, a {@link CtTypeParameter}, that declares the type parameter
* referenced or <code>null</code> if the reference is not in a context where such type parameter is declared.
* See also {@link #getTypeParameterDeclaration()} which has a different semantic.
*/
@Override
@DerivedProperty
CtTypeParameter getDeclaration();

/**
* Returns the declaration in the target type. In the following example, getTypeParameterDeclaration of T in Dog&lt;T&gt; returns the type parameter definition "X" (while {@link #getDeclaration()} returns the "T" of Cat).
* <pre>
* class Dog&lt;X&gt;{}
* class Cat&lt;T&gt; {
* Dog&lt;T&gt; dog;
* }
* </pre>
*/
@DerivedProperty
CtTypeParameter getTypeParameterDeclaration();

// overriding the return type
@Override
CtTypeParameterReference clone();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,25 +186,32 @@ public CtTypeParameter getDeclaration() {
return result;
}
}
return null;
}

@Override
public CtTypeParameter getTypeParameterDeclaration() {

CtElement parent = this.getParent();

// case 2: this is an actual type argument of a type reference eg List<E>
// case 1: this is an actual type argument of a type reference eg List<E>
if (parent instanceof CtTypeReference) {
CtType t = ((CtTypeReference) parent).getTypeDeclaration();
return findTypeParamDeclaration(t, this.getSimpleName());
return findTypeParamDeclarationByPosition(t, ((CtTypeReference) parent).getActualTypeArguments().indexOf(this));
}

// case 3: this is an actual type argument of a method/constructor reference
// case 2: this is an actual type argument of a method/constructor reference
if (parent instanceof CtExecutableReference) {
CtExecutable<?> exec = ((CtExecutableReference<?>) parent).getExecutableDeclaration();
if (exec instanceof CtMethod || exec instanceof CtConstructor) {
return findTypeParamDeclaration((CtFormalTypeDeclarer) exec, this.getSimpleName());
return findTypeParamDeclarationByPosition((CtFormalTypeDeclarer) exec, ((CtTypeReference) parent).getActualTypeArguments().indexOf(this));
}
}

return null;
}


private CtTypeParameter findTypeParamDeclaration(CtFormalTypeDeclarer type, String refName) {
for (CtTypeParameter typeParam : type.getFormalCtTypeParameters()) {
if (typeParam.getSimpleName().equals(refName)) {
Expand All @@ -214,6 +221,10 @@ private CtTypeParameter findTypeParamDeclaration(CtFormalTypeDeclarer type, Stri
return null;
}

private CtTypeParameter findTypeParamDeclarationByPosition(CtFormalTypeDeclarer type, int position) {
return type.getFormalCtTypeParameters().get(position);
}

@Override
public CtType<Object> getTypeDeclaration() {
return getDeclaration();
Expand Down
21 changes: 13 additions & 8 deletions src/test/java/spoon/test/generics/GenericsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ public void testTypeParameterDeclarer() throws Exception {
assertEquals("T", classThatDefinesANewTypeArgument.getFormalCtTypeParameters().get(0).getSimpleName());
assertSame(classThatDefinesANewTypeArgument, typeParam.getTypeParameterDeclarer());
CtTypeParameterReference typeParamReference = typeParam.getReference();
assertSame(typeParam, typeParamReference.getDeclaration());

// creating an appropriate context
CtMethod m = classThatDefinesANewTypeArgument.getFactory().createMethod();
Expand All @@ -182,6 +183,7 @@ public void testTypeParameterDeclarer() throws Exception {

// the final assertions
assertSame(typeParam, typeParamReference.getDeclaration());

assertSame(classThatDefinesANewTypeArgument, typeParamReference.getDeclaration().getParent());

// now testing that the getDeclaration of a type parameter is actually a dynamic lookup
Expand Down Expand Up @@ -589,12 +591,7 @@ public void testTypeParameterReferenceAsActualTypeArgument() throws Exception {

CtTypeParameter typeParam = aTacos.getFormalCtTypeParameters().get(0);
CtTypeParameterReference typeParamRef = typeParam.getReference();


// a tyoe parameter ref with no context cannot be resolved
assertSame(null, typeParamRef.getDeclaration());
// by default a typeParamRef is not in a tree
assertEquals(false, typeParamRef.isParentInitialized());
assertSame(typeParam, typeParamRef.getDeclaration());

assertEquals("spoon.test.generics.ClassThatDefinesANewTypeArgument", typeRef.toString());

Expand All @@ -611,7 +608,11 @@ public void testTypeParameterReferenceAsActualTypeArgument() throws Exception {
//typeParamRef has got new parent
assertSame(typeRef, typeParamRef.getParent());

assertSame(typeParam, typeParamRef.getDeclaration());
// null because without context
assertEquals(null, typeParamRef.getDeclaration());
assertEquals(typeParam, typeParamRef.getTypeParameterDeclaration());
typeParamRef.setSimpleName("Y");
assertEquals(typeParam, typeParamRef.getTypeParameterDeclaration());
}
@Test
public void testGenericTypeReference() throws Exception {
Expand All @@ -626,7 +627,11 @@ public void testGenericTypeReference() throws Exception {
assertTrue(genericTypeRef.getActualTypeArguments().size()>0);
assertEquals(aTacos.getFormalCtTypeParameters().size(), genericTypeRef.getActualTypeArguments().size());
for(int i=0; i<aTacos.getFormalCtTypeParameters().size(); i++) {
assertSame("TypeParameter reference idx="+i+" is different", aTacos.getFormalCtTypeParameters().get(i), genericTypeRef.getActualTypeArguments().get(i).getDeclaration());
assertSame("TypeParameter reference idx="+i+" is different", aTacos.getFormalCtTypeParameters().get(i), ((CtTypeParameterReference)genericTypeRef.getActualTypeArguments().get(i)).getTypeParameterDeclaration());
}

// contract: getTypeParameterDeclaration goes back to the declaration, eevn without context
assertSame(aTacos.getFormalCtTypeParameters().get(0), ((CtTypeParameterReference)genericTypeRef.getActualTypeArguments().get(0)).getTypeParameterDeclaration());

}
}

0 comments on commit acd4f24

Please sign in to comment.