use of spoon.reflect.declaration.CtType in project spoon by INRIA.
the class APITest method testSetterInNodes.
@Test
public void testSetterInNodes() throws Exception {
// that the new value is != null to avoid NPE when we set the parent.
class SetterMethodWithoutCollectionsFilter extends TypeFilter<CtMethod<?>> {
private final List<CtTypeReference<?>> collections = new ArrayList<>(4);
public SetterMethodWithoutCollectionsFilter(Factory factory) {
super(CtMethod.class);
for (Class<?> aCollectionClass : Arrays.asList(Collection.class, List.class, Map.class, Set.class)) {
collections.add(factory.Type().createReference(aCollectionClass));
}
}
@Override
public boolean matches(CtMethod<?> element) {
boolean isSetter = isSetterMethod(element);
boolean isNotSubType = !isSubTypeOfCollection(element);
// setter with unsettableProperty should not respect the contract, as well as derived properties
boolean doesNotHaveUnsettableAnnotation = doesNotHaveUnsettableAnnotation(element);
boolean isNotSetterForADerivedProperty = isNotSetterForADerivedProperty(element);
boolean superMatch = super.matches(element);
return isSetter && doesNotHaveUnsettableAnnotation && isNotSetterForADerivedProperty && isNotSubType && superMatch;
}
private boolean isNotSetterForADerivedProperty(CtMethod<?> method) {
String methodName = method.getSimpleName();
String getterName = methodName.replace("set", "get");
if (getterName.equals(methodName)) {
return false;
}
CtType<?> zeClass = (CtType) method.getParent();
List<CtMethod<?>> getterMethods = zeClass.getMethodsByName(getterName);
if (getterMethods.size() != 1) {
return false;
}
CtMethod<?> getterMethod = getterMethods.get(0);
return (getterMethod.getAnnotation(DerivedProperty.class) == null);
}
private boolean doesNotHaveUnsettableAnnotation(CtMethod<?> element) {
return (element.getAnnotation(UnsettableProperty.class) == null);
}
private boolean isSubTypeOfCollection(CtMethod<?> element) {
final List<CtParameter<?>> parameters = element.getParameters();
if (parameters.size() != 1) {
return false;
}
final CtTypeReference<?> type = parameters.get(0).getType();
for (CtTypeReference<?> aCollectionRef : collections) {
if (type.isSubtypeOf(aCollectionRef) || type.equals(aCollectionRef)) {
return true;
}
}
return false;
}
private boolean isSetterMethod(CtMethod<?> element) {
final List<CtParameter<?>> parameters = element.getParameters();
if (parameters.size() != 1) {
return false;
}
final CtTypeReference<?> typeParameter = parameters.get(0).getType();
final CtTypeReference<CtElement> ctElementRef = element.getFactory().Type().createReference(CtElement.class);
// isSubtypeOf will return true in case of equality
boolean isSubtypeof = typeParameter.isSubtypeOf(ctElementRef);
if (!isSubtypeof) {
return false;
}
return element.getSimpleName().startsWith("set") && element.getDeclaringType().getSimpleName().startsWith("Ct") && element.getBody() != null;
}
}
class CheckNotNullToSetParentMatcher extends CtElementImpl {
public TemplateParameter<CtVariableAccess<?>> _parameter_access_;
public void matcher() {
if (_parameter_access_.S() != null) {
_parameter_access_.S().setParent(this);
}
}
@Override
@Local
public void accept(CtVisitor visitor) {
}
}
final Launcher launcher = new Launcher();
launcher.setArgs(new String[] { "--output-type", "nooutput" });
launcher.getEnvironment().setNoClasspath(true);
// Implementations
launcher.addInputResource("./src/main/java/spoon/support/reflect/code");
launcher.addInputResource("./src/main/java/spoon/support/reflect/declaration");
launcher.addInputResource("./src/main/java/spoon/support/reflect/reference");
launcher.addInputResource("./src/test/java/" + this.getClass().getCanonicalName().replace(".", "/") + ".java");
// Needed for #isSubTypeOf method.
launcher.addInputResource("./src/main/java/spoon/reflect/");
launcher.buildModel();
// Template matcher.
CtClass<CheckNotNullToSetParentMatcher> matcherCtClass = launcher.getFactory().Class().get(CheckNotNullToSetParentMatcher.class);
CtIf templateRoot = matcherCtClass.getMethod("matcher").getBody().getStatement(0);
final List<CtMethod<?>> setters = Query.getElements(launcher.getFactory(), new SetterMethodWithoutCollectionsFilter(launcher.getFactory()));
assertTrue("Number of setters found null", setters.size() > 0);
for (CtStatement statement : setters.stream().map((Function<CtMethod<?>, CtStatement>) ctMethod -> ctMethod.getBody().getStatement(0)).collect(Collectors.toList())) {
// First statement should be a condition to protect the setter of the parent.
assertTrue("Check the method " + statement.getParent(CtMethod.class).getSignature() + " in the declaring class " + statement.getParent(CtType.class).getQualifiedName(), statement instanceof CtIf);
CtIf ifCondition = (CtIf) statement;
TemplateMatcher matcher = new TemplateMatcher(templateRoot);
assertEquals("Check the number of if in method " + statement.getParent(CtMethod.class).getSignature() + " in the declaring class " + statement.getParent(CtType.class).getQualifiedName(), 1, matcher.find(ifCondition).size());
}
}
use of spoon.reflect.declaration.CtType in project spoon by INRIA.
the class MetamodelTest method testRoleOnField.
@Test
public void testRoleOnField() {
// contract: all non-final fields must be annotated with {@link spoon.reflect.annotations.MetamodelPropertyField}
SpoonAPI implementations = new Launcher();
implementations.addInputResource("src/main/java/spoon/support/reflect");
implementations.buildModel();
Factory factory = implementations.getFactory();
CtTypeReference metamodelPropertyField = factory.Type().get(MetamodelPropertyField.class).getReference();
final List<String> result = new ArrayList();
List<CtField> fieldWithoutAnnotation = (List<CtField>) implementations.getModel().getElements(new TypeFilter<CtField>(CtField.class) {
@Override
public boolean matches(CtField candidate) {
if (candidate.hasModifier(ModifierKind.FINAL) || candidate.hasModifier(ModifierKind.STATIC) || candidate.hasModifier(ModifierKind.TRANSIENT)) {
return false;
}
if (// not a role
"parent".equals(candidate.getSimpleName()) || "metadata".equals(candidate.getSimpleName()) || // cache field
"valueOfMethod".equals(candidate.getSimpleName())) {
return false;
}
CtClass parent = candidate.getParent(CtClass.class);
return parent != null && (parent.isSubtypeOf(candidate.getFactory().createCtTypeReference(CtReference.class)) || parent.isSubtypeOf(candidate.getFactory().createCtTypeReference(CtElement.class)));
}
}).stream().map(x -> {
result.add(x.toString());
return x;
}).filter(f -> f.getAnnotation(metamodelPropertyField) == null).collect(Collectors.toList());
assertTrue(result.contains("@spoon.reflect.annotations.MetamodelPropertyField(role = spoon.reflect.path.CtRole.IS_SHADOW)\nboolean isShadow;"));
assertTrue(result.contains("@spoon.reflect.annotations.MetamodelPropertyField(role = spoon.reflect.path.CtRole.TYPE)\nspoon.reflect.reference.CtTypeReference<T> type;"));
assertTrue(result.size() > 100);
Assert.assertEquals(Collections.emptyList(), fieldWithoutAnnotation);
final CtTypeReference propertySetter = factory.Type().get(PropertySetter.class).getReference();
final CtTypeReference propertyGetter = factory.Type().get(PropertyGetter.class).getReference();
List<CtField> fields = factory.getModel().getElements(new AnnotationFilter<CtField>(MetamodelPropertyField.class));
for (CtField field : fields) {
CtClass parent = field.getParent(CtClass.class);
CtExpression roleExpression = field.getAnnotation(metamodelPropertyField).getValue("role");
List<String> roles = new ArrayList<>();
if (roleExpression instanceof CtFieldRead) {
roles.add(((CtFieldRead) roleExpression).getVariable().getSimpleName());
} else if (roleExpression instanceof CtNewArray) {
List<CtFieldRead> elements = ((CtNewArray) roleExpression).getElements();
for (int i = 0; i < elements.size(); i++) {
CtFieldRead ctFieldRead = elements.get(i);
roles.add(ctFieldRead.getVariable().getSimpleName());
}
}
CtQuery superQuery = parent.map(new SuperInheritanceHierarchyFunction());
List<CtMethod> methods = superQuery.map((CtType type) -> type.getMethodsAnnotatedWith(propertyGetter, propertySetter)).list();
boolean setterFound = false;
boolean getterFound = false;
for (CtMethod method : methods) {
CtAnnotation getterAnnotation = method.getAnnotation(propertyGetter);
CtAnnotation setterAnnotation = method.getAnnotation(propertySetter);
if (getterAnnotation != null) {
getterFound |= roles.contains(((CtFieldRead) getterAnnotation.getValue("role")).getVariable().getSimpleName());
}
if (setterAnnotation != null) {
setterFound |= roles.contains(((CtFieldRead) setterAnnotation.getValue("role")).getVariable().getSimpleName());
}
}
assertTrue(roles + " must have a getter in " + parent.getQualifiedName(), getterFound);
assertTrue(roles + " must have a setter in " + parent.getQualifiedName(), setterFound);
}
}
use of spoon.reflect.declaration.CtType in project spoon by INRIA.
the class NoClasspathTest method testInheritanceInNoClassPathWithClasses.
@Test
public void testInheritanceInNoClassPathWithClasses() throws IOException {
// contract: when using noclasspath in combination with a source classpath
// spoon is able to resolve the inheritance between classes contained in source cp
String sourceInputDirPath = "./src/test/resources/spoon/test/inheritance";
String targetBinPath = "./target/spoon-nocp-bin";
Launcher spoon = new Launcher();
spoon.getEnvironment().setShouldCompile(true);
spoon.addInputResource(sourceInputDirPath);
spoon.setBinaryOutputDirectory(targetBinPath);
spoon.run();
spoon = new Launcher();
spoon.getEnvironment().setNoClasspath(true);
spoon.getEnvironment().setSourceClasspath(new String[] { targetBinPath });
spoon.addInputResource(sourceInputDirPath + "/AnotherClass.java");
spoon.buildModel();
CtType anotherclass = spoon.getFactory().Type().get("org.acme.AnotherClass");
assertEquals(1, anotherclass.getFields().size());
CtField field = (CtField) anotherclass.getFields().get(0);
CtTypeReference myClassReference = spoon.getFactory().Type().createReference("fr.acme.MyClass");
assertEquals(myClassReference, field.getType());
assertNotNull(myClassReference.getActualClass());
CtTypeReference myInterfaceReference = spoon.getFactory().Type().createReference("org.myorganization.MyInterface");
assertTrue(myClassReference.isSubtypeOf(myInterfaceReference));
assertTrue(field.getType().isSubtypeOf(myInterfaceReference));
}
use of spoon.reflect.declaration.CtType in project spoon by INRIA.
the class SpoonArchitectureEnforcerTest method testFactorySubFactory.
@Test
public void testFactorySubFactory() throws Exception {
// contract:: all subfactory methods must also be in the main factory
// this is very important for usability and discoverability
final Launcher launcher = new Launcher();
launcher.addInputResource("./src/main/java/spoon/reflect/factory");
class SanityCheck {
int val = 0;
}
;
SanityCheck sanityCheck = new SanityCheck();
launcher.addProcessor(new AbstractManualProcessor() {
@Override
public void process() {
CtType factoryImpl = getFactory().Interface().get(Factory.class);
CtPackage factoryPackage = getFactory().Package().getOrCreate("spoon.reflect.factory");
CtInterface itf = getFactory().Interface().create("MegaFactoryItf");
CtClass impl = getFactory().Class().create("MegaFactory");
for (CtType<?> t : factoryPackage.getTypes()) {
//
if (t.getSimpleName().startsWith("Mega"))
continue;
for (CtMethod<?> m : t.getMethods()) {
// we check only public methods
if (m.hasModifier(ModifierKind.PUBLIC) == false)
continue;
// we only consider factory methods
if (!m.getSimpleName().startsWith("create"))
continue;
// too generic, what should we create??
if (m.getSimpleName().equals("create")) {
String simpleNameType = m.getType().getSimpleName().replace("Ct", "");
CtMethod method = m.clone();
method.setSimpleName("create" + simpleNameType);
assertTrue(method.getSignature() + " (from " + t.getQualifiedName() + ") is not present in the main factory", factoryImpl.hasMethod(method));
continue;
}
// too generic, is it a fieldref? an execref? etc
if (m.getSimpleName().equals("createReference"))
continue;
if (m.getModifiers().contains(ModifierKind.ABSTRACT))
continue;
sanityCheck.val++;
// the core assertion
assertTrue(m.getSignature() + " is not present in the main factory", factoryImpl.hasMethod(m));
}
}
}
});
launcher.run();
assertTrue(sanityCheck.val > 100);
}
use of spoon.reflect.declaration.CtType in project spoon by INRIA.
the class SpoonTestHelpers method getSetterOf.
/**
* returns the corresponding setter, if several are possible returns the lowest one in the hierarchy
*/
public static CtMethod<?> getSetterOf(CtType<?> baseType, CtMethod<?> getter) {
String setterName = getter.getSimpleName().replaceFirst("^get", "set");
Object[] tentativeSetters = baseType.getAllMethods().stream().filter(x -> x.getSimpleName().equals(setterName)).toArray();
if (tentativeSetters.length == 0) {
return null;
}
// return one that is as low as possible in the hierarchy
for (Object o : tentativeSetters) {
if (baseType.getPackage().getElements(new OverridingMethodFilter((CtMethod<?>) o)).size() == 0) {
return (CtMethod<?>) o;
}
}
// System.out.println(setterName+" "+tentativeSetters.length);
return (CtMethod<?>) tentativeSetters[0];
}
Aggregations