use of spoon.reflect.declaration.CtType in project spoon by INRIA.
the class SuperInheritanceHierarchyFunction method apply.
@Override
public void apply(CtTypeInformation input, CtConsumer<Object> outputConsumer) {
CtTypeReference<?> typeRef;
CtType<?> type;
// detect whether input is a class or something else (e.g. interface)
boolean isClass;
if (input instanceof CtType) {
type = (CtType<?>) input;
typeRef = type.getReference();
} else {
typeRef = (CtTypeReference<?>) input;
try {
type = typeRef.getTypeDeclaration();
} catch (SpoonClassNotFoundException e) {
if (typeRef.getFactory().getEnvironment().getNoClasspath() == false) {
throw e;
}
type = null;
}
}
// if the type is unknown, than we expect it is interface, otherwise we would visit java.lang.Object too, even for interfaces
isClass = type == null ? false : (type instanceof CtClass);
if (isClass == false && includingInterfaces == false) {
// the input is interface, but this scanner should visit only interfaces. Finish
return;
}
ScanningMode mode = enter(typeRef, isClass);
if (mode == SKIP_ALL) {
// listener decided to not visit that input. Finish
return;
}
if (includingSelf) {
sendResult(typeRef, outputConsumer);
if (query.isTerminated()) {
mode = SKIP_CHILDREN;
}
}
if (mode == NORMAL) {
if (isClass == false) {
visitSuperInterfaces(typeRef, outputConsumer);
} else {
// call visitSuperClasses only for input of type class. The contract of visitSuperClasses requires that
visitSuperClasses(typeRef, outputConsumer, includingInterfaces);
}
}
exit(typeRef, isClass);
}
use of spoon.reflect.declaration.CtType 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);
}
}
use of spoon.reflect.declaration.CtType in project spoon by INRIA.
the class LocalVariableReferenceFunction method apply.
@Override
public void apply(final CtElement scope, CtConsumer<Object> outputConsumer) {
CtVariable<?> var = targetVariable;
if (var == null) {
if (variableClass.isInstance(scope)) {
var = (CtVariable<?>) scope;
} else {
throw new SpoonException("The input of " + getClass().getSimpleName() + " must be a " + variableClass.getSimpleName() + " but is " + scope.getClass().getSimpleName());
}
}
final CtVariable<?> variable = var;
final String simpleName = variable.getSimpleName();
// the context which knows whether we are scanning in scope of local type or not
final Context context = new Context();
CtQuery scopeQuery;
if (scope == variable) {
// we are starting search from local variable declaration
scopeQuery = createScopeQuery(variable, scope, context);
} else {
// we are starting search later, somewhere deep in scope of variable declaration
final CtElement variableParent = variable.getParent();
/*
* search in parents of searching scope for the variableParent
* 1) to check that scope is a child of variableParent
* 2) to detect if there is an local class between variable declaration and scope
*/
if (scope.map(new ParentFunction()).select(new Filter<CtElement>() {
@Override
public boolean matches(CtElement element) {
if (element instanceof CtType) {
// detected that the search scope is in local class declared in visibility scope of variable
context.nrTypes++;
}
return variableParent == element;
}
}).first() == null) {
// the scope is not under children of localVariable
throw new SpoonException("Cannot search for references of variable in wrong scope.");
}
// search in all children of the scope element
scopeQuery = scope.map(new CtScannerFunction().setListener(context));
}
scopeQuery.select(new Filter<CtElement>() {
@Override
public boolean matches(CtElement element) {
if (variableReferenceClass.isInstance(element)) {
CtVariableReference<?> varRef = (CtVariableReference<?>) element;
if (simpleName.equals(varRef.getSimpleName())) {
// we have found a variable reference of required type in visibility scope of targetVariable
if (context.hasLocalType()) {
// so finally check that found variable reference is really a reference to target variable
return variable == varRef.getDeclaration();
}
// else we can be sure that found reference is reference to variable
return true;
}
}
return false;
}
}).forEach(outputConsumer);
}
use of spoon.reflect.declaration.CtType in project spoon by INRIA.
the class CtQueryImpl method getIndexOfCallerInStackOfLambda.
/**
* JVM implementations reports exception in call of lambda in different way.
* A) the to be called lambda expression whose input parameters are invalid is on top of stack trace
* B) the to be called lambda expression whose input parameters are invalid is NOT in stack trace at all
*
* This method detects actual behavior of JVM, so the code, which decides whether ClassCastException is expected (part of filtering process)
* or unexpected - thrown by clients wrong code works on all JVM implementations
*/
private static int getIndexOfCallerInStackOfLambda() {
CtConsumer<CtType<?>> f = (CtType<?> t) -> {
};
CtConsumer<Object> unchecked = (CtConsumer) f;
Object obj = new Integer(1);
try {
unchecked.accept(obj);
throw new SpoonException("The lambda expression with input type CtType must throw ClassCastException when input type is Integer. Basic CtQuery contract is violated by JVM!");
} catch (ClassCastException e) {
StackTraceElement[] stack = e.getStackTrace();
for (int i = 0; i < stack.length; i++) {
if ("getIndexOfCallerInStackOfLambda".equals(stack[i].getMethodName())) {
// check whether we can detect type of lambda input parameter from CCE
Class<?> detectectedClass = detectTargetClassFromCCE(e, obj);
if (CtType.class.equals(detectectedClass) == false) {
// mark it by negative index, so the query engine will fall back to eating of all CCEs and slow implementation
return -1;
}
return i;
}
}
throw new SpoonException("Spoon cannot detect index of caller of lambda expression in stack trace.", e);
}
}
use of spoon.reflect.declaration.CtType in project spoon by INRIA.
the class APITest method testPrintNotAllSourcesWithFilter.
@Test
public void testPrintNotAllSourcesWithFilter() throws Exception {
// contract: setOutputFilter can take an arbitrary filter
final File target = new File("./target/print-not-all/default");
final SpoonAPI launcher = new Launcher();
launcher.getEnvironment().setNoClasspath(true);
launcher.addInputResource("./src/main/java/spoon/template/");
launcher.setSourceOutputDirectory(target);
launcher.setOutputFilter(new AbstractFilter<CtType<?>>(CtType.class) {
@Override
public boolean matches(CtType<?> element) {
return "spoon.template.Parameter".equals(element.getQualifiedName()) || "spoon.template.AbstractTemplate".equals(element.getQualifiedName());
}
});
launcher.run();
List<File> list = new ArrayList<>(FileUtils.listFiles(target, new String[] { "java" }, true));
final List<String> filesName = list.stream().map(File::getName).sorted().collect(Collectors.<String>toList());
assertEquals(2, filesName.size());
assertEquals("AbstractTemplate.java", filesName.get(0));
assertEquals("Parameter.java", filesName.get(1));
}
Aggregations