package spoon.test.targeted; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static spoon.testing.utils.ModelUtils.build; import static spoon.testing.utils.ModelUtils.buildClass; import java.util.List; import org.junit.Test; import spoon.Launcher; import spoon.reflect.code.CtExpression; import spoon.reflect.code.CtFieldAccess; import spoon.reflect.code.CtFieldRead; import spoon.reflect.code.CtFieldWrite; import spoon.reflect.code.CtInvocation; import spoon.reflect.code.CtSuperAccess; import spoon.reflect.code.CtThisAccess; import spoon.reflect.code.CtTypeAccess; import spoon.reflect.declaration.CtAnonymousExecutable; import spoon.reflect.declaration.CtClass; import spoon.reflect.declaration.CtConstructor; import spoon.reflect.declaration.CtField; import spoon.reflect.declaration.CtMethod; import spoon.reflect.declaration.CtType; import spoon.reflect.factory.Factory; import spoon.reflect.reference.CtFieldReference; import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.filter.NameFilter; import spoon.reflect.visitor.filter.TypeFilter; import spoon.support.comparator.CtLineElementComparator; import spoon.support.reflect.code.CtConstructorCallImpl; import spoon.support.reflect.code.CtFieldReadImpl; import spoon.support.reflect.code.CtThisAccessImpl; import spoon.support.util.SortedList; import spoon.test.targeted.testclasses.Bar; import spoon.test.targeted.testclasses.Foo; import spoon.test.targeted.testclasses.InternalSuperCall; import spoon.test.targeted.testclasses.Pozole; import spoon.test.targeted.testclasses.SuperClass; import spoon.test.targeted.testclasses.Tapas; import com.sun.org.apache.bcel.internal.classfile.InnerClass; public class TargetedExpressionTest { @Test public void testCtSuperAccess() throws Exception { final Factory factory = build(InternalSuperCall.class); final CtClass<?> ctClass = factory.Class().get(InternalSuperCall.class); CtMethod<?> method = ctClass.getElements(new NameFilter<CtMethod<?>>("methode")).get(0); assertEquals( "spoon.test.targeted.testclasses.InternalSuperCall.super.toString()", method.getBody().getStatements().get(0).toString()); assertNotNull(method.getElements(new TypeFilter<>(CtSuperAccess.class)).get(0).getTarget()); CtMethod<?> toStringMethod = ctClass.getElements(new NameFilter<CtMethod<?>>("toString")).get(0); assertEquals( "return super.toString()", toStringMethod.getBody().getStatements().get(0).toString()); assertNull(toStringMethod.getElements(new TypeFilter<>(CtSuperAccess.class)).get(0).getTarget()); } @Test public void testCtThisAccess() throws Exception { CtType<?> type = build("spoon.test.targeted.testclasses", "InnerClassThisAccess"); assertEquals("InnerClassThisAccess", type.getSimpleName()); CtMethod<?> meth1 = type.getElements(new NameFilter<CtMethod<?>>("method2")).get(0); assertEquals( "this.method()", meth1.getBody().getStatements().get(0).toString()); CtClass<?> c = type.getElements(new NameFilter<CtClass<?>>("1InnerClass")).get(0); assertEquals("1InnerClass", c.getSimpleName()); CtConstructor<?> ctr = c.getConstructor(type.getFactory().Type().createReference(boolean.class)); assertEquals("this.b = b", ctr.getBody().getLastStatement().toString()); } @Test public void testTargetOfFieldAccess() throws Exception { Factory factory = build(Foo.class, Bar.class, SuperClass.class); final CtClass<Object> type = factory.Class().get(Foo.class); CtConstructor<?> constructor = type.getConstructors().toArray(new CtConstructor<?>[0])[0]; final List<CtFieldAccess<?>> elements = constructor.getElements(new TypeFilter<CtFieldAccess<?>>(CtFieldAccess.class)); assertEquals(2, elements.size()); assertEquals("Target is CtThisAccessImpl if there is a 'this' explicit.", CtThisAccessImpl.class, elements.get(0).getTarget().getClass()); assertNotNull("Target isn't null if there is a 'this' explicit.", elements.get(1).getTarget()); assertTrue(elements.get(1).getTarget().isImplicit()); } @Test public void testNotTargetedExpression() throws Exception { Factory factory = build(Foo.class, Bar.class, SuperClass.class); CtClass<Object> fooClass = factory.Class().get(Foo.class); CtField<?> iField = fooClass.getField("i"); CtFieldAccess<?> fieldAccess = factory.Core().createFieldRead(); fieldAccess.setVariable((CtFieldReference) iField.getReference()); fieldAccess.setTarget(factory.Code().createThisAccess(fooClass.getReference())); assertEquals("this.i", fieldAccess.toString()); // this test is made for this line. Check that we can setTarget(null) // without NPE fieldAccess.setTarget(null); assertEquals("i", fieldAccess.toString()); } @Test public void testCastWriteWithGenerics() throws Exception { final Factory factory = build(Pozole.class); final CtClass<Object> aPozole = factory.Class().get(Pozole.class); final CtConstructor<Object> aConstructor = aPozole.getConstructor(aPozole.getReference()); final List<CtFieldRead> elements = aConstructor.getElements(new TypeFilter<>(CtFieldRead.class)); assertEquals(1, elements.size()); assertEquals("((spoon.test.targeted.testclasses.Pozole<T>) (v1))", elements.get(0).getTarget().toString()); } @Test public void testTargetsOfFieldAccess() throws Exception { final Factory factory = build(Foo.class, Bar.class, SuperClass.class); final CtClass<Foo> type = factory.Class().get(Foo.class); final CtTypeReference<Foo> expectedType = type.getReference(); final CtTypeReference<Bar> expectedBarType = factory.Class().<Bar>get(Bar.class).getReference(); final CtTypeReference<SuperClass> expectedSuperClassType = factory.Class().<SuperClass>get(SuperClass.class).getReference(); final CtTypeReference<Foo.Fii.Fuu> expectedFuuType = factory.Class().<Foo.Fii.Fuu>get(Foo.Fii.Fuu.class).getReference(); final CtMethod<?> fieldMethod = type.getMethodsByName("field").get(0); final CtThisAccess<Foo> expectedThisAccess = type.getFactory().Code().createThisAccess(expectedType); final List<CtFieldAccess<?>> elements = fieldMethod.getElements(new TypeFilter<CtFieldAccess<?>>(CtFieldAccess.class)); assertEquals(10, elements.size()); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("this.i"), elements.get(0)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("i"), elements.get(1)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedBarType).target(elements.get(3)).result("this.bar.i"), elements.get(2)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("this.bar"), elements.get(3)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedBarType).target(elements.get(5)).result("bar.i"), elements.get(4)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("bar"), elements.get(5)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedSuperClassType).target(expectedThisAccess).result("this.o"), elements.get(6)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedSuperClassType).target(expectedThisAccess).result("o"), elements.get(7)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedFuuType).target(elements.get(9)).result("fuu.p"), elements.get(8)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("fuu"), elements.get(9)); } @Test public void testTargetsOfStaticFieldAccess() throws Exception { final Factory factory = build(Foo.class, Bar.class, SuperClass.class); final CtClass<Foo> type = factory.Class().get(Foo.class); final CtTypeReference<Foo> expectedType = type.getReference(); final CtTypeReference<Bar> expectedBarType = factory.Class().<Bar>get(Bar.class).getReference(); final CtMethod<?> constructor = type.getMethodsByName("m").get(0); final CtThisAccess<Foo> expectedThisAccess = type.getFactory().Code().createThisAccess(expectedType); final CtTypeAccess<Foo> expectedTypeAccess = type.getFactory().Code().createTypeAccess(expectedType); final CtTypeAccess<Bar> expectedBarTypeAccess = type.getFactory().Code().createTypeAccess(expectedBarType); final List<CtFieldAccess<?>> elements = constructor.getElements(new TypeFilter<CtFieldAccess<?>>(CtFieldAccess.class)); assertEquals(10, elements.size()); assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldRead.class).declaringType(expectedType).target(expectedThisAccess).result("this.k"), elements.get(0)); assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldRead.class).declaringType(expectedType).target(expectedTypeAccess).result("spoon.test.targeted.testclasses.Foo.k"), elements.get(1)); assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldRead.class).declaringType(expectedType).target(expectedTypeAccess).result("spoon.test.targeted.testclasses.Foo.k"), elements.get(2)); assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldWrite.class).declaringType(expectedType).target(expectedThisAccess).result("this.k"), elements.get(3)); assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldWrite.class).declaringType(expectedType).target(expectedTypeAccess).result("spoon.test.targeted.testclasses.Foo.k"), elements.get(4)); assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldWrite.class).declaringType(expectedType).target(expectedTypeAccess).result("spoon.test.targeted.testclasses.Foo.k"), elements.get(5)); assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldRead.class).declaringType(expectedBarType).target(expectedBarTypeAccess).result("spoon.test.targeted.testclasses.Bar.FIELD"), elements.get(6)); assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldRead.class).declaringType(expectedBarType).target(expectedBarTypeAccess).result("spoon.test.targeted.testclasses.Bar.FIELD"), elements.get(7)); assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldWrite.class).declaringType(expectedBarType).target(expectedBarTypeAccess).result("spoon.test.targeted.testclasses.Bar.FIELD"), elements.get(8)); assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldWrite.class).declaringType(expectedBarType).target(expectedBarTypeAccess).result("spoon.test.targeted.testclasses.Bar.FIELD"), elements.get(9)); final CtAnonymousExecutable staticInit = type.getAnonymousExecutables().get(0); final List<CtFieldAccess<?>> staticElements = staticInit.getElements(new TypeFilter<>(CtFieldAccess.class)); assertEquals(1, staticElements.size()); // Changing behaviour when writing static field, it is now writed using the class name assertEqualsFieldAccess(new ExpectedTargetedExpression().type(CtFieldWrite.class).declaringType(expectedType).target(expectedTypeAccess).result("p"), staticElements.get(0)); } @Test public void testTargetsOfFieldAccessInInnerClass() throws Exception { final Factory factory = build(Foo.class, Bar.class, SuperClass.class); final CtClass<Foo> type = factory.Class().get(Foo.class); final CtTypeReference<Foo> expectedType = type.getReference(); final CtTypeReference<SuperClass> expectedSuperClassType = factory.Class().<SuperClass>get(SuperClass.class).getReference(); final CtType<InnerClass> innerClass = type.getNestedType("InnerClass"); final CtTypeReference<InnerClass> expectedInnerClass = innerClass.getReference(); final CtType<?> nestedTypeScanner = type.getNestedType("1NestedTypeScanner"); final CtTypeReference<?> expectedNested = nestedTypeScanner.getReference(); final CtTypeAccess<Foo> fooTypeAccess = factory.Code().createTypeAccess(expectedType); final CtThisAccess<Foo> expectedThisAccess = factory.Code().createThisAccess(expectedType); final CtThisAccess<InnerClass> expectedInnerClassAccess = factory.Code().createThisAccess(expectedInnerClass); final CtThisAccess expectedNestedAccess = factory.Code().createThisAccess(expectedNested); final CtMethod<?> innerInvMethod = innerClass.getMethodsByName("innerField").get(0); final List<CtFieldAccess<?>> elements = innerInvMethod.getElements(new TypeFilter<>(CtFieldAccess.class)); assertEquals(6, elements.size()); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedInnerClass).target(expectedInnerClassAccess).result("this.i"), elements.get(0)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedInnerClass).target(expectedInnerClassAccess).result("i"), elements.get(1)); assertEquals(true, elements.get(1).getTarget().isImplicit()); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("this.i"), elements.get(2)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedType).target(fooTypeAccess).result("spoon.test.targeted.testclasses.Foo.k"), elements.get(3)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedSuperClassType).target(expectedThisAccess).result("this.o"), elements.get(4)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedSuperClassType).target(expectedThisAccess).result("o"), elements.get(5)); final List<CtFieldAccess<?>> newElements = nestedTypeScanner.getMethodsByName("checkField").get(0).getElements(new TypeFilter<>(CtFieldAccess.class)); assertEquals(2, newElements.size()); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedNested).target(expectedNestedAccess).result("this.type").isLocal(), newElements.get(0)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedNested).target(expectedNestedAccess).result("type").isLocal(), newElements.get(1)); } @Test public void testTargetsOfFieldInAnonymousClass() throws Exception { final Factory factory = build(Foo.class, Bar.class, SuperClass.class); final CtClass<Foo> type = factory.Class().get(Foo.class); final CtTypeReference<Foo> expectedType = type.getReference(); final CtClass<?> anonymousClass = type.getElements(new TypeFilter<CtClass>(CtClass.class) { @Override public boolean matches(CtClass element) { return element.isAnonymous() && super.matches(element); } }).get(0); final CtTypeReference<?> expectedAnonymousType = anonymousClass.getReference(); final CtThisAccess<Foo> expectedThisAccess = factory.Code().createThisAccess(expectedType); final CtThisAccess expectedAnonymousThisAccess = factory.Code().createThisAccess(expectedAnonymousType); final CtMethod<?> method = anonymousClass.getMethodsByName("invStatic").get(0); final List<CtFieldAccess> elements = method.getElements(new TypeFilter<>(CtFieldAccess.class)); assertEquals(3, elements.size()); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("this.i"), elements.get(0)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedAnonymousType).target(expectedAnonymousThisAccess).result("this.i"), elements.get(1)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedAnonymousType).target(expectedAnonymousThisAccess).result("i"), elements.get(2)); } @Test public void testStaticTargetsOfFieldAccessNoClasspath() throws Exception { final Launcher launcher = new Launcher(); launcher.getEnvironment().setNoClasspath(true); launcher.addInputResource("./src/test/resources/spoon/test/noclasspath/targeted/Foo.java"); launcher.setSourceOutputDirectory("./target/noclasspath"); launcher.run(); final CtTypeReference<Object> expectedFoo = launcher.getFactory().Class().createReference("Foo"); final CtTypeReference<Object> expectedBar = launcher.getFactory().Class().createReference("Bar"); final CtTypeReference<Object> expectedFiiFuu = launcher.getFactory().Class().create("Fii.Fuu").getReference(); final CtThisAccess<Object> expectedThisAccess = launcher.getFactory().Code().createThisAccess(expectedFoo); final CtTypeAccess<Object> expectedTypeAccess = launcher.getFactory().Code().createTypeAccess(expectedFoo); final CtTypeAccess<Object> expectedBarTypeAccess = launcher.getFactory().Code().createTypeAccess(expectedBar); final CtMethod<?> fieldMethod = launcher.getFactory().Class().get("Foo").getMethodsByName("field").get(0); final List<CtFieldAccess<?>> elements = fieldMethod.getElements(new TypeFilter<>(CtFieldAccess.class)); assertEquals(10, elements.size()); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedFoo).target(CtConstructorCallImpl.class).result("new Foo().i"), elements.get(0)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedFoo).target(elements.get(2)).result("foo.i"), elements.get(1)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedFoo).target(expectedThisAccess).result("foo"), elements.get(2)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedFoo).target(expectedThisAccess).result("this.i"), elements.get(3)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedFoo).target(expectedThisAccess).result("foo"), elements.get(4)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedFoo).target(expectedTypeAccess.toString()).result("Foo.staticField"), elements.get(5)); assertEqualsFieldAccess(new ExpectedTargetedExpression().result("staticField"), elements.get(6)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedBar).target(expectedBarTypeAccess).result("Bar.staticFieldBar"), elements.get(7)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedBar).target(expectedBarTypeAccess).result("Bar.staticFieldBar"), elements.get(8)); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedFiiFuu).target(launcher.getFactory().Code().createTypeAccess(expectedFiiFuu)).result("Fii.Fuu.i"), elements.get(9)); } @Test public void testTargetsOfInv() throws Exception { // contract: Specify declaring type of the executable of an invocation, the target of the invocation and its result. final Factory factory = build(Foo.class, Bar.class, SuperClass.class); final CtClass<Foo> type = factory.Class().get(Foo.class); final CtClass<Foo.Fii.Fuu> fuu = factory.Class().<Foo.Fii.Fuu>get(Foo.Fii.Fuu.class); final CtTypeReference<Foo> expectedType = type.getReference(); final CtTypeReference<Bar> expectedBarType = factory.Class().<Bar>get(Bar.class).getReference(); final CtTypeReference<SuperClass> expectedSuperClassType = factory.Class().<SuperClass>get(SuperClass.class).getReference(); final CtTypeReference<Foo.Fii.Fuu> expectedFuuType = fuu.getReference(); final CtThisAccess<Foo> expectedThisAccess = factory.Code().createThisAccess(expectedType); final CtTypeAccess<Foo> fooTypeAccess = factory.Code().createTypeAccess(expectedType); final CtTypeAccess<SuperClass> superClassTypeAccess = factory.Code().createTypeAccess(expectedSuperClassType); final CtThisAccess<Foo> expectedSuperThisAccess = factory.Code().createThisAccess(expectedType); expectedSuperThisAccess.setTarget(superClassTypeAccess); final List<CtInvocation<?>> elements = type.getMethodsByName("inv").get(0).getElements(new TypeFilter<CtInvocation<?>>(CtInvocation.class)); assertEquals(7, elements.size()); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(CtConstructorCallImpl.class).result("new spoon.test.targeted.testclasses.Foo(0, 0).method()"), elements.get(0)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(CtFieldReadImpl.class).result("foo.method()"), elements.get(1)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("this.method()"), elements.get(2)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("method()"), elements.get(3)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedBarType).target(CtFieldReadImpl.class).result("bar.methodBar()"), elements.get(4)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedFuuType).target(CtFieldReadImpl.class).result("fuu.method()"), elements.get(5)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedSuperClassType).target(expectedSuperThisAccess).result("superMethod()"), elements.get(6)); assertEquals(fooTypeAccess.getType().getQualifiedName(), ((CtThisAccess) elements.get(2).getTarget()).getTarget().getType().getQualifiedName()); assertEquals(fooTypeAccess.getType().getQualifiedName(), ((CtThisAccess) elements.get(3).getTarget()).getTarget().getType().getQualifiedName()); } @Test public void testStaticTargetsOfInv() throws Exception { // contract: Specify declaring type of the executable of an static invocation, the target of the static invocation and its result. final Factory factory = build(Foo.class, Bar.class, SuperClass.class); final CtClass<Foo> type = factory.Class().get(Foo.class); final CtClass<Foo.Fii.Fuu> fuu = factory.Class().<Foo.Fii.Fuu>get(Foo.Fii.Fuu.class); final CtTypeReference<Foo> expectedType = type.getReference(); final CtTypeReference<Bar> expectedBarType = factory.Class().<Bar>get(Bar.class).getReference(); final CtTypeReference<Foo.Fii.Fuu> expectedFuuType = fuu.getReference(); final CtThisAccess<Foo> expectedThisAccess = type.getFactory().Code().createThisAccess(expectedType); final CtTypeAccess<Foo> expectedTypeAccess = type.getFactory().Code().createTypeAccess(expectedType); final CtTypeAccess<Bar> expectedBarTypeAccess = type.getFactory().Code().createTypeAccess(expectedBarType); final CtMethod<?> invMethod = type.getMethodsByName("invStatic").get(0); final List<CtInvocation<?>> elements = invMethod.getElements(new TypeFilter<CtInvocation<?>>(CtInvocation.class)); assertEquals(8, elements.size()); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(CtConstructorCallImpl.class).result("new spoon.test.targeted.testclasses.Foo(0, 0).staticMethod()"), elements.get(0)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(CtFieldReadImpl.class).result("foo.staticMethod()"), elements.get(1)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("this.staticMethod()"), elements.get(2)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedTypeAccess).result("spoon.test.targeted.testclasses.Foo.staticMethod()"), elements.get(3)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedTypeAccess).result("spoon.test.targeted.testclasses.Foo.staticMethod()"), elements.get(4)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedBarType).target(expectedBarTypeAccess).result("spoon.test.targeted.testclasses.Bar.staticMethodBar()"), elements.get(5)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedBarType).target(expectedBarTypeAccess).result("spoon.test.targeted.testclasses.Bar.staticMethodBar()"), elements.get(6)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedFuuType).target(factory.Code().createTypeAccess(expectedFuuType)).result("spoon.test.targeted.testclasses.Foo.Fii.Fuu.m()"), elements.get(7)); } @Test public void testTargetsOfInvInInnerClass() throws Exception { // contract: Specify declaring type of the executable of an invocation, the target of the invocation and its result. All this in an innerclass. final Factory factory = build(Foo.class, Bar.class, SuperClass.class); final CtClass<Foo> type = factory.Class().get(Foo.class); final CtTypeReference<Foo> expectedType = type.getReference(); final CtTypeReference<SuperClass> expectedSuperClassType = factory.Class().<SuperClass>get(SuperClass.class).getReference(); final CtType<InnerClass> innerClass = type.getNestedType("InnerClass"); final CtTypeReference<InnerClass> expectedInnerClass = innerClass.getReference(); final CtType<?> nestedTypeScanner = type.getNestedType("1NestedTypeScanner"); final CtTypeReference<?> expectedNested = nestedTypeScanner.getReference(); final CtTypeAccess<Foo> fooTypeAccess = factory.Code().createTypeAccess(expectedType); final CtThisAccess expectedThisAccess = factory.Code().createThisAccess(expectedType); final CtThisAccess expectedSuperThisAccess = factory.Code().createThisAccess(expectedSuperClassType); final CtThisAccess<InnerClass> expectedInnerClassAccess = factory.Code().createThisAccess(expectedInnerClass); final CtThisAccess expectedNestedAccess = factory.Code().createThisAccess(expectedNested); final CtMethod<?> innerInvMethod = innerClass.getMethodsByName("innerInv").get(0); final List<CtInvocation<?>> elements = innerInvMethod.getElements(new TypeFilter<CtInvocation<?>>(CtInvocation.class)); assertEquals(8, elements.size()); expectedThisAccess.setType(expectedInnerClass); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("inv()"), elements.get(0)); expectedThisAccess.setType(expectedType); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("this.inv()"), elements.get(1)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(fooTypeAccess).result("spoon.test.targeted.testclasses.Foo.staticMethod()"), elements.get(2)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(fooTypeAccess).result("spoon.test.targeted.testclasses.Foo.staticMethod()"), elements.get(3)); expectedSuperThisAccess.setType(expectedInnerClass); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedSuperClassType).target(expectedSuperThisAccess).result("superMethod()"), elements.get(4)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedSuperClassType).target(expectedThisAccess).result("this.superMethod()"), elements.get(5)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedInnerClass).target(expectedInnerClassAccess).result("method()"), elements.get(6)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedInnerClass).target(expectedInnerClassAccess).result("this.method()"), elements.get(7)); final List<CtInvocation> newElements = nestedTypeScanner.getMethodsByName("checkType").get(0).getElements(new TypeFilter<>(CtInvocation.class)); assertEquals(1, newElements.size()); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedNested).target(expectedNestedAccess).result("this.checkType(type)"), newElements.get(0)); } @Test public void testTargetsOfInvInAnonymousClass() throws Exception { // contract: Specify declaring type of the executable of an invocation, the target of the invocation, and its result. All this in an anonymous class. final Factory factory = build(Foo.class, Bar.class, SuperClass.class); final CtClass<Foo> type = factory.Class().get(Foo.class); final CtTypeReference<Foo> expectedType = type.getReference(); final CtClass<?> anonymousClass = type.getElements(new TypeFilter<CtClass>(CtClass.class) { @Override public boolean matches(CtClass element) { return element.isAnonymous() && super.matches(element); } }).get(0); final CtTypeReference<?> expectedAnonymousType = anonymousClass.getReference(); final CtThisAccess<Foo> expectedThisAccess = factory.Code().createThisAccess(expectedType); final CtThisAccess expectedAnonymousThisAccess = factory.Code().createThisAccess(expectedAnonymousType); final CtMethod<?> method = anonymousClass.getMethodsByName("m").get(0); final List<CtInvocation> elements = method.getElements(new TypeFilter<>(CtInvocation.class)); assertEquals(2, elements.size()); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedType).target(expectedThisAccess).result("this.invStatic()"), elements.get(0)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(expectedAnonymousType).target(expectedAnonymousThisAccess).result("this.invStatic()"), elements.get(1)); } @Test public void testStaticTargetsOfInvNoClasspath() throws Exception { // contract: Specify declaring type of the executable of an invocation, the target of the invocation and its result. All this in no classpath mode. final Launcher launcher = new Launcher(); launcher.getEnvironment().setNoClasspath(true); launcher.addInputResource("./src/test/resources/spoon/test/noclasspath/targeted/Foo.java"); launcher.setSourceOutputDirectory("./target/noclasspath"); launcher.run(); final CtTypeReference<Object> foo = launcher.getFactory().Class().createReference("Foo"); final CtTypeReference<Object> bar = launcher.getFactory().Class().createReference("Bar"); final CtThisAccess<Object> expectedThisAccess = launcher.getFactory().Code().createThisAccess(foo); final CtTypeAccess<Object> expectedTypeAccess = launcher.getFactory().Code().createTypeAccess(foo); final CtTypeAccess<Object> expectedBarTypeAccess = launcher.getFactory().Code().createTypeAccess(bar); final CtTypeAccess<Object> fiiFuuTypeAccess = launcher.getFactory().Code().createTypeAccess(launcher.getFactory().Type().createReference("Fii.Fuu")); final CtMethod<?> invMethod = launcher.getFactory().Class().get("Foo").getMethodsByName("inv").get(0); final List<CtInvocation<?>> elements = invMethod.getElements(new TypeFilter<>(CtInvocation.class)); assertEquals(8, elements.size()); assertEqualsInvocation(new ExpectedTargetedExpression().target(CtConstructorCallImpl.class).result("new Foo(0, 0).staticMethod()"), elements.get(0)); assertEqualsInvocation(new ExpectedTargetedExpression().target(CtFieldReadImpl.class).result("foo.staticMethod()"), elements.get(1)); assertEqualsInvocation(new ExpectedTargetedExpression().target(expectedThisAccess).result("this.staticMethod()"), elements.get(2)); assertEqualsInvocation(new ExpectedTargetedExpression().target(expectedTypeAccess).result("Foo.staticMethod()"), elements.get(3)); assertEqualsInvocation(new ExpectedTargetedExpression().target(expectedThisAccess).result("staticMethod()"), elements.get(4)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(bar).target(expectedBarTypeAccess).result("Bar.staticMethodBar()"), elements.get(5)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(bar).target(expectedBarTypeAccess).result("Bar.staticMethodBar()"), elements.get(6)); assertEqualsInvocation(new ExpectedTargetedExpression().declaringType(launcher.getFactory().Class().create("Fii.Fuu").getReference()).target(fiiFuuTypeAccess).result("Fii.Fuu.m()"), elements.get(7)); } @Test public void testInitializeFieldAccessInNoclasspathMode() throws Exception { final Launcher launcher = new Launcher(); launcher.getEnvironment().setNoClasspath(true); launcher.addInputResource("./src/test/resources/spoon/test/noclasspath/targeted/Foo.java"); launcher.setSourceOutputDirectory("./target/noclasspath"); launcher.run(); final CtTypeReference<Object> expectedFoo = launcher.getFactory().Class().createReference("Foo"); final CtThisAccess<Object> expectedThisAccess = launcher.getFactory().Code().createThisAccess(expectedFoo); final List<CtFieldAccess<?>> elements = launcher.getFactory().Class().get("Foo").getConstructor().getElements(new TypeFilter<>(CtFieldAccess.class)); assertEquals(1, elements.size()); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(expectedFoo).target(expectedThisAccess).result("this.bar"), elements.get(0)); } @Test public void testClassDeclaredInALambda() throws Exception { // contract: A class can be declared in a lambda expression where we use final fields. final CtType<Tapas> type = buildClass(Tapas.class); final List<CtFieldAccess> elements = new SortedList(new CtLineElementComparator()); elements.addAll(type.getElements(new TypeFilter<>(CtFieldAccess.class))); assertEquals(3, elements.size()); final CtTypeReference<Object> firstExpected = type.getFactory().Type().createReference("spoon.test.targeted.testclasses.Tapas$1$InnerSubscriber"); CtThisAccess<Object> expectedThisAccess = type.getFactory().Code().createThisAccess(firstExpected); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(firstExpected).target(expectedThisAccess).type(CtFieldWrite.class).result("this.index"), elements.get(0)); final CtTypeReference<Object> secondExpectedInner = type.getFactory().Type().createReference("spoon.test.targeted.testclasses.Tapas$3InnerSubscriber"); expectedThisAccess = type.getFactory().Code().createThisAccess(secondExpectedInner); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(secondExpectedInner).target(expectedThisAccess).type(CtFieldWrite.class).result("this.index").isLocal(), elements.get(1)); final CtTypeReference<Object> thirdExpectedInner = type.getFactory().Type().createReference("spoon.test.targeted.testclasses.Tapas$4InnerSubscriber"); expectedThisAccess = type.getFactory().Code().createThisAccess(thirdExpectedInner); assertEqualsFieldAccess(new ExpectedTargetedExpression().declaringType(thirdExpectedInner).target(expectedThisAccess).type(CtFieldWrite.class).result("this.index").isLocal(), elements.get(2)); } private void assertEqualsFieldAccess(ExpectedTargetedExpression expected, CtFieldAccess<?> fieldAccess) { if (expected.declaringType == null) { assertNull(fieldAccess.getVariable().getDeclaringType()); } else { assertEquals(expected.isLocal, fieldAccess.getVariable().getDeclaringType().isLocalType()); assertEquals(expected.declaringType.getQualifiedName(), fieldAccess.getVariable().getDeclaringType().getQualifiedName()); } if (expected.targetClass != null) { assertEquals(expected.targetClass, fieldAccess.getTarget().getClass()); } else if (expected.targetString != null) { assertEquals(expected.targetString, fieldAccess.getTarget().toString()); } assertEquals(expected.result, fieldAccess.toString()); if (expected.type != null) { assertTrue(expected.type.isInstance(fieldAccess)); } } private void assertEqualsInvocation(ExpectedTargetedExpression expected, CtInvocation<?> invocation) { // two required parts: toString and declaringType (type containing the method to be called) assertEquals(expected.result, invocation.toString()); assertEquals(expected.declaringType, invocation.getExecutable().getDeclaringType()); // + two optional parts if (expected.targetClass != null) { assertEquals(expected.targetClass, invocation.getTarget().getClass()); } else if (expected.targetString != null) { assertEquals(expected.targetString, invocation.getTarget().toString()); } } private class ExpectedTargetedExpression { Class<? extends CtExpression> type; Class<? extends CtExpression> targetClass; String targetString; CtExpression<?> target; CtTypeReference<?> declaringType; String result; boolean isLocal = false; public ExpectedTargetedExpression type(Class<? extends CtExpression> type) { this.type = type; return this; } public ExpectedTargetedExpression target(Class<? extends CtExpression> target) { this.targetClass = target; return this; } public ExpectedTargetedExpression target(String target) { this.targetString = target; return this; } public ExpectedTargetedExpression target(CtExpression<?> target) { this.target = target; return this; } public ExpectedTargetedExpression declaringType(CtTypeReference<?> declaringType) { this.declaringType = declaringType; return this; } public ExpectedTargetedExpression result(String result) { this.result = result; return this; } public ExpectedTargetedExpression isLocal() { this.isLocal = true; return this; } } }