-
-
Notifications
You must be signed in to change notification settings - Fork 346
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: CtTypeParameter(Reference)#getTypeErasure()
- Loading branch information
1 parent
43c7e52
commit 8bbef27
Showing
6 changed files
with
215 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 129 additions & 0 deletions
129
src/test/java/spoon/test/ctType/CtTypeParameterTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package spoon.test.ctType; | ||
|
||
import java.lang.reflect.Executable; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
import java.util.List; | ||
|
||
import org.junit.Test; | ||
|
||
import spoon.reflect.declaration.CtClass; | ||
import spoon.reflect.declaration.CtConstructor; | ||
import spoon.reflect.declaration.CtExecutable; | ||
import spoon.reflect.declaration.CtFormalTypeDeclarer; | ||
import spoon.reflect.declaration.CtMethod; | ||
import spoon.reflect.declaration.CtParameter; | ||
import spoon.reflect.declaration.CtType; | ||
import spoon.reflect.declaration.CtTypeMember; | ||
import spoon.reflect.declaration.CtTypeParameter; | ||
import spoon.reflect.reference.CtTypeParameterReference; | ||
import spoon.reflect.reference.CtTypeReference; | ||
import spoon.reflect.visitor.filter.NameFilter; | ||
import spoon.test.ctType.testclasses.ErasureModelA; | ||
import spoon.testing.utils.ModelUtils; | ||
|
||
import static org.junit.Assert.*; | ||
|
||
public class CtTypeParameterTest { | ||
|
||
@Test | ||
public void testTypeErasure() throws Exception { | ||
//contract: the erasure type computed by CtParameterType(Reference)#getTypeErasure is same like the type of method parameter made by java compiler | ||
CtClass<?> ctModel = (CtClass<?>) ModelUtils.buildClass(ErasureModelA.class); | ||
//visit all methods of type ctModel | ||
//visit all inner types and their methods recursively `getTypeErasure` returns expected value | ||
//for each formal type parameter or method parameter check if | ||
checkType(ctModel); | ||
} | ||
|
||
private void checkType(CtType<?> type) throws NoSuchFieldException, SecurityException { | ||
List<CtTypeParameter> l_typeParams = type.getFormalCtTypeParameters(); | ||
for (CtTypeParameter ctTypeParameter : l_typeParams) { | ||
checkTypeParamErasureOfType(ctTypeParameter, type.getActualClass()); | ||
} | ||
|
||
for (CtTypeMember typeMemeber : type.getTypeMembers()) { | ||
if (typeMemeber instanceof CtFormalTypeDeclarer) { | ||
CtFormalTypeDeclarer ftDecl = (CtFormalTypeDeclarer) typeMemeber; | ||
l_typeParams = ftDecl.getFormalCtTypeParameters(); | ||
if (typeMemeber instanceof CtExecutable<?>) { | ||
CtExecutable<?> exec = (CtExecutable<?>) typeMemeber; | ||
for (CtTypeParameter ctTypeParameter : l_typeParams) { | ||
checkTypeParamErasureOfExecutable(ctTypeParameter, exec); | ||
} | ||
for (CtParameter<?> param : exec.getParameters()) { | ||
checkParameterErasureOfExecutable(param, exec); | ||
} | ||
} else if (typeMemeber instanceof CtType<?>) { | ||
CtType<?> nestedType = (CtType<?>) typeMemeber; | ||
checkType(nestedType); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void checkTypeParamErasureOfType(CtTypeParameter typeParam, Class<?> clazz) throws NoSuchFieldException, SecurityException { | ||
Field field = clazz.getDeclaredField("param"+typeParam.getSimpleName()); | ||
assertEquals("TypeErasure of type param "+getTypeParamIdentification(typeParam), field.getType().getName(), typeParam.getTypeErasure().getQualifiedName()); | ||
} | ||
|
||
private void checkTypeParamErasureOfExecutable(CtTypeParameter typeParam, CtExecutable<?> exec) throws NoSuchFieldException, SecurityException { | ||
CtParameter<?> param = exec.filterChildren(new NameFilter<>("param"+typeParam.getSimpleName())).first(); | ||
assertNotNull("Missing param"+typeParam.getSimpleName() + " in "+ exec.getSignature(), param); | ||
int paramIdx = exec.getParameters().indexOf(param); | ||
Class declClass = exec.getParent(CtType.class).getActualClass(); | ||
Executable declExec; | ||
if (exec instanceof CtConstructor) { | ||
declExec = declClass.getDeclaredConstructors()[0]; | ||
} else { | ||
declExec = getMethodByName(declClass, exec.getSimpleName()); | ||
} | ||
Class<?> paramType = declExec.getParameterTypes()[paramIdx]; | ||
assertEquals("TypeErasure of executable param "+getTypeParamIdentification(typeParam), paramType.getName(), typeParam.getTypeErasure().getQualifiedName()); | ||
} | ||
|
||
private void checkParameterErasureOfExecutable(CtParameter<?> param, CtExecutable<?> exec) { | ||
CtTypeReference<?> paramTypeRef = param.getType(); | ||
if (paramTypeRef instanceof CtTypeParameterReference) { | ||
CtTypeParameterReference typeParamRef = (CtTypeParameterReference) paramTypeRef; | ||
paramTypeRef = typeParamRef.getTypeErasure(); | ||
} | ||
int paramIdx = exec.getParameters().indexOf(param); | ||
Class declClass = exec.getParent(CtType.class).getActualClass(); | ||
Executable declExec; | ||
if (exec instanceof CtConstructor) { | ||
declExec = declClass.getDeclaredConstructors()[0]; | ||
} else { | ||
declExec = getMethodByName(declClass, exec.getSimpleName()); | ||
} | ||
Class<?> paramType = declExec.getParameterTypes()[paramIdx]; | ||
assertEquals("TypeErasure of executable "+exec.getSignature()+" parameter "+param.getSimpleName(), paramType.getName(), paramTypeRef.getQualifiedName()); | ||
} | ||
|
||
|
||
private Executable getMethodByName(Class declClass, String simpleName) { | ||
for (Method method : declClass.getDeclaredMethods()) { | ||
if(method.getName().equals(simpleName)) { | ||
return method; | ||
} | ||
} | ||
fail("Method "+simpleName+" not found in "+declClass.getName()); | ||
return null; | ||
} | ||
|
||
private String getTypeParamIdentification(CtTypeParameter typeParam) { | ||
String result = "<"+typeParam.getSimpleName()+">"; | ||
CtFormalTypeDeclarer l_decl = typeParam.getParent(CtFormalTypeDeclarer.class); | ||
if (l_decl instanceof CtType) { | ||
return ((CtType) l_decl).getQualifiedName()+result; | ||
} | ||
if (l_decl instanceof CtExecutable) { | ||
CtExecutable exec = (CtExecutable) l_decl; | ||
if (exec instanceof CtMethod) { | ||
result=exec.getSignature()+result; | ||
} | ||
return exec.getParent(CtType.class).getQualifiedName()+"#"+result; | ||
} | ||
throw new AssertionError(); | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
src/test/java/spoon/test/ctType/testclasses/ErasureModelA.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package spoon.test.ctType.testclasses; | ||
|
||
import java.io.Serializable; | ||
import java.util.List; | ||
|
||
public class ErasureModelA<A, B extends Exception, C extends B, D extends List<B>> { | ||
|
||
A paramA; | ||
B paramB; | ||
C paramC; | ||
D paramD; | ||
|
||
public <I, J extends C> ErasureModelA(I paramI, J paramJ, D paramD) { | ||
} | ||
|
||
public <I, J extends C, K extends ErasureModelA<A,B,C,D>&Serializable> void method(I paramI, J paramJ, D paramD, K paramK) { | ||
} | ||
|
||
public <I> void wildCardMethod(I paramI, ErasureModelA<? extends I, B, C, D> extendsI) { | ||
} | ||
|
||
static class ModelB<A2,B2 extends Exception, C2 extends B2, D2 extends List<B2>> extends ErasureModelA<A2,B2,C2,D2> { | ||
A2 paramA2; | ||
B2 paramB2; | ||
C2 paramC2; | ||
D2 paramD2; | ||
|
||
public <I, J extends C2> ModelB(I paramI, J paramJ, D2 paramD2) { | ||
super(paramI, paramJ, paramD2); | ||
} | ||
|
||
@Override | ||
public <I, J extends C2, K2 extends ErasureModelA<A2,B2,C2,D2>&Serializable> void method(I paramI, J paramJ, D2 paramD2, K2 paramK2) { | ||
} | ||
} | ||
|
||
static class ModelC extends ErasureModelA<Integer, RuntimeException, IllegalArgumentException, List<RuntimeException>> { | ||
|
||
public ModelC(Float paramI, IllegalArgumentException paramJ, ModelC paramK) { | ||
super(paramI, paramJ, null); | ||
} | ||
|
||
public void method(Float paramI, IllegalArgumentException paramJ, ModelC paramK) { | ||
} | ||
} | ||
} |