use of spoon.test.metamodel.MetamodelProperty in project spoon by INRIA.
the class ReplaceParametrizedTest method testContract.
@Test
public void testContract() throws Throwable {
List<String> problems = new ArrayList<>();
// contract: all elements are replaceable wherever they are in the model
// this test puts them at all possible locations
CtType<?> toTest = typeToTest.getModelInterface();
CtElement o = factory.Core().create((Class<? extends CtElement>) toTest.getActualClass());
for (MetamodelProperty mmField : typeToTest.getRoleToProperty().values()) {
Class<?> argType = mmField.getItemValueType().getActualClass();
if (!CtElement.class.isAssignableFrom(argType)) {
continue;
}
CtTypeReference<?> itemType = mmField.getItemValueType();
// special cases...
if (itemType.getQualifiedName().equals(CtStatement.class.getName())) {
// the children of CtLoop wraps CtStatement into an implicit CtBlock. So make a block directly to test plain get/set and not wrapping.
itemType = factory.createCtTypeReference(CtBlock.class);
}
if (o.getClass().getSimpleName().equals("CtAnnotationFieldAccessImpl") && mmField.getRole() == CtRole.VARIABLE) {
itemType = factory.createCtTypeReference(CtFieldReference.class);
} else if (CtFieldAccess.class.isAssignableFrom(o.getClass()) && mmField.getRole() == CtRole.VARIABLE) {
itemType = factory.createCtTypeReference(CtFieldReference.class);
}
CtElement argument = (CtElement) createCompatibleObject(itemType);
assertNotNull(argument);
// we create a fresh object
CtElement receiver = ((CtElement) o).clone();
RoleHandler rh = RoleHandlerHelper.getRoleHandler(o.getClass(), mmField.getRole());
if (mmField.isUnsettable()) {
try {
// we invoke the setter
invokeSetter(rh, receiver, argument);
} catch (SpoonException e) {
// ok this unsettable property has no setter at all
return;
}
// this unsettable property has setter, but it should do nothing
CtRole argumentsRoleInParent = argument.getRoleInParent();
if (argumentsRoleInParent == null) {
// OK - unsettable property set no value
continue;
}
if (argumentsRoleInParent == mmField.getRole()) {
problems.add("UnsettableProperty " + mmField + " sets the value");
} else {
if (mmField.isDerived()) {
// it is OK, that setting of value into derived unsettable field influences other field
// Example 1: CtCatchVariable.setType(x) influences result of getMultitype()
// Example 2: CtEnumValue.setAssignment(x) influences result of getDefaultExpression()
} else {
problems.add("UnsettableProperty " + mmField + " sets the value into different role " + argumentsRoleInParent);
}
}
continue;
}
// we invoke the setter
invokeSetter(rh, receiver, argument);
// contract: a property setter sets properties that are visitable by a scanner
CtElement finalArgument = argument;
class Scanner extends CtScanner {
boolean found = false;
@Override
public void scan(CtRole role, CtElement e) {
super.scan(role, e);
if (e == finalArgument) {
if (rh.getRole() == role || rh.getRole().getSuperRole() == role) {
found = true;
return;
}
// if (rh.getRole()==CtRole.TYPE && role==CtRole.MULTI_TYPE) {
// //CtCatchVaraible#type sets CtCatchVaraible#multiType - OK
// found = true;
// return;
// }
problems.add("Argument was set into " + rh.getRole() + " but was found in " + role);
}
}
}
;
Scanner s = new Scanner();
receiver.accept(s);
assertTrue("Settable field " + mmField.toString() + " should set value.\n" + getReport(problems), s.found);
// contract: a property getter on the same role can be used to get the value back
assertSame(argument, invokeGetter(rh, receiver));
final CtElement argument2 = argument.clone();
assertNotSame(argument, argument2);
// we do the replace
argument.replace(argument2);
// the new element is indeed now in this AST
assertTrue(receiver.getClass().getSimpleName() + " failed for " + mmField, receiver.getElements(new Filter<CtElement>() {
@Override
public boolean matches(CtElement element) {
return element == argument2;
}
}).size() == 1);
}
if (problems.size() > 0) {
fail(getReport(problems));
}
}
use of spoon.test.metamodel.MetamodelProperty in project spoon by INRIA.
the class RoleHandlersGenerator method process.
@Override
public void process() {
SpoonMetaModel metaModel = new SpoonMetaModel(getFactory());
// all root super MMFields
List<MetamodelProperty> superFields = new ArrayList<>();
metaModel.getConcepts().forEach(mmConcept -> {
mmConcept.getRoleToProperty().forEach((role, rim) -> {
addUniqueObject(superFields, rim.getRootSuperField());
});
});
superFields.sort((a, b) -> {
int d = a.getRole().name().compareTo(b.getRole().name());
if (d != 0) {
return d;
}
return a.getOwnerConcept().getName().compareTo(b.getOwnerConcept().getName());
});
PrinterHelper concept = new PrinterHelper(getFactory().getEnvironment());
superFields.forEach(mmField -> {
concept.write(mmField.getOwnerConcept().getName() + " CtRole." + mmField.getRole().name()).writeln().incTab().write("ItemType: ").write(mmField.getValueType().toString()).writeln();
for (MMMethodKind mk : MMMethodKind.values()) {
MMMethod mmMethod = mmField.getMethod(mk);
if (mmMethod != null) {
concept.write(mk.name()).write(": ").write(mmMethod.getSignature()).write(" : ").write(mmMethod.getReturnType().toString()).writeln();
}
}
concept.decTab();
concept.write("----------------------------------------------------------").writeln();
});
try (Writer w = new OutputStreamWriter(new FileOutputStream(file("target/report/concept.txt")))) {
w.write(concept.toString());
} catch (IOException e) {
throw new RuntimeException(e);
}
CtType<?> template = getTemplate("spoon.generating.meta.ModelRoleHandlerTemplate");
CtClass<?> modelRoleHandlersClass = Substitution.createTypeFromTemplate(TARGET_PACKAGE + ".ModelRoleHandlers", template, new HashMap<>());
CtNewArray<?> roleHandlersFieldExpr = (CtNewArray<?>) modelRoleHandlersClass.getField("roleHandlers").getDefaultExpression();
superFields.forEach(rim -> {
Map<String, Object> params = new HashMap<>();
params.put("$getterName$", rim.getMethod(MMMethodKind.GET).getName());
if (rim.getMethod(MMMethodKind.SET) != null) {
params.put("$setterName$", rim.getMethod(MMMethodKind.SET).getName());
}
params.put("$Role$", getFactory().Type().createReference(CtRole.class));
params.put("ROLE", rim.getRole().name());
params.put("$TargetType$", rim.getOwnerConcept().getModelInterface().getReference());
// params.put("AbstractHandler", getFactory().Type().createReference("spoon.reflect.meta.impl.AbstractRoleHandler"));
params.put("AbstractHandler", getRoleHandlerSuperTypeQName(rim));
params.put("Node", rim.getOwnerConcept().getModelInterface().getReference());
params.put("ValueType", fixMainValueType(getRoleHandlerSuperTypeQName(rim).endsWith("SingleHandler") ? rim.getValueType() : rim.getItemValueType()));
CtClass<?> modelRoleHandlerClass = Substitution.createTypeFromTemplate(getHandlerName(rim), getTemplate("spoon.generating.meta.RoleHandlerTemplate"), params);
if (rim.getMethod(MMMethodKind.SET) == null) {
modelRoleHandlerClass.getMethodsByName("setValue").forEach(m -> m.delete());
}
modelRoleHandlerClass.addModifier(ModifierKind.STATIC);
modelRoleHandlersClass.addNestedType(modelRoleHandlerClass);
roleHandlersFieldExpr.addElement(getFactory().createCodeSnippetExpression("new " + modelRoleHandlerClass.getSimpleName() + "()"));
});
}
Aggregations