use of spoon.reflect.visitor.Filter in project spoon by INRIA.
the class FilterTest method testFilterChildrenWithoutFilterQueryStep.
@Test
public void testFilterChildrenWithoutFilterQueryStep() throws Exception {
final Launcher launcher = new Launcher();
launcher.setArgs(new String[] { "--output-type", "nooutput", "--level", "info" });
launcher.addInputResource("./src/test/java/spoon/test/filters/testclasses");
launcher.run();
// Contract: the filterChildren(null) without Filter returns same results like filter which returns true for each input.
List<CtElement> list = launcher.getFactory().Package().getRootPackage().filterChildren(null).list();
Iterator<CtElement> iter = list.iterator();
launcher.getFactory().Package().getRootPackage().filterChildren(e -> {
return true;
}).forEach(real -> {
// the elements produced by each query are same
CtElement expected = iter.next();
if (real != expected) {
assertEquals(expected, real);
}
});
assertTrue(list.size() > 0);
assertTrue(iter.hasNext() == false);
}
use of spoon.reflect.visitor.Filter in project spoon by INRIA.
the class FilterTest method testEarlyTerminatingQuery.
@Test
public void testEarlyTerminatingQuery() throws Exception {
// contract: a method first evaluates query until first element is found and then terminates the query
final Launcher launcher = new Launcher();
launcher.setArgs(new String[] { "--output-type", "nooutput", "--level", "info" });
launcher.addInputResource("./src/test/java/spoon/test/filters/testclasses");
launcher.run();
class Context {
boolean wasTerminated = false;
void failIfTerminated(String place) {
assertTrue("The " + place + " is called after query was terminated.", wasTerminated == false);
}
}
Context context = new Context();
CtMethod firstMethod = launcher.getFactory().Package().getRootPackage().filterChildren(e -> {
context.failIfTerminated("Filter#match of filterChildren");
return true;
}).map((CtElement e) -> {
context.failIfTerminated("Array returning CtFunction#apply of map");
// send result twice to check that second item is skipped
return new CtElement[] { e, e };
}).map((CtElement e) -> {
context.failIfTerminated("List returning CtFunction#apply of map");
// send result twice to check that second item is skipped
return Arrays.asList(new CtElement[] { e, e });
}).map((CtElement e, CtConsumer<Object> out) -> {
context.failIfTerminated("CtConsumableFunction#apply of map");
if (e instanceof CtMethod) {
// this call should pass and cause termination of the query
out.accept(e);
context.wasTerminated = true;
// let it call out.accept(e); once more to check that next step is not called after query is terminated
}
out.accept(e);
}).map(e -> {
context.failIfTerminated("CtFunction#apply of map after CtConsumableFunction");
return e;
}).first(CtMethod.class);
assertTrue(firstMethod != null);
assertTrue(context.wasTerminated);
}
use of spoon.reflect.visitor.Filter in project spoon by INRIA.
the class CtRenameLocalVariableRefactoring method detectNameConflicts.
@Override
protected void detectNameConflicts() {
/*
* There can be these conflicts
* 1) target variable would shadow before declared variable (parameter, localVariable, catchVariable)
* --------------------------------------------------------------------------------------------------
*/
PotentialVariableDeclarationFunction potentialDeclarationFnc = new PotentialVariableDeclarationFunction(newName);
CtVariable<?> var = getTarget().map(potentialDeclarationFnc).first();
if (var != null) {
if (var instanceof CtField) {
/*
* we have found a field of same name.
* It is not problem, because variables can hide field declaration.
* Do nothing - OK
*/
} else if (potentialDeclarationFnc.isTypeOnTheWay()) {
/*
* There is a local class declaration between future variable reference and variable declaration `var`.
* The found variable declaration `var` can be hidden by target variable with newName
* as long as there is no reference to `var` in visibility scope of the target variable.
* So search for such `var` reference now
*/
CtVariableReference<?> shadowedVar = target.map(new SiblingsFunction().includingSelf(true).mode(Mode.NEXT)).map(new VariableReferenceFunction(var)).first();
if (shadowedVar != null) {
// found variable reference, which would be shadowed by variable after rename.
createNameConflictIssue(var, shadowedVar);
} else {
/*
* there is no local variable reference, which would be shadowed by variable after rename.
* OK
*/
}
} else {
/*
* the found variable is in conflict with target variable with newName
*/
createNameConflictIssue(var);
}
}
/*
* 2) target variable is shadowed by later declared variable
* ---------------------------------------------------------
*/
final QueryDriver queryDriver = new QueryDriver();
getTarget().map(new LocalVariableScopeFunction(queryDriver)).select(new Filter<CtElement>() {
/**
* return true for all CtVariables, which are in conflict
*/
@Override
public boolean matches(CtElement element) {
if (element instanceof CtType<?>) {
CtType<?> localClass = (CtType<?>) element;
// TODO use faster hasField, implemented using map(new AllFieldsFunction()).select(new NameFilter(newName)).first()!=null
Collection<CtFieldReference<?>> fields = localClass.getAllFields();
for (CtFieldReference<?> fieldRef : fields) {
if (newName.equals(fieldRef.getSimpleName())) {
/*
* we have found a local class field, which will shadow input local variable if it's reference is in visibility scope of that field.
* Search for target variable reference in visibility scope of this field.
* If found than we cannot rename target variable to newName, because that reference would be shadowed
*/
queryDriver.ignoreChildrenOf(element);
CtLocalVariableReference<?> shadowedVar = element.map(new LocalVariableReferenceFunction(target)).first();
if (shadowedVar != null) {
createNameConflictIssue(fieldRef.getFieldDeclaration(), shadowedVar);
return true;
}
return false;
}
}
return false;
}
if (element instanceof CtVariable<?>) {
CtVariable<?> variable = (CtVariable<?>) element;
if (newName.equals(variable.getSimpleName()) == false) {
// the variable with different name. Ignore it
return false;
}
// we have found a variable with new name
if (variable instanceof CtField) {
throw new SpoonException("This should not happen. The children of local class which contains a field with new name should be skipped!");
}
if (variable instanceof CtCatchVariable || variable instanceof CtLocalVariable || variable instanceof CtParameter) {
/*
* we have found a catch variable or local variable or parameter with new name.
*/
if (queryDriver.isInContextOfLocalClass()) {
/*
* We are in context of local class.
* This variable would shadow input local variable after rename
* so we cannot rename if there exist a local variable reference in variable visibility scope.
*/
queryDriver.ignoreChildrenOf(variable.getParent());
CtQueryable searchScope;
if (variable instanceof CtLocalVariable) {
searchScope = variable.map(new SiblingsFunction().includingSelf(true).mode(Mode.NEXT));
} else {
searchScope = variable.getParent();
}
CtLocalVariableReference<?> shadowedVar = searchScope.map(new LocalVariableReferenceFunction(target)).first();
if (shadowedVar != null) {
// found local variable reference, which would be shadowed by variable after rename.
createNameConflictIssue(variable, shadowedVar);
return true;
}
// there is no local variable reference, which would be shadowed by variable after rename.
return false;
} else {
/*
* We are not in context of local class.
* So this variable is in conflict. Return it
*/
createNameConflictIssue(variable);
return true;
}
} else {
// Any new variable type???
throw new SpoonException("Unexpected variable " + variable.getClass().getName());
}
}
return false;
}
}).first();
}
use of spoon.reflect.visitor.Filter 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.visitor.Filter in project spoon by INRIA.
the class SerializationModelStreamer method load.
public Factory load(InputStream in) throws IOException {
try {
ObjectInputStream ois = new ObjectInputStream(in);
final Factory f = (Factory) ois.readObject();
// create query using factory directly
// because any try to call CtElement#map or CtElement#filterChildren will fail on uninitialized factory
f.createQuery(f.Module().getAllModules().toArray()).filterChildren(new Filter<CtElement>() {
@Override
public boolean matches(CtElement e) {
e.setFactory(f);
return false;
}
}).list();
ois.close();
return f;
} catch (ClassNotFoundException e) {
Launcher.LOGGER.error(e.getMessage(), e);
throw new IOException(e.getMessage());
}
}
Aggregations