package spoon.test.reference;
import org.junit.Before;
import org.junit.Test;
import spoon.Launcher;
import spoon.SpoonModelBuilder;
import spoon.compiler.SpoonResourceHelper;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtConstructor;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtExecutableReference;
import spoon.reflect.visitor.Filter;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.AbstractReferenceFilter;
import spoon.reflect.visitor.filter.NameFilter;
import spoon.reflect.visitor.filter.ReferenceTypeFilter;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/**
* Created by gerard on 21/11/2014.
*/
public class ExecutableReferenceGenericTest {
private Factory factory;
public static final String NAME_MY_CLASS_1 = "MyClass";
@Before
public void setUp() throws Exception {
Launcher spoon = new Launcher();
factory = spoon.createFactory();
SpoonModelBuilder compiler = spoon.createCompiler(
factory,
SpoonResourceHelper.resources(
"./src/test/java/spoon/test/reference/MyClass.java",
"./src/test/java/spoon/test/reference/MyClass2.java",
"./src/test/java/spoon/test/reference/MyClass3.java"));
compiler.build();
}
@Test
public void testReferencesBetweenConstructors() throws Exception {
final List<CtConstructor<?>> constructors = getConstructorsByClass("MyClass");
CtConstructor<?> emptyConstructor = constructors.get(0);
CtConstructor<?> oneParamConstructor = constructors.get(1);
CtConstructor<?> twoParamsConstructor = constructors.get(2);
// Empty constructor which has a reference to the constructor with one parameter.
List<CtExecutableReference<?>> refConstructors = getCtConstructorsByCtConstructor(emptyConstructor);
assertEquals(1, refConstructors.size());
assertEquals(1, refConstructors.get(0).getDeclaration().getParameters().size());
assertEquals(oneParamConstructor, refConstructors.get(0).getDeclaration());
// Constructor with one parameter which has a reference to the constructor with two parameter.
refConstructors = getCtConstructorsByCtConstructor(oneParamConstructor);
assertEquals(1, refConstructors.size());
assertEquals(2, refConstructors.get(0).getDeclaration().getParameters().size());
assertEquals(twoParamsConstructor, refConstructors.get(0).getDeclaration());
}
@Test
public void testReferencesBetweenConstructorsInOtherClass() throws Exception {
final List<CtConstructor<?>> constructors = getConstructorsByClass("MyClass2");
final CtConstructor<?> ctConstructor = constructors.get(0);
final List<CtExecutableReference<?>> refConstructors = getCtConstructorsReferencedInCtConstructor(ctConstructor);
final CtClass<?> clazz1 = getCtClassByName("MyClass");
final CtConstructor<?> emptyConstructorClass1 = getConstructorsByClass(clazz1.getSimpleName()).get(0);
final CtClass<?> clazz3 = getCtClassByName("MyClass3");
final CtConstructor<?> emptyConstructorClass3 = getConstructorsByClass(clazz3.getSimpleName()).get(0);
assertEquals(3, refConstructors.size());
assertEquals(0, emptyConstructorClass1.getParameters().size());
assertEquals(0, emptyConstructorClass3.getParameters().size());
assertNull(refConstructors.get(0).getDeclaration()); // reference to Object constructor.
assertNotNull(refConstructors.get(0).getExecutableDeclaration());
assertEquals(emptyConstructorClass1, refConstructors.get(1).getDeclaration());
assertEquals(emptyConstructorClass3, refConstructors.get(2).getDeclaration());
}
@Test
public void testOneReferenceBetweenMethodsInSameClass() throws Exception {
final CtClass<?> clazz = getCtClassByName("MyClass");
CtMethod<?> method1 = getCtMethodByNameFromCtClass(clazz, "method1");
List<CtExecutableReference<?>> refsMethod1 = getReferencesOfAMethod(method1);
CtMethod<?> expected = getCtMethodByNameFromCtClass(clazz, "method2");
assertEquals(1, refsMethod1.size());
assertEquals(expected, refsMethod1.get(0).getDeclaration());
}
@Test
public void testMultiReferenceBetweenMethodsWithGenericInSameClass() throws Exception {
final CtClass<?> clazz = getCtClassByName("MyClass");
CtMethod<?> method2 = getCtMethodByNameFromCtClass(clazz, "method2");
List<CtExecutableReference<?>> refsMethod2 = getReferencesOfAMethod(method2);
CtMethod<?> expectedMethod1 = getCtMethodByNameFromCtClass(clazz, "method1");
CtMethod<?> expectedMethod5 = getCtMethodByNameFromCtClass(clazz, "method5");
assertEquals(3, refsMethod2.size());
assertEquals(expectedMethod1, refsMethod2.get(0).getDeclaration());
assertEquals(expectedMethod1, refsMethod2.get(1).getDeclaration());
assertEquals(expectedMethod5, refsMethod2.get(2).getDeclaration());
}
@Test
public void testMultiReferencesBetweenMethodsWithoutGenericInSameClass() throws Exception {
final CtClass<?> clazz = getCtClassByName("MyClass");
CtMethod<?> method3 = getCtMethodByNameFromCtClass(clazz, "method3");
List<CtExecutableReference<?>> refsMethod3 = getReferencesOfAMethod(method3);
CtMethod<?> expectedMethod2 = getCtMethodByNameFromCtClass(clazz, "method2");
CtMethod<?> expectedMethod4 = getCtMethodByNameFromCtClass(clazz, "method4");
assertEquals(2, refsMethod3.size());
assertEquals(expectedMethod2, refsMethod3.get(0).getDeclaration());
assertEquals(expectedMethod4, refsMethod3.get(1).getDeclaration());
}
@Test
public void testMethodWithoutReferences() throws Exception {
final CtClass<?> clazz = getCtClassByName("MyClass");
CtMethod<?> method4 = getCtMethodByNameFromCtClass(clazz, "method4");
List<CtExecutableReference<?>> refsMethod4 = getReferencesOfAMethod(method4);
assertEquals(0, refsMethod4.size());
}
@Test
public void testMethodGenericWithoutReferences() throws Exception {
final CtClass<?> clazz = getCtClassByName("MyClass");
CtMethod<?> method5 = getCtMethodByNameFromCtClass(clazz, "method5");
List<CtExecutableReference<?>> refsMethod5 = getReferencesOfAMethod(method5);
assertEquals(0, refsMethod5.size());
}
@Test
public void testOneReferenceWithGenericMethodOutOfTheClass() throws Exception {
final CtClass<?> clazz = getCtClassByName("MyClass");
final CtClass<?> clazz2 = getCtClassByName("MyClass2");
CtMethod<?> methodA = getCtMethodByNameFromCtClass(clazz2, "methodA");
List<CtExecutableReference<?>> refsMethodA = getReferencesOfAMethod(methodA);
CtMethod<?> expectedMethod1 = getCtMethodByNameFromCtClass(clazz, "method1");
assertEquals(1, refsMethodA.size());
assertEquals(expectedMethod1, refsMethodA.get(0).getDeclaration());
}
@Test
public void testOneReferenceWithMethodNotGenericOutOfTheClass() throws Exception {
final CtClass<?> clazz = getCtClassByName("MyClass");
final CtClass<?> clazz2 = getCtClassByName("MyClass2");
CtMethod<?> methodB = getCtMethodByNameFromCtClass(clazz2, "methodB");
List<CtExecutableReference<?>> refsMethodB = getReferencesOfAMethod(methodB);
CtMethod<?> expectedMethod2 = getCtMethodByNameFromCtClass(clazz, "method2");
assertEquals(1, refsMethodB.size());
assertEquals(expectedMethod2, refsMethodB.get(0).getDeclaration());
}
@Test
public void testMultiReferenceWithGenericMethodOutOfTheClass() throws Exception {
final CtClass<?> clazz2 = getCtClassByName("MyClass2");
final CtClass<?> clazz3 = getCtClassByName("MyClass3");
CtMethod<?> methodC = getCtMethodByNameFromCtClass(clazz2, "methodC");
List<CtExecutableReference<?>> refsMethodC = getReferencesOfAMethod(methodC);
CtMethod<?> expectedMethodI = getCtMethodByNameFromCtClass(clazz3, "methodI");
CtMethod<?> expectedMethodII = getCtMethodByNameFromCtClass(clazz3, "methodII");
assertEquals(2, refsMethodC.size());
assertEquals(expectedMethodI, refsMethodC.get(0).getDeclaration());
assertEquals(expectedMethodII, refsMethodC.get(1).getDeclaration());
}
@Test
public void testReferencesBetweenMethods() throws Exception {
final CtClass<?> clazz2 = getCtClassByName("MyClass2");
CtMethod<?> methodD = getCtMethodByNameFromCtClass(clazz2, "methodD");
// Method D references the method E.
List<CtExecutableReference<?>> refsMethodD = getReferencesOfAMethod(methodD);
CtMethod<?> expectedMethodE = getCtMethodByNameFromCtClass(clazz2, "methodE");
assertEquals(1, refsMethodD.size());
assertEquals(expectedMethodE, refsMethodD.get(0).getDeclaration());
// Method E references the method F.
List<CtExecutableReference<?>> refsMethodE = getReferencesOfAMethod(expectedMethodE);
CtMethod<?> expectedMethodF = getCtMethodByNameFromCtClass(clazz2, "methodF");
assertEquals(1, refsMethodE.size());
assertEquals(expectedMethodF, refsMethodE.get(0).getDeclaration());
}
@Test
public void testExecutableReferences() throws Exception {
// factory has loaded MyClass, MyClass2 and MyClass3
CtClass<?> classMyClass = Query.getElements(factory, new NameFilter<CtClass>("MyClass")).get(0);
assertEquals("MyClass", classMyClass.getSimpleName());
List<CtExecutableReference<?>> refsExecutableClass1 = Query.getElements(classMyClass,
new AbstractReferenceFilter<CtExecutableReference<?>>(CtExecutableReference.class) {
public boolean matches(CtExecutableReference<?> reference) {
return true;
}
});
CtClass<?> classMyClass2 = Query.getElements(factory, new NameFilter<CtClass>("MyClass2")).get(0);
assertEquals("MyClass2", classMyClass2.getSimpleName());
List<CtExecutableReference<?>> refsExecutableClass2 = Query.getElements(classMyClass2,
new AbstractReferenceFilter<CtExecutableReference<?>>(CtExecutableReference.class) {
public boolean matches(CtExecutableReference<?> reference) {
return true;
}
});
assertEquals(11, refsExecutableClass1.size());
for (CtExecutableReference<?> ref : refsExecutableClass1) {
assertNotNull(ref);
if (!ref.toString().equals("java.lang.Object#Object()")) {
assertNotNull(ref.getDeclaration());
}
}
assertEquals(9, refsExecutableClass2.size());
for (CtExecutableReference<?> ref : refsExecutableClass2) {
assertNotNull(ref);
if (!ref.toString().equals("java.lang.Object#Object()")) {
assertNotNull(ref.getDeclaration());
}
}
}
private List<CtConstructor<?>> getConstructorsByClass(final String myClass) {
return Query.getElements(factory, new Filter<CtConstructor<?>>() {
@Override
public boolean matches(CtConstructor<?> element) {
return myClass.equals(((CtClass<?>) element.getParent()).getSimpleName());
}
});
}
private List<CtExecutableReference<?>> getCtConstructorsByCtConstructor(CtConstructor<?> aConstructor) {
if (aConstructor.getBody().getStatements().size() == 0) {
return new ArrayList<>();
}
if (!(aConstructor.getBody().getStatement(0) instanceof CtInvocation)) {
return new ArrayList<>();
}
final CtInvocation inv = aConstructor.getBody().getStatement(0);
if (!inv.getExecutable().getSimpleName().equals(CtExecutableReference.CONSTRUCTOR_NAME)) {
return new ArrayList<>();
}
return inv.getExecutable().getElements(new AbstractReferenceFilter<CtExecutableReference<?>>(CtExecutableReference.class) {
@Override
public boolean matches(CtExecutableReference<?> reference) {
return reference.isConstructor();
}
});
}
private List<CtExecutableReference<?>> getCtConstructorsReferencedInCtConstructor(CtConstructor<?> aConstructor) {
return aConstructor.getElements(new AbstractReferenceFilter<CtExecutableReference<?>>(CtExecutableReference.class) {
@Override
public boolean matches(CtExecutableReference<?> reference) {
return reference.isConstructor();
}
});
}
private CtClass<?> getCtClassByName(final String name) {
return Query.getElements(factory, new Filter<CtClass<?>>() {
@Override
public boolean matches(CtClass<?> element) {
return name.equals(element.getSimpleName());
}
}).get(0);
}
private List<CtExecutableReference<?>> getReferencesOfAMethod(CtMethod<?> method1) {
return method1.getElements(new ReferenceTypeFilter<CtExecutableReference<?>>(CtExecutableReference.class));
}
private CtMethod<?> getCtMethodByNameFromCtClass(CtClass<?> clazz, String nameMethod5) {
return clazz.getMethodsByName(nameMethod5).get(0);
}
}