use of spoon.support.visitor.ClassTypingContext in project spoon by INRIA.
the class GenericsTest method testClassTypingContext.
@Test
public void testClassTypingContext() throws Exception {
// contract: a ClassTypingContext enables one to perform type resolution of generic types
Factory factory = build(new File("src/test/java/spoon/test/generics/testclasses"));
CtClass<?> ctClassCelebrationLunch = factory.Class().get(CelebrationLunch.class);
CtTypeReference<?> typeReferenceOfDisgust = ctClassCelebrationLunch.filterChildren(new NamedElementFilter<>(CtNamedElement.class, "disgust")).map((CtTypedElement te) -> {
return te.getType();
}).first();
assertEquals("spoon.test.generics.testclasses.CelebrationLunch<java.lang.Integer, java.lang.Long, java.lang.Double>.WeddingLunch<spoon.test.generics.testclasses.Mole>", typeReferenceOfDisgust.toString());
// method WeddingLunch#eatMe
CtMethod<?> tWeddingLunch_eatMe = typeReferenceOfDisgust.getDeclaration().filterChildren((CtNamedElement e) -> "eatMe".equals(e.getSimpleName())).first();
CtClass<?> ctClassLunch = factory.Class().get(Lunch.class);
// method Lunch#eatMe
CtMethod<?> ctClassLunch_eatMe = ctClassLunch.filterChildren((CtNamedElement e) -> "eatMe".equals(e.getSimpleName())).first();
// type of first parameter of method WeddingLunch#eatMe
CtTypeReference<?> ctWeddingLunch_X = tWeddingLunch_eatMe.getParameters().get(0).getType();
// X is the type parameter of WeddingLunch
assertEquals("X", ctWeddingLunch_X.getSimpleName());
// type of first parameter of method Lunch#eatMe
CtTypeReference<?> ctClassLunch_A = ctClassLunch_eatMe.getParameters().get(0).getType();
assertEquals("A", ctClassLunch_A.getSimpleName());
// are these two types same?
ClassTypingContext typingContextOfDisgust = new ClassTypingContext(typeReferenceOfDisgust);
// contract: the class typing context provides its scope
assertSame(typeReferenceOfDisgust.getTypeDeclaration(), typingContextOfDisgust.getAdaptationScope());
// in disgust, X of WeddingLunch is bound to "Model"
assertEquals("spoon.test.generics.testclasses.Mole", typingContextOfDisgust.adaptType(ctWeddingLunch_X).getQualifiedName());
// adapt A to scope of CelebrationLunch<Integer,Long,Double>.WeddingLunch<Mole>
// in disgust, the A of Lunch is bound to "Mole"
assertEquals("spoon.test.generics.testclasses.Mole", typingContextOfDisgust.adaptType(ctClassLunch_A).getQualifiedName());
// I don't understand the goal and utility of this one
assertEquals("java.lang.Double", typingContextOfDisgust.getEnclosingGenericTypeAdapter().adaptType(ctClassLunch_A).getQualifiedName());
// now we resolve those types, but in the context of the declaration, where no concrete types exist
// are these two types same in scope of CelebrationLunch<K,L,M>.WddingLunch<X> class itself
ClassTypingContext sthOftWeddingLunch_X = new ClassTypingContext(typeReferenceOfDisgust.getDeclaration());
// contract: the class typing context provides its scope
assertSame(typeReferenceOfDisgust.getDeclaration(), sthOftWeddingLunch_X.getAdaptationScope());
// in WeddingLunch "X" is still "X"
assertEquals("X", sthOftWeddingLunch_X.adaptType(ctWeddingLunch_X).getQualifiedName());
// in WeddingLunch the "A" from Lunch of is called "X"
assertEquals("X", sthOftWeddingLunch_X.adaptType(ctClassLunch_A).getQualifiedName());
// ?????
// adapt A to scope of enclosing class of CelebrationLunch<K,L,M>.WddingLunch<X>, which is CelebrationLunch<K,L,M>
assertEquals("M", sthOftWeddingLunch_X.getEnclosingGenericTypeAdapter().adaptType(ctClassLunch_A).getQualifiedName());
}
use of spoon.support.visitor.ClassTypingContext in project spoon by INRIA.
the class GenericsTest method testCannotAdaptTypeOfNonTypeScope.
@Test
public void testCannotAdaptTypeOfNonTypeScope() throws Exception {
// contract: ClassTypingContext doesn't fail on type parameters, which are defined out of the scope of ClassTypingContext
CtType<?> ctClass = ModelUtils.buildClass(OuterTypeParameter.class);
// the method defines type parameter, which is used in super of local class
CtReturn<?> retStmt = (CtReturn<?>) ctClass.getMethodsByName("method").get(0).getBody().getStatements().get(0);
CtNewClass<?> newClassExpr = (CtNewClass<?>) retStmt.getReturnedExpression();
CtType<?> declaringType = newClassExpr.getAnonymousClass();
CtMethod<?> m1 = declaringType.getMethodsByName("iterator").get(0);
ClassTypingContext c = new ClassTypingContext(declaringType);
// the adaptation of such type parameter keeps that parameter as it is.
assertFalse(c.isOverriding(m1, declaringType.getSuperclass().getTypeDeclaration().getMethodsByName("add").get(0)));
assertTrue(c.isOverriding(m1, declaringType.getSuperclass().getTypeDeclaration().getMethodsByName("iterator").get(0)));
}
use of spoon.support.visitor.ClassTypingContext in project spoon by INRIA.
the class GenericsTest method testClassContextOnInnerClass.
@Test
public void testClassContextOnInnerClass() throws Exception {
CtClass<?> classBanana = (CtClass<?>) buildClass(Banana.class);
CtClass<?> classVitamins = classBanana.getNestedType("Vitamins");
CtTypeReference<?> refList_T = classVitamins.getSuperclass();
// contract: generic types defined in enclocing classe (Banana<T>) are resolved from inner class hierarchy (Vitamins->List<T>) too.
assertSame(classBanana.getFormalCtTypeParameters().get(0), new ClassTypingContext(classVitamins).adaptType(refList_T.getActualTypeArguments().get(0)).getDeclaration());
}
use of spoon.support.visitor.ClassTypingContext in project spoon by INRIA.
the class GenericsTest method testRecursiveTypeAdapting.
@Test
public void testRecursiveTypeAdapting() throws Exception {
CtType<?> classOrange = buildClass(Orange.class);
CtClass<?> classA = classOrange.getNestedType("A");
CtTypeParameter typeParamO = classA.getFormalCtTypeParameters().get(0);
CtTypeParameter typeParamM = classA.getFormalCtTypeParameters().get(1);
assertEquals("O", typeParamO.getQualifiedName());
assertEquals("M", typeParamM.getQualifiedName());
assertEquals("K", typeParamO.getSuperclass().getQualifiedName());
assertEquals("O", typeParamM.getSuperclass().getQualifiedName());
assertEquals("K", typeParamM.getSuperclass().getSuperclass().getQualifiedName());
CtClass<?> classB = classOrange.getNestedType("B");
CtTypeParameter typeParamN = classB.getFormalCtTypeParameters().get(0);
CtTypeParameter typeParamP = classB.getFormalCtTypeParameters().get(1);
assertEquals("N", typeParamN.getQualifiedName());
assertEquals("P", typeParamP.getQualifiedName());
ClassTypingContext ctcB = new ClassTypingContext(classB);
assertEquals("N", ctcB.adaptType(typeParamO).getQualifiedName());
assertEquals("P", ctcB.adaptType(typeParamM).getQualifiedName());
// contract: superClass of CtTypeParam is adapted too
assertEquals("K", ctcB.adaptType(typeParamO).getSuperclass().getQualifiedName());
assertEquals("N", ctcB.adaptType(typeParamM).getSuperclass().getQualifiedName());
assertEquals("K", ctcB.adaptType(typeParamM).getSuperclass().getSuperclass().getQualifiedName());
CtTypeReference<?> typeRef_list2m = classA.getField("list2m").getType();
assertEquals("java.util.List<java.util.List<M>>", typeRef_list2m.toString());
// contract: the CtTypeReference is adapted recursive including actual type arguments
assertEquals("java.util.List<java.util.List<P>>", ctcB.adaptType(typeRef_list2m).toString());
CtTypeReference<?> typeRef_ListQextendsM = classA.getMethodsByName("method").get(0).getParameters().get(0).getType();
assertEquals("java.util.List<? extends M>", typeRef_ListQextendsM.toString());
// contract: the CtTypeReference is adapted recursive including actual type arguments and their bounds
assertEquals("java.util.List<? extends P>", ctcB.adaptType(typeRef_ListQextendsM).toString());
}
use of spoon.support.visitor.ClassTypingContext in project spoon by INRIA.
the class GenericsTest method testMethodTypingContextAdaptMethod.
@Test
public void testMethodTypingContextAdaptMethod() throws Exception {
// core contracts of MethodTypingContext#adaptMethod
Factory factory = build(new File("src/test/java/spoon/test/generics/testclasses"));
CtClass<?> ctClassLunch = factory.Class().get(Lunch.class);
// represents <C> void eatMe(A paramA, B paramB, C paramC){}
CtMethod<?> trLunch_eatMe = ctClassLunch.filterChildren(new NamedElementFilter<>(CtMethod.class, "eatMe")).first();
CtClass<?> ctClassWeddingLunch = factory.Class().get(WeddingLunch.class);
ClassTypingContext ctcWeddingLunch = new ClassTypingContext(ctClassWeddingLunch);
// we all analyze new methods
final MethodTypingContext methodSTH = new MethodTypingContext().setClassTypingContext(ctcWeddingLunch);
// contract: method can be adapted only using MethodTypingContext
methodSTH.setMethod(trLunch_eatMe);
CtMethod<?> adaptedLunchEatMe = (CtMethod<?>) methodSTH.getAdaptationScope();
// contract: adapting of method declared in different scope, returns new method
assertTrue(adaptedLunchEatMe != trLunch_eatMe);
// check that new method is adapted correctly
// is declared in correct class
assertSame(ctClassWeddingLunch, adaptedLunchEatMe.getDeclaringType());
// is not member of the same class (WeddingLunch)
for (CtTypeMember typeMember : ctClassWeddingLunch.getTypeMembers()) {
assertFalse(adaptedLunchEatMe == typeMember);
}
// the name is the same
assertEquals("eatMe", adaptedLunchEatMe.getSimpleName());
// it has the same number of of formal type parameters
assertEquals(1, adaptedLunchEatMe.getFormalCtTypeParameters().size());
assertEquals("C", adaptedLunchEatMe.getFormalCtTypeParameters().get(0).getQualifiedName());
// parameters are correct
assertEquals(3, adaptedLunchEatMe.getParameters().size());
// "A paramA" becomes "X paramA" becomes Lunch%A corresponds to X in WeddingLunch
assertEquals("X", adaptedLunchEatMe.getParameters().get(0).getType().getQualifiedName());
// B paramB becomes Tacos becomes Lunch%B corresponds to Tacos in WeddingLunch (class WeddingLunch<X> extends CelebrationLunch<Tacos, Paella, X>)
assertEquals(Tacos.class.getName(), adaptedLunchEatMe.getParameters().get(1).getType().getQualifiedName());
// "C paramC" stays "C paramC"
assertEquals("C", adaptedLunchEatMe.getParameters().get(2).getType().getQualifiedName());
// contract: adapting of adapted method returns input method
methodSTH.setMethod(adaptedLunchEatMe);
assertSame(adaptedLunchEatMe, methodSTH.getAdaptationScope());
}
Aggregations