-
-
Notifications
You must be signed in to change notification settings - Fork 352
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: CtTypeParamer#getTypeErasure, getTypeAdaptedTo
- Loading branch information
1 parent
286e6e9
commit 059792f
Showing
4 changed files
with
310 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
111 changes: 111 additions & 0 deletions
111
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,111 @@ | ||
package spoon.test.ctType; | ||
|
||
import java.lang.reflect.Executable; | ||
import java.lang.reflect.Field; | ||
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.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 { | ||
CtClass<?> ctModel = (CtClass<?>) ModelUtils.buildClass(ErasureModelA.class); | ||
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); | ||
} | ||
} 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 = declClass.getDeclaredMethods()[0]; | ||
} | ||
Class<?> paramType = declExec.getParameterTypes()[paramIdx]; | ||
assertEquals("TypeErasure of executable param "+getTypeParamIdentification(typeParam), paramType.getName(), typeParam.getTypeErasure().getQualifiedName()); | ||
} | ||
|
||
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(); | ||
} | ||
|
||
@Test | ||
public void testTypeAdapted() throws Exception { | ||
CtClass<?> ctModel = (CtClass<?>) ModelUtils.buildClass(ErasureModelA.class); | ||
CtTypeParameter tpA = ctModel.getFormalCtTypeParameters().get(0); | ||
CtTypeParameter tpB = ctModel.getFormalCtTypeParameters().get(1); | ||
CtTypeParameter tpC = ctModel.getFormalCtTypeParameters().get(2); | ||
CtTypeParameter tpD = ctModel.getFormalCtTypeParameters().get(3); | ||
|
||
CtClass<?> ctModelB = ctModel.filterChildren(new NameFilter<>("ModelB")).first(); | ||
assertEquals("A2", tpA.getTypeAdaptedTo(ctModelB).getQualifiedName()); | ||
assertEquals("B2", tpB.getTypeAdaptedTo(ctModelB).getQualifiedName()); | ||
assertEquals("C2", tpC.getTypeAdaptedTo(ctModelB).getQualifiedName()); | ||
assertEquals("D2", tpD.getTypeAdaptedTo(ctModelB).getQualifiedName()); | ||
|
||
CtClass<?> ctModelC = ctModel.filterChildren(new NameFilter<>("ModelC")).first(); | ||
assertEquals("java.lang.Integer", tpA.getTypeAdaptedTo(ctModelC).getQualifiedName()); | ||
assertEquals("java.lang.RuntimeException", tpB.getTypeAdaptedTo(ctModelC).getQualifiedName()); | ||
assertEquals("java.lang.IllegalArgumentException", tpC.getTypeAdaptedTo(ctModelC).getQualifiedName()); | ||
assertEquals("spoon.test.ctType.testclasses.ErasureModelA$ModelC", tpD.getTypeAdaptedTo(ctModelC).getQualifiedName()); | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
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,40 @@ | ||
package spoon.test.ctType.testclasses; | ||
|
||
public class ErasureModelA<A, B extends Exception, C extends B, D extends ErasureModelA<A,B,C,D>> { | ||
|
||
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> void method(I paramI, J paramJ, D paramD) { | ||
} | ||
|
||
static class ModelB<A2,B2 extends Exception, C2 extends B2, D2 extends ErasureModelA<A2,B2,C2,D2>> 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> void method(I paramI, J paramJ, D2 paramD2) { | ||
} | ||
} | ||
|
||
static class ModelC extends ErasureModelA<Integer, RuntimeException, IllegalArgumentException, ModelC> { | ||
|
||
public ModelC(Float paramI, IllegalArgumentException paramJ, ModelC paramK) { | ||
super(paramI, paramJ, null); | ||
} | ||
|
||
public void method(Float paramI, IllegalArgumentException paramJ, ModelC paramK) { | ||
} | ||
} | ||
} |