use of spoon.reflect.code.CtLambda 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.code.CtLambda in project spoon by INRIA.
the class JDTTreeBuilderHelper method createVariableAccessNoClasspath.
/**
* Analyzes if {@code singleNameReference} points to a {@link CtVariable} visible in current
* scope and, if existent, returns its corresponding {@link CtVariableAccess}. Returns
* {@code null} if {@code singleNameReference} could not be resolved as variable access. Since
* we are in noclasspath mode this function may also returns {@code null} if
* {@code singleNameReference} points to a variable declared by an unknown class.
*
* @param singleNameReference
* The potential variable access.
* @return A {@link CtVariableAccess} if {@code singleNameReference} points to a variable
* visible in current scope, {@code null} otherwise.
*/
<T> CtVariableAccess<T> createVariableAccessNoClasspath(SingleNameReference singleNameReference) {
final TypeFactory typeFactory = jdtTreeBuilder.getFactory().Type();
final CoreFactory coreFactory = jdtTreeBuilder.getFactory().Core();
final ExecutableFactory executableFactory = jdtTreeBuilder.getFactory().Executable();
final ContextBuilder contextBuilder = jdtTreeBuilder.getContextBuilder();
final ReferenceBuilder referenceBuilder = jdtTreeBuilder.getReferencesBuilder();
final PositionBuilder positionBuilder = jdtTreeBuilder.getPositionBuilder();
final String name = CharOperation.charToString(singleNameReference.token);
final CtVariable<T> variable = contextBuilder.getVariableDeclaration(name);
if (variable == null) {
return null;
}
final CtVariableReference<T> variableReference;
final CtVariableAccess<T> variableAccess;
if (variable instanceof CtParameter) {
// create variable of concrete type to avoid type casting while calling methods
final CtParameterReference<T> parameterReference = coreFactory.createParameterReference();
if (variable.getParent() instanceof CtLambda) {
// nothing
} else {
// Unfortunately, we can not use `variable.getReference()` here as some parent
// references (in terms of Java objects) have not been set up yet. Thus, we need to
// create the required parameter reference by our own.
// Since the given parameter has not been declared in a lambda expression it must
// have been declared by a method/constructor.
final CtExecutable executable = (CtExecutable) variable.getParent();
// create list of executable's parameter types
final List<CtTypeReference<?>> parameterTypesOfExecutable = new ArrayList<>();
@SuppressWarnings("unchecked") final List<CtParameter<?>> parametersOfExecutable = executable.getParameters();
for (CtParameter<?> parameter : parametersOfExecutable) {
parameterTypesOfExecutable.add(parameter.getType() != null ? parameter.getType().clone() : // it's the best match :(
typeFactory.OBJECT.clone());
}
// find executable's corresponding jdt element
AbstractMethodDeclaration executableJDT = null;
for (final ASTPair astPair : contextBuilder.stack) {
if (astPair.element == executable) {
executableJDT = (AbstractMethodDeclaration) astPair.node;
}
}
assert executableJDT != null;
// create a reference to executable's declaring class
final CtTypeReference declaringReferenceOfExecutable = // available
executableJDT.binding == null ? coreFactory.createTypeReference() : referenceBuilder.getTypeReference(executableJDT.binding.declaringClass);
// If executable is a constructor, `executable.getType()` returns null since the
// parent is not available yet. Fortunately, however, the return type of a
// constructor is its declaring class which, in our case, is already available with
// declaringReferenceOfExecutable.
CtTypeReference executableTypeReference = executable instanceof CtConstructor ? // indirectly sets the parent of `rt` and, thus, may break the AST!
declaringReferenceOfExecutable.clone() : executable.getType().clone();
}
variableReference = parameterReference;
variableAccess = isLhsAssignment(contextBuilder, singleNameReference) ? coreFactory.<T>createVariableWrite() : coreFactory.<T>createVariableRead();
} else if (variable instanceof CtField) {
variableReference = variable.getReference();
variableAccess = isLhsAssignment(contextBuilder, singleNameReference) ? coreFactory.<T>createFieldWrite() : coreFactory.<T>createFieldRead();
} else {
// CtLocalVariable, CtCatchVariable, ...
variableReference = variable.getReference();
variableAccess = isLhsAssignment(contextBuilder, singleNameReference) ? coreFactory.<T>createVariableWrite() : coreFactory.<T>createVariableRead();
}
variableReference.setSimpleName(name);
variableReference.setPosition(positionBuilder.buildPosition(singleNameReference.sourceStart(), singleNameReference.sourceEnd()));
variableAccess.setVariable(variableReference);
return variableAccess;
}
use of spoon.reflect.code.CtLambda in project spoon by INRIA.
the class TypeTest method testTypeReferenceInGenericsAndCasts.
@Test
public void testTypeReferenceInGenericsAndCasts() throws Exception {
final String target = "./target/type";
final Launcher launcher = new Launcher();
launcher.addInputResource("./src/test/java/spoon/test/type/testclasses");
launcher.setSourceOutputDirectory(target);
launcher.getEnvironment().setNoClasspath(true);
launcher.run();
final CtClass<Pozole> aPozole = launcher.getFactory().Class().get(Pozole.class);
final CtMethod<?> prepare = aPozole.getMethodsByName("finish").get(0);
// Intersection type in generic types.
final List<CtClass> localTypes = prepare.getElements(new TypeFilter<>(CtClass.class));
assertEquals(1, localTypes.size());
// New type parameter declaration.
final CtTypeParameter typeParameter = localTypes.get(0).getFormalCtTypeParameters().get(0);
assertNotNull(typeParameter);
assertEquals("T", typeParameter.getSimpleName());
assertIntersectionTypeForPozoleFinishMethod(aPozole, typeParameter.getSuperclass());
// Intersection type in casts.
final List<CtLambda<?>> lambdas = prepare.getElements(new TypeFilter<CtLambda<?>>(CtLambda.class));
assertEquals(1, lambdas.size());
assertEquals(1, lambdas.get(0).getTypeCasts().size());
assertEquals("java.lang.Runnable", lambdas.get(0).getTypeCasts().get(0).toString());
assertEquals(aPozole.getFactory().Type().createReference(Runnable.class), lambdas.get(0).getTypeCasts().get(0));
canBeBuilt(target, 8, true);
}
use of spoon.reflect.code.CtLambda in project spoon by INRIA.
the class LambdaTest method testLambdaFilter.
@Test
public void testLambdaFilter() throws Exception {
// check constructor with CtInterface
List<String> methodNames = foo.filterChildren(new LambdaFilter((CtInterface<?>) foo.getNestedType("CheckPerson"))).map((CtLambda l) -> l.getParent(CtMethod.class).getSimpleName()).list();
assertHasStrings(methodNames);
// check constructor with CtTypeReference
methodNames = foo.filterChildren(new LambdaFilter(foo.getNestedType("Check").getReference())).map((CtLambda l) -> l.getParent(CtMethod.class).getSimpleName()).list();
assertHasStrings(methodNames, "m", "m6");
// check empty constructor and addImplementingInterface with Interface
methodNames = foo.filterChildren(new LambdaFilter().addImplementingInterface((CtInterface<?>) foo.getNestedType("CheckPersons"))).map((CtLambda l) -> l.getParent(CtMethod.class).getSimpleName()).list();
assertHasStrings(methodNames, "m3", "m5");
// check empty constructor and addImplementingInterface with CtTypeReference
methodNames = foo.filterChildren(new LambdaFilter().addImplementingInterface(factory.createCtTypeReference(Predicate.class))).map((CtLambda l) -> l.getParent(CtMethod.class).getSimpleName()).list();
assertHasStrings(methodNames, "m2", "m4", "m7", "m8");
}
Aggregations