Search in sources :

Example 6 with CtLambda

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);
    }
}
Also used : ClassTypingContext(spoon.support.visitor.ClassTypingContext) ClassTypingContext(spoon.support.visitor.ClassTypingContext) CtLambda(spoon.reflect.code.CtLambda) CtQuery(spoon.reflect.visitor.chain.CtQuery) ArrayList(java.util.ArrayList) CtType(spoon.reflect.declaration.CtType) SubInheritanceHierarchyResolver(spoon.support.visitor.SubInheritanceHierarchyResolver) CtMethod(spoon.reflect.declaration.CtMethod) HashSet(java.util.HashSet)

Example 7 with CtLambda

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;
}
Also used : CtLambda(spoon.reflect.code.CtLambda) ArrayList(java.util.ArrayList) CtParameter(spoon.reflect.declaration.CtParameter) CtTypeReference(spoon.reflect.reference.CtTypeReference) CtField(spoon.reflect.declaration.CtField) CoreFactory(spoon.reflect.factory.CoreFactory) CtExecutable(spoon.reflect.declaration.CtExecutable) CtConstructor(spoon.reflect.declaration.CtConstructor) TypeFactory(spoon.reflect.factory.TypeFactory) ExecutableFactory(spoon.reflect.factory.ExecutableFactory) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)

Example 8 with CtLambda

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);
}
Also used : CtLambda(spoon.reflect.code.CtLambda) CtTypeParameter(spoon.reflect.declaration.CtTypeParameter) CtClass(spoon.reflect.declaration.CtClass) Pozole(spoon.test.type.testclasses.Pozole) Launcher(spoon.Launcher) Test(org.junit.Test)

Example 9 with CtLambda

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");
}
Also used : CtInterface(spoon.reflect.declaration.CtInterface) LambdaFilter(spoon.reflect.visitor.filter.LambdaFilter) CtLambda(spoon.reflect.code.CtLambda) CtMethod(spoon.reflect.declaration.CtMethod) Predicate(java.util.function.Predicate) Test(org.junit.Test)

Aggregations

CtLambda (spoon.reflect.code.CtLambda)9 Test (org.junit.Test)5 ArrayList (java.util.ArrayList)4 Launcher (spoon.Launcher)3 CtExecutable (spoon.reflect.declaration.CtExecutable)3 CtMethod (spoon.reflect.declaration.CtMethod)3 CtParameter (spoon.reflect.declaration.CtParameter)3 File (java.io.File)2 CtClass (spoon.reflect.declaration.CtClass)2 CtConstructor (spoon.reflect.declaration.CtConstructor)2 CtType (spoon.reflect.declaration.CtType)2 CtTypeParameter (spoon.reflect.declaration.CtTypeParameter)2 Factory (spoon.reflect.factory.Factory)2 CtExecutableReference (spoon.reflect.reference.CtExecutableReference)2 FileNotFoundException (java.io.FileNotFoundException)1 Serializable (java.io.Serializable)1 Arrays (java.util.Arrays)1 Collection (java.util.Collection)1 Collections (java.util.Collections)1 HashSet (java.util.HashSet)1