use of spoon.support.visitor.SubInheritanceHierarchyResolver in project spoon by INRIA.
the class FilterTest method testSubInheritanceHierarchyResolver.
@Test
public void testSubInheritanceHierarchyResolver() throws Exception {
// contract; SubInheritanceHierarchyResolver supports finding subtypes in an incremental manner
final Launcher launcher = new Launcher();
launcher.setArgs(new String[] { "--output-type", "nooutput", "--level", "info" });
launcher.addInputResource("./src/test/java/spoon/test/filters/testclasses");
launcher.buildModel();
SubInheritanceHierarchyResolver resolver = new SubInheritanceHierarchyResolver(launcher.getModel().getRootPackage());
// contract: by default, nothing is sent to the consumer
resolver.forEachSubTypeInPackage(new CtConsumer<CtType<?>>() {
@Override
public void accept(CtType<?> ctType) {
fail();
}
});
// we add a type
resolver.addSuperType(launcher.getFactory().Type().createReference(AbstractTostada.class));
class Counter {
int counter = 0;
}
Counter c = new Counter();
resolver.forEachSubTypeInPackage(new CtConsumer<CtType<?>>() {
@Override
public void accept(CtType<?> ctType) {
c.counter++;
}
});
// there are 5 subtypes of AbstractTostada
assertEquals(5, c.counter);
// we add a type already visited
resolver.addSuperType(launcher.getFactory().Type().createReference(Tostada.class));
// nothing is sent to the consumer
resolver.forEachSubTypeInPackage(new CtConsumer<CtType<?>>() {
@Override
public void accept(CtType<?> ctType) {
fail();
}
});
// we add a new type
resolver.addSuperType(launcher.getFactory().Type().createReference(ITostada.class));
Counter c2 = new Counter();
resolver.forEachSubTypeInPackage(new CtConsumer<CtType<?>>() {
@Override
public void accept(CtType<?> ctType) {
c2.counter++;
assertEquals("spoon.test.filters.testclasses.Tacos", ctType.getQualifiedName());
}
});
// only one subtype remains unvisited
assertEquals(1, c2.counter);
}
use of spoon.support.visitor.SubInheritanceHierarchyResolver in project spoon by INRIA.
the class SubInheritanceHierarchyFunction method apply.
@Override
public void apply(CtTypeInformation input, final CtConsumer<Object> outputConsumer) {
final SubInheritanceHierarchyResolver fnc = new SubInheritanceHierarchyResolver(((CtElement) input).getFactory().getModel().getRootPackage()).failOnClassNotFound(failOnClassNotFound).includingInterfaces(includingInterfaces);
if (includingSelf) {
if (input instanceof CtTypeReference) {
outputConsumer.accept(((CtTypeReference<?>) input).getTypeDeclaration());
} else {
outputConsumer.accept(((CtType<?>) input));
}
}
fnc.addSuperType(input);
fnc.forEachSubTypeInPackage(new CtConsumer<CtType>() {
@Override
public void accept(CtType typeInfo) {
outputConsumer.accept(typeInfo);
if (query.isTerminated()) {
// Cannot terminate, because it's support was removed.
// I think there are cases where it might be useful.
// fnc.terminate();
}
}
});
}
use of spoon.support.visitor.SubInheritanceHierarchyResolver in project spoon by INRIA.
the class AllMethodsSameSignatureFunction method apply.
@Override
public void apply(final CtExecutable<?> targetExecutable, final CtConsumer<Object> outputConsumer) {
// prepare filter for lambda expression. It will be configured by the algorithm below
final LambdaFilter lambdaFilter = new LambdaFilter();
final CtQuery lambdaQuery = targetExecutable.getFactory().getModel().filterChildren(lambdaFilter);
// the to be searched method
CtMethod<?> targetMethod;
if (targetExecutable instanceof CtLambda) {
// the input is lambda
if (includingSelf && includingLambdas) {
outputConsumer.accept(targetExecutable);
if (query.isTerminated()) {
return;
}
}
// in case of lambda, the target method is the method implemented by lambda
targetMethod = ((CtLambda<?>) targetExecutable).getOverriddenMethod();
outputConsumer.accept(targetMethod);
if (query.isTerminated()) {
return;
}
// the input is the lambda expression, which was already returned or doesn't have to be returned at all because includingSelf == false
// add extra filter into lambdaQuery which skips that input lambda expression
lambdaQuery.select(new Filter<CtLambda<?>>() {
@Override
public boolean matches(CtLambda<?> lambda) {
return targetExecutable != lambda;
}
});
} else if (targetExecutable instanceof CtMethod) {
if (includingSelf) {
outputConsumer.accept(targetExecutable);
if (query.isTerminated()) {
return;
}
}
targetMethod = (CtMethod<?>) targetExecutable;
} else {
// CtConstructor or CtAnonymousExecutable never overrides other executable. We are done
if (includingSelf) {
outputConsumer.accept(targetExecutable);
}
return;
}
final List<CtMethod<?>> targetMethods = new ArrayList<>();
targetMethods.add(targetMethod);
CtType<?> declaringType = targetMethod.getDeclaringType();
lambdaFilter.addImplementingInterface(declaringType);
// search for all declarations and implementations of this method in sub and super classes and interfaces of all related hierarchies.
class Context {
boolean haveToSearchForSubtypes;
}
final Context context = new Context();
// at the beginning we know that we have to always search for sub types too.
context.haveToSearchForSubtypes = true;
// Sub inheritance hierarchy function, which remembers visited sub types and does not returns/visits them again
final SubInheritanceHierarchyResolver subHierarchyFnc = new SubInheritanceHierarchyResolver(declaringType.getFactory().getModel().getRootPackage());
// add hierarchy of `targetMethod` as to be checked for sub types of declaring type
subHierarchyFnc.addSuperType(declaringType);
// unique names of all types whose super inheritance hierarchy was searched for rootType
Set<String> typesCheckedForRootType = new HashSet<>();
// list of sub types whose inheritance hierarchy has to be checked
final List<CtType<?>> toBeCheckedSubTypes = new ArrayList<>();
// add hierarchy of `targetMethod` as to be checked for super types of declaring type
toBeCheckedSubTypes.add(declaringType);
while (toBeCheckedSubTypes.size() > 0) {
for (CtType<?> subType : toBeCheckedSubTypes) {
ClassTypingContext ctc = new ClassTypingContext(subType);
// search for first target method from the same type inheritance hierarchy
targetMethod = getTargetMethodOfHierarchy(targetMethods, ctc);
// search for all methods with same signature in inheritance hierarchy of `subType`
forEachOverridenMethod(ctc, targetMethod, typesCheckedForRootType, new CtConsumer<CtMethod<?>>() {
@Override
public void accept(CtMethod<?> overriddenMethod) {
targetMethods.add(overriddenMethod);
outputConsumer.accept(overriddenMethod);
CtType<?> type = overriddenMethod.getDeclaringType();
lambdaFilter.addImplementingInterface(type);
subHierarchyFnc.addSuperType(type);
// mark that new super type was added, so we have to search for sub types again
context.haveToSearchForSubtypes = true;
}
});
if (query.isTerminated()) {
return;
}
}
toBeCheckedSubTypes.clear();
if (context.haveToSearchForSubtypes) {
context.haveToSearchForSubtypes = false;
// there are some new super types, whose sub inheritance hierarchy has to be checked
// search their inheritance hierarchy for sub types
subHierarchyFnc.forEachSubTypeInPackage(new CtConsumer<CtType<?>>() {
@Override
public void accept(CtType<?> type) {
toBeCheckedSubTypes.add(type);
}
});
}
}
if (includingLambdas) {
// search for all lambdas implementing any of the found interfaces
lambdaQuery.forEach(outputConsumer);
}
}
Aggregations