use of spoon.reflect.path.CtRole in project spoon by INRIA.
the class SpoonMetaModel method addFieldsOfType.
/**
* adds all {@link MetamodelProperty}s of `ctType`
* @param mmConcept the owner of to be created fields
* @param ctType to be scanned {@link CtType}
*/
private void addFieldsOfType(MetamodelConcept mmConcept, CtType<?> ctType) {
ctType.getTypeMembers().forEach(typeMember -> {
if (typeMember instanceof CtMethod<?>) {
CtMethod<?> method = (CtMethod<?>) typeMember;
CtRole role = getRoleOfMethod(method);
if (role != null) {
MetamodelProperty field = mmConcept.getOrCreateMMField(role);
field.addMethod(method);
} else {
mmConcept.otherMethods.add(method);
}
}
});
addFieldsOfSuperType(mmConcept, ctType.getSuperclass());
ctType.getSuperInterfaces().forEach(superIfaceRef -> addFieldsOfSuperType(mmConcept, superIfaceRef));
}
use of spoon.reflect.path.CtRole 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.reflect.path.CtRole in project spoon by INRIA.
the class TestCtRole method testGetCtRoleByName.
@Test
public void testGetCtRoleByName() {
// contract: one should be able to get CtRole based on its name (without '_' whatever the case is, or with '_' in uppercase)
// exactly the same name: OK
String name = "DECLARING_TYPE";
assertEquals(CtRole.DECLARING_TYPE, CtRole.fromName(name));
// camel case: OK
name = "declaringType";
assertEquals(CtRole.DECLARING_TYPE, CtRole.fromName(name));
// lower case: OK
name = "declaringtype";
assertEquals(CtRole.DECLARING_TYPE, CtRole.fromName(name));
// lower case with underscore: not accepted
name = "declaring_type";
assertNull(CtRole.fromName(name));
for (CtRole role : CtRole.values()) {
assertEquals(role, CtRole.fromName(role.name().replaceAll("_", "").toLowerCase()));
}
}
use of spoon.reflect.path.CtRole in project spoon by INRIA.
the class TestCtRole method testCtRoleSubRoleMatchesWithSuperRole.
@Test
public void testCtRoleSubRoleMatchesWithSuperRole() {
// contract: CtRole#getSubRoles() and CtRole#getSuperRole() are empty or links to each other
int countOfSubRoles = 0;
for (CtRole role : CtRole.values()) {
for (CtRole subRole : role.getSubRoles()) {
countOfSubRoles++;
assertSame(role, subRole.getSuperRole());
}
if (role.getSuperRole() != null) {
assertTrue(role.getSuperRole().getSubRoles().contains(role));
}
}
assertTrue(countOfSubRoles > 0);
}
use of spoon.reflect.path.CtRole in project spoon by INRIA.
the class MetaModelTest method spoonMetaModelTest.
/*
* this test reports all spoon model elements which are not yet handled by meta model
* actually this is the result
*/
@Test
public void spoonMetaModelTest() {
SpoonMetaModel mm = new SpoonMetaModel(new File("./src/main/java"));
List<String> problems = new ArrayList<>();
// detect unused CtRoles
Set<CtRole> unhandledRoles = new HashSet<>(Arrays.asList(CtRole.values()));
mm.getConcepts().forEach(mmConcept -> {
mmConcept.getRoleToProperty().forEach((role, mmField) -> {
if (mmField.isUnsettable()) {
// contract: all unsettable fields are derived too
assertTrue("Unsettable field " + mmField + " must be derived too", mmField.isDerived());
}
unhandledRoles.remove(role);
if (mmField.getMethod(MMMethodKind.GET) == null) {
problems.add("Missing getter for " + mmField.getOwnerConcept().getName() + " and CtRole." + mmField.getRole());
}
if (mmField.getMethod(MMMethodKind.SET) == null) {
if (mmConcept.getTypeContext().isSubtypeOf(mm.getFactory().Type().createReference(CtReference.class)) == false && mmConcept.getName().equals("CtTypeInformation") == false) {
// only NON references needs a setter
problems.add("Missing setter for " + mmField.getOwnerConcept().getName() + " and CtRole." + mmField.getRole());
}
}
// contract: type of field value is never implicit
assertFalse("Value type of Field " + mmField.toString() + " is implicit", mmField.getValueType().isImplicit());
assertFalse("Item value type of Field " + mmField.toString() + " is implicit", mmField.getItemValueType().isImplicit());
mmField.forEachUnhandledMethod(ctMethod -> problems.add("Unhandled method signature: " + ctMethod.getDeclaringType().getSimpleName() + "#" + ctMethod.getSignature()));
});
});
unhandledRoles.forEach(it -> problems.add("Unused CtRole." + it.name()));
/*
* This assertion prints all the methods which are not covered by current implementation of SpoonMetaModel.
* It is not a bug. It is useful to see how much is SpoonMetaModel covering real Spoon model.
*/
// assertTrue(String.join("\n", problems), problems.isEmpty());
}
Aggregations