Search in sources :

Example 31 with CtBlock

use of spoon.reflect.code.CtBlock in project spoon by INRIA.

the class CloneVisitorGenerator method process.

@Override
public void process() {
    final CtClass<Object> target = createCloneVisitor();
    final CtClass<Object> targetBuilder = createCloneBuilder();
    final Factory factory = target.getFactory();
    final CtTypeReference<Object> cloneBuilder = factory.Type().createReference("spoon.support.visitor.clone.CloneBuilder");
    final CtTypeAccess<Object> cloneBuilderType = factory.Code().createTypeAccess(cloneBuilder);
    final CtVariableAccess<Object> builderFieldAccess = factory.Code().createVariableRead(factory.Field().createReference(target.getReference(), cloneBuilder, "builder"), false);
    final CtVariableAccess<Object> tailorerFieldAccess = factory.Code().createVariableRead(factory.Field().createReference(target.getReference(), cloneBuilder, "tailorer"), false);
    final CtVariableAccess<Object> cloneHelperFieldAccess = factory.Code().createVariableRead(factory.Field().createReference(target.getReference(), cloneBuilder, "cloneHelper"), false);
    final CtFieldReference<Object> other = factory.Field().createReference((CtField) target.getField("other"));
    final CtVariableAccess otherRead = factory.Code().createVariableRead(other, true);
    new CtScanner() {

        private final List<String> internals = Collections.singletonList("CtCircularTypeReference");

        @Override
        public <T> void visitCtMethod(CtMethod<T> element) {
            if (!element.getSimpleName().startsWith("visitCt")) {
                return;
            }
            CtMethod<T> clone = element.clone();
            // Variables used by the visit method.
            final CtParameter<CtElement> ctParameter = (CtParameter<CtElement>) element.getParameters().get(0);
            final CtVariableAccess<CtElement> elementVarRead = factory.Code().createVariableRead(ctParameter.getReference(), false);
            final CtInvocation cloneBuilderInvocation = createCloneBuilderBuildInvocation(elementVarRead);
            final CtLocalVariable localCloningElement = createLocalCloningElement(ctParameter.getType(), createFactoryInvocation(elementVarRead));
            final CtVariableAccess localVarRead = factory.Code().createVariableRead(localCloningElement.getReference(), false);
            // Changes body of the cloned method.
            for (int i = 1; i < clone.getBody().getStatements().size() - 1; i++) {
                List<CtExpression> invArgs = ((CtInvocation) clone.getBody().getStatement(i)).getArguments();
                if (invArgs.size() <= 1) {
                    throw new RuntimeException("You forget the role argument in line " + i + " of method " + element.getSimpleName() + " from " + element.getDeclaringType().getQualifiedName());
                }
                final CtInvocation targetInvocation = (CtInvocation) invArgs.get(1);
                if ("getValue".equals(targetInvocation.getExecutable().getSimpleName()) && "CtLiteral".equals(targetInvocation.getExecutable().getDeclaringType().getSimpleName())) {
                    clone.getBody().getStatement(i--).delete();
                    continue;
                }
                // 
                clone.getBody().getStatement(i).replace(createSetter((CtInvocation) clone.getBody().getStatement(i), localVarRead));
            }
            // Delete enter and exit methods.
            clone.getBody().getStatement(0).delete();
            clone.getBody().getStatement(clone.getBody().getStatements().size() - 1).delete();
            // declaration of local variable
            clone.getBody().insertBegin(localCloningElement);
            // call to copy
            clone.getBody().insertEnd(createCloneBuilderCopyInvocation(elementVarRead, localVarRead));
            // call to tailor
            clone.getBody().insertEnd(createTailorerScanInvocation(elementVarRead, localVarRead));
            // final assignment
            clone.getBody().insertEnd(factory.Code().createVariableAssignment(other, false, localVarRead));
            // Add auto-generated comment.
            final CtComment comment = factory.Core().createComment();
            comment.setCommentType(CtComment.CommentType.INLINE);
            comment.setContent("auto-generated, see " + CloneVisitorGenerator.class.getName());
            clone.addComment(comment);
            target.addMethod(clone);
        }

        /**
         * Creates <code>anElement.setX(clone(anElement.getX()))</code>.
         *
         * @param scanInvocation <code>scan(anElement.getX())</code>.
         * @param elementVarRead <code>anElement</code>.
         */
        private CtInvocation<?> createSetter(CtInvocation scanInvocation, CtVariableAccess<CtElement> elementVarRead) {
            final CtInvocation<?> getter = (CtInvocation<?>) scanInvocation.getArguments().get(1);
            final String getterName = getter.getExecutable().getSimpleName();
            final CtExecutableReference<Object> setterRef = factory.Executable().createReference("void CtElement#set" + getterName.substring(3, getterName.length()) + "()");
            final CtExecutableReference<Object> cloneRef = factory.Executable().createReference("CtElement spoon.support.visitor.equals.CloneHelper#clone()");
            final CtInvocation<Object> cloneInv = factory.Code().createInvocation(null, cloneRef, getter);
            cloneInv.setTarget(cloneHelperFieldAccess);
            return factory.Code().createInvocation(elementVarRead, setterRef, cloneInv);
        }

        /**
         * Creates <code>CtElement anElement = CloneBuilder.build(builder, element, element.getFactory().Core().createElement())</code>.
         *
         * @param typeReference <code>CtElement</code>.
         * @param ctInvocation <code>CloneBuilder.build(builder, element, element.getFactory().Core().createElement())</code>.
         */
        private <T> CtLocalVariable<T> createLocalCloningElement(CtTypeReference<T> typeReference, CtInvocation<T> ctInvocation) {
            return factory.Code().createLocalVariable(typeReference, "a" + typeReference.getSimpleName(), ctInvocation);
        }

        /**
         * Creates <code>CloneBuilder.build(builder, element, element.getFactory().Core().createElement())</code>.
         *
         * @param elementAccess <code>element</code>.
         */
        private CtInvocation<CloneBuilder> createCloneBuilderBuildInvocation(CtVariableAccess<CtElement> elementAccess) {
            final CtExecutableReference<CloneBuilder> buildExecRef = factory.Executable().createReference("CloneBuilder CtElement#build()");
            return factory.Code().createInvocation(cloneBuilderType, buildExecRef, builderFieldAccess, elementAccess, createFactoryInvocation(elementAccess.clone()));
        }

        private CtInvocation<CloneBuilder> createCloneBuilderCopyInvocation(CtVariableAccess<CtElement> elementVarRead, CtVariableAccess<CtElement> elementVarRead2) {
            final CtExecutableReference<CloneBuilder> buildExecRef = factory.Executable().createReference("CloneBuilder #copy()");
            return factory.Code().createInvocation(builderFieldAccess, buildExecRef, elementVarRead, elementVarRead2);
        }

        private CtInvocation<CloneBuilder> createTailorerScanInvocation(CtVariableAccess elementVarRead, CtVariableAccess localVarRead) {
            final CtExecutableReference<CloneBuilder> buildExecRef = factory.Executable().createReference("CloneHelper #tailor()");
            return factory.Code().createInvocation(cloneHelperFieldAccess, buildExecRef, elementVarRead, localVarRead);
        }

        /**
         * Creates <code>element.getFactory().Core().createElement()</code>.
         *
         * @param elementAccess <code>element</code>.
         */
        private CtInvocation createFactoryInvocation(CtVariableAccess<CtElement> elementAccess) {
            final String typeName = elementAccess.getType().getSimpleName();
            // #getFactory()
            final CtInvocation<Object> getFactory = factory.Code().createInvocation(null, factory.Executable().createReference("Factory CtElement#getFactory()"));
            getFactory.setTarget(elementAccess);
            // Factory#Core() or Factory#Internal()
            final String factoryName = internals.contains(typeName) ? "Internal" : "Core";
            final CtInvocation<Object> coreFactory = factory.Code().createInvocation(getFactory, factory.Executable().createReference("CoreFactory Factory#" + factoryName + "()"));
            // CoreFactory#createElement()
            return factory.Code().createInvocation(coreFactory, factory.Executable().createReference("CoreFactory CtElement#create" + typeName.substring(2, typeName.length()) + "()"));
        }
    }.scan(getFactory().Class().get(CtScanner.class));
    new CtScanner() {

        private final List<String> excludesAST = // 
        Arrays.asList(// 
        "spoon.support.reflect.declaration.CtTypeInformationImpl", // 
        "spoon.support.reflect.code.CtAbstractInvocationImpl", // 
        "spoon.support.reflect.declaration.CtTypedElementImpl", // 
        "spoon.support.reflect.declaration.CtVariableImpl", // 
        "spoon.support.reflect.reference.CtActualTypeContainerImpl", // 
        "spoon.support.reflect.code.CtCFlowBreakImpl", // 
        "spoon.support.reflect.code.CtLabelledFlowBreakImpl", // 
        "spoon.support.reflect.declaration.CtCodeSnippetImpl", // 
        "spoon.support.reflect.declaration.CtFormalTypeDeclarerImpl", // 
        "spoon.support.reflect.declaration.CtGenericElementImpl", // 
        "spoon.support.reflect.reference.CtGenericElementReferenceImpl", // 
        "spoon.support.reflect.declaration.CtModifiableImpl", // 
        "spoon.support.reflect.declaration.CtMultiTypedElementImpl", "spoon.support.reflect.declaration.CtTypeMemberImpl", "spoon.support.reflect.code.CtRHSReceiverImpl", "spoon.support.reflect.declaration.CtShadowableImpl", "spoon.support.reflect.code.CtBodyHolderImpl", "spoon.support.reflect.declaration.CtModuleDirectiveImpl");

        private final List<String> excludesFields = Arrays.asList("factory", "elementValues", "target", "metadata");

        private final CtTypeReference<List> LIST_REFERENCE = factory.Type().createReference(List.class);

        private final CtTypeReference<Collection> COLLECTION_REFERENCE = factory.Type().createReference(Collection.class);

        private final CtTypeReference<Set> SET_REFERENCE = factory.Type().createReference(Set.class);

        private final CtTypeReference<CtElement> CTELEMENT_REFERENCE = factory.Type().createReference(CtElement.class);

        private final CtClass<?> GETTER_TEMPLATE_MATCHER_CLASS = factory.Class().get(GENERATING_CLONE_PACKAGE + ".GetterTemplateMatcher");

        private final CtClass<?> SETTER_TEMPLATE_MATCHER_CLASS = factory.Class().get(GENERATING_CLONE_PACKAGE + ".SetterTemplateMatcher");

        @Override
        public <T> void visitCtMethod(CtMethod<T> element) {
            if (!element.getSimpleName().startsWith("visitCt") && !element.getSimpleName().startsWith("scanCt")) {
                return;
            }
            if ("scanCtVisitable".equals(element.getSimpleName())) {
                return;
            }
            final String qualifiedNameOfImplClass = "spoon.support" + element.getParameters().get(0).getType().getQualifiedName().substring(5) + "Impl";
            if (excludesAST.contains(qualifiedNameOfImplClass)) {
                return;
            }
            final CtType<?> declaration = factory.Class().get(qualifiedNameOfImplClass);
            if (declaration == null) {
                throw new SpoonException(qualifiedNameOfImplClass + " doesn't have declaration in the source path for " + element.getSignature());
            }
            CtMethod<T> clone = element.clone();
            clone.getBody().getStatements().clear();
            for (CtField<?> ctField : declaration.getFields()) {
                if (excludesFields.contains(ctField.getSimpleName())) {
                    continue;
                }
                if (isConstantOrStatic(ctField)) {
                    continue;
                }
                if (isSubTypeOfCtElement(ctField.getType())) {
                    continue;
                }
                final CtMethod<?> setterOfField = getSetterOf(ctField);
                final CtInvocation<?> setterInvocation = createSetterInvocation(// 
                element.getParameters().get(0).getType(), // 
                setterOfField, createGetterInvocation(element.getParameters().get(0), getGetterOf(ctField)));
                final List<CtMethod<?>> methodsToAvoid = getCtMethodThrowUnsupportedOperation(setterOfField);
                if (methodsToAvoid.size() > 0) {
                    clone.getBody().addStatement(createProtectionToException(setterInvocation, methodsToAvoid));
                } else {
                    clone.getBody().addStatement(setterInvocation);
                }
            }
            if (clone.getBody().getStatements().size() > 0) {
                clone.getBody().insertEnd(createSuperInvocation(element));
                // Add auto-generated comment.
                final CtComment comment = factory.Core().createComment();
                comment.setCommentType(CtComment.CommentType.INLINE);
                comment.setContent("auto-generated, see " + CloneVisitorGenerator.class.getName());
                clone.addComment(comment);
                targetBuilder.addMethod(clone);
            }
        }

        /**
         * Creates <code>if (!(other instanceof CtX && other instanceof CtY && ..)) {}</code>.
         */
        private CtIf createProtectionToException(CtInvocation<?> setterInvocation, List<CtMethod<?>> methodsAvoid) {
            final CtIf anIf = factory.Core().createIf();
            anIf.setCondition(factory.Core().createUnaryOperator().setOperand(createBinaryConditions(methodsAvoid)).setKind(UnaryOperatorKind.NOT));
            anIf.setThenStatement(factory.Code().createCtBlock(setterInvocation));
            return anIf;
        }

        /**
         * Creates <code>condition && condition && ...</code>.
         *
         * @param methodsAvoid Methods to avoid.
         */
        private CtExpression<Object> createBinaryConditions(List<CtMethod<?>> methodsAvoid) {
            CtExpression<Object> left = null;
            CtExpression<Object> right;
            for (int i = 0; i < methodsAvoid.size(); i++) {
                final CtInterface<?> ctInterface = getInterfaceOf(methodsAvoid.get(i).getDeclaringType());
                if (i == 0) {
                    left = // 
                    factory.Code().createBinaryOperator(// 
                    otherRead, // 
                    factory.Code().createTypeAccess(ctInterface.getReference()), BinaryOperatorKind.INSTANCEOF);
                } else {
                    right = // 
                    factory.Code().createBinaryOperator(// 
                    otherRead, // 
                    factory.Code().createTypeAccess(ctInterface.getReference()), BinaryOperatorKind.INSTANCEOF);
                    left = factory.Code().createBinaryOperator(left, right, BinaryOperatorKind.OR);
                }
            }
            return left;
        }

        /**
         * Query to get all methods which throw an UnsupportedOperationException. We must avoid to call these methods during a clone process.
         */
        private List<CtMethod<?>> getCtMethodThrowUnsupportedOperation(CtMethod<?> method) {
            final List<CtMethod<?>> avoid = new ArrayList<>();
            final CtInterface<?> ctInterface = getInterfaceOf(method.getDeclaringType());
            if (ctInterface == null) {
                return avoid;
            }
            final CtMethod<?> declarationMethod = getMethodByCtMethod(ctInterface, method);
            for (CtMethod<?> ctMethod : Query.getElements(factory, new OverridingMethodFilter(declarationMethod))) {
                if (!avoidThrowUnsupportedOperationException(ctMethod)) {
                    avoid.add(ctMethod);
                }
            }
            return avoid;
        }

        /**
         * Check if the candidate method throw an UnsupportedOperationException.
         */
        private boolean avoidThrowUnsupportedOperationException(CtMethod<?> candidate) {
            if (candidate.getBody().getStatements().size() != 1) {
                return true;
            }
            if (!(candidate.getBody().getStatement(0) instanceof CtThrow)) {
                return true;
            }
            CtThrow ctThrow = candidate.getBody().getStatement(0);
            if (!(ctThrow.getThrownExpression() instanceof CtConstructorCall)) {
                return true;
            }
            final CtConstructorCall<? extends Throwable> thrownExpression = (CtConstructorCall<? extends Throwable>) ctThrow.getThrownExpression();
            if (!thrownExpression.getType().equals(factory.Type().createReference(UnsupportedOperationException.class))) {
                return true;
            }
            return false;
        }

        /**
         * Query to get a method from a CtMethod.
         */
        private CtMethod<?> getMethodByCtMethod(CtType<?> ctType, CtMethod<?> method) {
            for (CtMethod<?> ctMethod : ctType.getAllMethods()) {
                if (!method.getSimpleName().equals(ctMethod.getSimpleName())) {
                    continue;
                }
                boolean cont = method.getParameters().size() == ctMethod.getParameters().size();
                for (int i = 0; cont && i < method.getParameters().size(); i++) {
                    if (!method.getParameters().get(i).getType().equals(ctMethod.getParameters().get(i).getType())) {
                        cont = false;
                    }
                }
                if (cont) {
                    return ctMethod;
                }
            }
            throw new AssertionError("Can't find method " + method.getSignature() + " in the given interface " + ctType.getQualifiedName());
        }

        /**
         * Query to get the interface of the class.
         */
        private CtInterface<?> getInterfaceOf(CtType<?> declaringType) {
            final CtTypeReference<?>[] interfaces = declaringType.getSuperInterfaces().toArray(new CtTypeReference[declaringType.getSuperInterfaces().size()]);
            for (CtTypeReference<?> anInterface : interfaces) {
                if (anInterface.getSimpleName().equals(declaringType.getSimpleName().substring(0, declaringType.getSimpleName().length() - 4))) {
                    return (CtInterface<?>) anInterface.getDeclaration();
                }
            }
            throw new AssertionError("You should have the interface for the implementation " + declaringType.getQualifiedName());
        }

        /**
         * Creates <code>super.visitMethod(element)</code>.
         *
         * @param element <code>visitMethod</code>.
         */
        private <T> CtInvocation<T> createSuperInvocation(CtMethod<T> element) {
            return factory.Code().createInvocation(factory.Core().createSuperAccess(), element.getReference(), factory.Code().createVariableRead(element.getParameters().get(0).getReference(), false));
        }

        /**
         * Creates <code>((CtElement) other).setX(element.getX())</code>
         * or <code>((CtElement) other).setX(new Collection(element.getX()))</code>
         * if the field is a collection.
         *
         * @param type <code>CtElement</code>
         * @param setter <code>setX</code>.
         * @param getter <code>getX</code>.
         */
        private CtInvocation<?> createSetterInvocation(CtTypeReference<?> type, CtMethod<?> setter, CtInvocation<?> getter) {
            return factory.Code().createInvocation(otherRead.clone().addTypeCast(type), setter.getReference(), getter);
        }

        /**
         * Creates <code>element.getX()</code>.
         *
         * @param element <code>element</code>.
         * @param getter <code>getX</code>.
         */
        private CtInvocation<?> createGetterInvocation(CtParameter<?> element, CtMethod<?> getter) {
            return factory.Code().createInvocation(factory.Code().createVariableRead(element.getReference(), false), getter.getReference());
        }

        /**
         * Query to get the setter of given field.
         */
        private <T> CtMethod<?> getSetterOf(final CtField<T> ctField) {
            if (ctField.getType().equals(getFactory().createCtTypeReference(CtModifierHandler.class))) {
                return ctField.getDeclaringType().getMethodsByName("setModifiers").get(0);
            }
            // Search by name convention.
            for (CtMethod<?> ctMethod : ctField.getDeclaringType().getMethods()) {
                if (ctMethod.getSimpleName().startsWith("set") && ctMethod.getSimpleName().toLowerCase().contains(ctField.getSimpleName().toLowerCase())) {
                    if (ctMethod.getParameters().size() != 1) {
                        continue;
                    }
                    if (!ctMethod.getParameters().get(0).getType().equals(ctField.getType())) {
                        continue;
                    }
                    return ctMethod;
                }
            }
            SETTER_TEMPLATE_MATCHER_CLASS.getMethod("setElement", factory.Type().BOOLEAN_PRIMITIVE).getBody();
            final List<CtMethod> matchers = ctField.getDeclaringType().getElements(new TypeFilter<CtMethod>(CtMethod.class) {

                @Override
                public boolean matches(CtMethod element) {
                    final CtBlock body = element.getBody();
                    if (body.getStatements().size() != 3) {
                        return false;
                    }
                    if (body.getStatement(1) instanceof CtAssignment) {
                        final CtExpression assigned = ((CtAssignment) body.getStatement(1)).getAssigned();
                        if (!(assigned instanceof CtFieldAccess)) {
                            return false;
                        }
                        if (!((CtFieldAccess) assigned).getVariable().getSimpleName().equals(ctField.getSimpleName())) {
                            return false;
                        }
                    } else {
                        return false;
                    }
                    return true;
                }
            });
            if (matchers.size() != 1) {
                throw new SpoonException("Get more than one setter. Please make an more ingenious method to get setter method. " + matchers.size() + " " + ctField);
            }
            return matchers.get(0);
        }

        /**
         * Query to get the getter of the given field.
         */
        private <T> CtMethod<?> getGetterOf(CtField<T> ctField) {
            if (ctField.getType().equals(getFactory().createCtTypeReference(CtModifierHandler.class))) {
                return ctField.getDeclaringType().getMethod("getModifiers");
            }
            // Search by name convention.
            for (CtMethod<?> ctMethod : ctField.getDeclaringType().getMethods()) {
                if (// 
                (ctMethod.getSimpleName().startsWith("get") || ctMethod.getSimpleName().startsWith("is")) && ctMethod.getSimpleName().toLowerCase().contains(ctField.getSimpleName().toLowerCase())) {
                    if (!ctMethod.getType().equals(ctField.getType())) {
                        continue;
                    }
                    if (ctMethod.getParameters().size() != 0) {
                        continue;
                    }
                    return ctMethod;
                }
            }
            // Search with template.
            final CtBlock<?> templateRoot = GETTER_TEMPLATE_MATCHER_CLASS.getMethod("getElement").getBody();
            ((CtReturn) templateRoot.getStatement(0)).setReturnedExpression(factory.Code().createVariableRead(ctField.getReference(), true));
            List<CtMethod> matchers = ctField.getDeclaringType().getElements(new TypeFilter<CtMethod>(CtMethod.class) {

                @Override
                public boolean matches(CtMethod element) {
                    return element.getBody().toString().equals(templateRoot.toString());
                }
            });
            if (matchers.isEmpty()) {
                throw new SpoonException("No getter found for field " + ctField);
            }
            if (matchers.size() > 1) {
                throw new SpoonException("Get more than one getter (" + StringUtils.join(matchers, ";") + "). Please make an more ingenious method to get getter method.");
            }
            return matchers.get(0);
        }

        /**
         * Check if the type is a subtype of CtElement.
         */
        private boolean isSubTypeOfCtElement(CtTypeReference<?> type) {
            if (!type.isPrimitive() && !type.equals(factory.Type().STRING)) {
                if (type.isSubtypeOf(factory.Type().createReference(CtElement.class))) {
                    return true;
                }
                if (type.getQualifiedName().equals(LIST_REFERENCE.getQualifiedName()) || type.getQualifiedName().equals(COLLECTION_REFERENCE.getQualifiedName()) || type.getQualifiedName().equals(SET_REFERENCE.getQualifiedName())) {
                    if (type.getActualTypeArguments().get(0).isSubtypeOf(CTELEMENT_REFERENCE)) {
                        return true;
                    }
                }
            }
            return false;
        }

        private boolean isConstantOrStatic(CtField<?> ctField) {
            return ctField.getModifiers().contains(ModifierKind.FINAL) || ctField.getModifiers().contains(ModifierKind.STATIC);
        }
    }.scan(getFactory().Class().get(CtInheritanceScanner.class));
}
Also used : CtParameter(spoon.reflect.declaration.CtParameter) CtInvocation(spoon.reflect.code.CtInvocation) CtTypeReference(spoon.reflect.reference.CtTypeReference) CtExecutableReference(spoon.reflect.reference.CtExecutableReference) ArrayList(java.util.ArrayList) List(java.util.List) CtInterface(spoon.reflect.declaration.CtInterface) CtAssignment(spoon.reflect.code.CtAssignment) CtElement(spoon.reflect.declaration.CtElement) CtLocalVariable(spoon.reflect.code.CtLocalVariable) CtIf(spoon.reflect.code.CtIf) CtType(spoon.reflect.declaration.CtType) CtConstructorCall(spoon.reflect.code.CtConstructorCall) Collection(java.util.Collection) CtScanner(spoon.reflect.visitor.CtScanner) CtMethod(spoon.reflect.declaration.CtMethod) CtComment(spoon.reflect.code.CtComment) CtFieldAccess(spoon.reflect.code.CtFieldAccess) Set(java.util.Set) Factory(spoon.reflect.factory.Factory) TypeFilter(spoon.reflect.visitor.filter.TypeFilter) CtThrow(spoon.reflect.code.CtThrow) CtField(spoon.reflect.declaration.CtField) CtInheritanceScanner(spoon.reflect.visitor.CtInheritanceScanner) OverridingMethodFilter(spoon.reflect.visitor.filter.OverridingMethodFilter) CtVariableAccess(spoon.reflect.code.CtVariableAccess) SpoonException(spoon.SpoonException) CtExpression(spoon.reflect.code.CtExpression) CtBlock(spoon.reflect.code.CtBlock)

Example 32 with CtBlock

use of spoon.reflect.code.CtBlock in project spoon by INRIA.

the class TemplateMatcher method helperMatch.

/**
 * Detects whether `template` AST node and `target` AST node are matching.
 * This method is called for each node of to be matched template
 * and for appropriate node of `target`
 *
 * @param target actually checked AST node from target model
 * @param template actually checked AST node from template
 *
 * @return true if template matches this node, false if it does not matches
 *
 * note: Made private to hide the Objects.
 */
private boolean helperMatch(Object target, Object template) {
    if ((target == null) && (template == null)) {
        return true;
    }
    if ((target == null) || (template == null)) {
        return false;
    }
    if (containsSame(variables, template) || containsSame(typeVariables, template)) {
        /*
			 * we are just matching a template parameter.
			 * Check that defined ParameterMatcher matches the target too
			 */
        boolean add = invokeCallBack(target, template);
        if (add) {
            // ParameterMatcher matches the target too, add that match
            return addMatch(template, target);
        }
        return false;
    }
    if (target.getClass() != template.getClass()) {
        return false;
    }
    if ((template instanceof CtTypeReference) && template.equals(templateType.getReference())) {
        return true;
    }
    if ((template instanceof CtPackageReference) && template.equals(templateType.getPackage())) {
        return true;
    }
    if (template instanceof CtReference) {
        CtReference tRef = (CtReference) template;
        /*
			 * Check whether name of a template reference matches with name of target reference
			 * after replacing of variables in template name
			 */
        boolean ok = matchNames(tRef.getSimpleName(), ((CtReference) target).getSimpleName());
        if (ok && !template.equals(target)) {
            boolean remove = !invokeCallBack(target, template);
            if (remove) {
                matches.remove(tRef.getSimpleName());
                return false;
            }
            return true;
        }
    }
    if (template instanceof CtNamedElement) {
        CtNamedElement named = (CtNamedElement) template;
        boolean ok = matchNames(named.getSimpleName(), ((CtNamedElement) target).getSimpleName());
        if (ok && !template.equals(target)) {
            boolean remove = !invokeCallBack(target, template);
            if (remove) {
                matches.remove(named.getSimpleName());
                return false;
            }
        }
    }
    if (template instanceof Collection) {
        return matchCollections((Collection<?>) target, (Collection<?>) template);
    }
    if (template instanceof Map) {
        if (template.equals(target)) {
            return true;
        }
        Map<?, ?> temMap = (Map<?, ?>) template;
        Map<?, ?> tarMap = (Map<?, ?>) target;
        if (!temMap.keySet().equals(tarMap.keySet())) {
            return false;
        }
        return matchCollections(tarMap.values(), temMap.values());
    }
    if (template instanceof CtBlock<?>) {
        final List<CtStatement> statements = ((CtBlock) template).getStatements();
        if (statements.size() == 1 && statements.get(0) instanceof CtInvocation) {
            final CtInvocation ctStatement = (CtInvocation) statements.get(0);
            if ("S".equals(ctStatement.getExecutable().getSimpleName()) && CtBlock.class.equals(ctStatement.getType().getActualClass())) {
                return true;
            }
        }
    }
    if (target instanceof CtElement) {
        for (Field f : RtHelper.getAllFields(target.getClass())) {
            f.setAccessible(true);
            if (Modifier.isStatic(f.getModifiers())) {
                continue;
            }
            if (f.getName().equals("parent")) {
                continue;
            }
            if (f.getName().equals("position")) {
                continue;
            }
            if (f.getName().equals("docComment")) {
                continue;
            }
            if (f.getName().equals("factory")) {
                continue;
            }
            if (f.getName().equals("comments")) {
                continue;
            }
            if (f.getName().equals("metadata")) {
                continue;
            }
            try {
                if (!helperMatch(f.get(target), f.get(template))) {
                    return false;
                }
            } catch (IllegalAccessException ignore) {
            }
        }
        return true;
    } else if (target instanceof String) {
        return matchNames((String) template, (String) target);
    } else {
        return target.equals(template);
    }
}
Also used : CtElement(spoon.reflect.declaration.CtElement) CtField(spoon.reflect.declaration.CtField) Field(java.lang.reflect.Field) CtInvocation(spoon.reflect.code.CtInvocation) CtPackageReference(spoon.reflect.reference.CtPackageReference) CtBlock(spoon.reflect.code.CtBlock) CtReference(spoon.reflect.reference.CtReference) CtStatement(spoon.reflect.code.CtStatement) CtTypeReference(spoon.reflect.reference.CtTypeReference) Collection(java.util.Collection) CtNamedElement(spoon.reflect.declaration.CtNamedElement) HashMap(java.util.HashMap) Map(java.util.Map)

Example 33 with CtBlock

use of spoon.reflect.code.CtBlock in project spoon by INRIA.

the class TemplateReplaceReturnTest method testReturnReplaceTemplate.

@Test
public void testReturnReplaceTemplate() throws Exception {
    // contract: the template engine supports replace of `return _param_.S()` by `<CtBlock>`
    Launcher launcher = new Launcher();
    launcher.addTemplateResource(new FileSystemFile("./src/test/java/spoon/test/template/testclasses/ReturnReplaceTemplate.java"));
    launcher.buildModel();
    Factory factory = launcher.getFactory();
    CtBlock<String> model = (CtBlock) factory.Class().get(ReturnReplaceTemplate.class).getMethod("sample").getBody();
    CtClass<?> resultKlass = factory.Class().create(factory.Package().getOrCreate("spoon.test.template"), "ReturnReplaceResult");
    new ReturnReplaceTemplate(model).apply(resultKlass);
    assertEquals("{ if (((java.lang.System.currentTimeMillis()) % 2L) == 0) { return \"Panna\"; }else { return \"Orel\"; }}", getOptimizedString(resultKlass.getMethod("method").getBody()));
    launcher.setSourceOutputDirectory(new File("./target/spooned/"));
    launcher.getModelBuilder().generateProcessedSourceFiles(OutputType.CLASSES);
    ModelUtils.canBeBuilt(new File("./target/spooned/spoon/test/template/ReturnReplaceResult.java"), 8);
}
Also used : CtBlock(spoon.reflect.code.CtBlock) ReturnReplaceTemplate(spoon.test.template.testclasses.ReturnReplaceTemplate) Launcher(spoon.Launcher) Factory(spoon.reflect.factory.Factory) FileSystemFile(spoon.support.compiler.FileSystemFile) ModelUtils.getOptimizedString(spoon.testing.utils.ModelUtils.getOptimizedString) File(java.io.File) FileSystemFile(spoon.support.compiler.FileSystemFile) Test(org.junit.Test)

Example 34 with CtBlock

use of spoon.reflect.code.CtBlock in project spoon by INRIA.

the class InsertMethodsTest method insertBeforeAndUpdateParent.

@Test
public void insertBeforeAndUpdateParent() throws Exception {
    /**
     * if (condition)
     *     while (loop_condition)
     *
     * In this case the 'while' is inside an implicit block, but
     * when we insert a new statement
     *
     * if (condition) {
     *     newStatement
     *     while (loop_condition)
     *     ...
     * }
     *
     * Now the while is inside an explicit block.
     */
    Launcher spoon = new Launcher();
    Factory factory = spoon.createFactory();
    spoon.createCompiler(factory, SpoonResourceHelper.resources("./src/test/resources/spoon/test/intercession/insertBefore/InsertBeforeExample2.java")).build();
    // Get the 'while'
    List<CtWhile> elements = Query.getElements(factory, new TypeFilter<CtWhile>(CtWhile.class));
    assertTrue(1 == elements.size());
    CtWhile theWhile = elements.get(0);
    // We make sure the parent of the while is the CtIf and not the block
    CtElement parent = theWhile.getParent();
    assertTrue(parent instanceof CtBlock);
    assertTrue(parent.isImplicit());
    CtIf ifParent = (CtIf) parent.getParent();
    // Create a new statement to be inserted before the while
    CtStatement insert = factory.Code().createCodeSnippetStatement("System.out.println()");
    // Insertion of the new statement
    theWhile.insertBefore(insert);
    // We make sure the parent of the while is updated
    CtElement newParent = theWhile.getParent();
    assertTrue(newParent != ifParent);
    assertTrue(newParent instanceof CtBlock);
    assertFalse(newParent.isImplicit());
}
Also used : CtBlock(spoon.reflect.code.CtBlock) CtStatement(spoon.reflect.code.CtStatement) CtElement(spoon.reflect.declaration.CtElement) Launcher(spoon.Launcher) Factory(spoon.reflect.factory.Factory) CtWhile(spoon.reflect.code.CtWhile) CtIf(spoon.reflect.code.CtIf) Test(org.junit.Test)

Example 35 with CtBlock

use of spoon.reflect.code.CtBlock in project spoon by INRIA.

the class TestLabels method testLabelsAreDetected.

@Test
public void testLabelsAreDetected() {
    Launcher launcher = new Launcher();
    launcher.addInputResource("./src/test/java/spoon/test/labels/testclasses/ManyLabels.java");
    launcher.buildModel();
    CtMethod mainMethod = launcher.getFactory().getModel().getElements(new NamedElementFilter<>(CtMethod.class, "main")).get(0);
    CtBlock body = mainMethod.getBody();
    assertEquals(2, body.getStatements().size());
    CtBlock block = (CtBlock) body.getStatement(0);
    CtSwitch ctSwitch = (CtSwitch) body.getStatement(1);
    assertEquals("labelBlock", block.getLabel());
    assertEquals("sw", ctSwitch.getLabel());
    assertTrue(block.getStatement(1) instanceof CtIf);
    CtIf firstIf = (CtIf) block.getStatement(1);
    CtBlock then = firstIf.getThenStatement();
    CtBreak firstBreak = (CtBreak) then.getStatement(1);
    assertEquals("labelBlock", firstBreak.getTargetLabel());
    assertSame(block, firstBreak.getLabelledStatement());
    CtIf secondIf = (CtIf) block.getStatement(2);
    assertEquals("labelIf", secondIf.getLabel());
    CtBlock thenBlock = secondIf.getThenStatement();
    CtIf innerIf = (CtIf) thenBlock.getStatement(0);
    CtBlock innerThenBlock = innerIf.getThenStatement();
    CtBreak breakInnerIf = (CtBreak) innerThenBlock.getStatement(0);
    assertSame(secondIf, breakInnerIf.getLabelledStatement());
    CtCase firstCase = (CtCase) ctSwitch.getCases().get(0);
    List<CtStatement> statementList = firstCase.getStatements();
    assertEquals(2, statementList.size());
    CtDo ctDo = (CtDo) statementList.get(0);
    assertEquals("label", ctDo.getLabel());
    CtBreak finalBreak = (CtBreak) statementList.get(1);
    assertNull(finalBreak.getTargetLabel());
    assertNull(finalBreak.getLabelledStatement());
    CtBlock doBlock = (CtBlock) ctDo.getBody();
    CtWhile ctWhile = (CtWhile) doBlock.getStatement(1);
    assertEquals("lWhile", ctWhile.getLabel());
    CtBlock whileBlock = (CtBlock) ctWhile.getBody();
    CtFor forLoop = (CtFor) whileBlock.getStatement(0);
    CtBreak breakSwitch = (CtBreak) whileBlock.getStatement(1);
    assertEquals("sw", breakSwitch.getTargetLabel());
    assertSame(ctSwitch, breakSwitch.getLabelledStatement());
    assertEquals("forloop", forLoop.getLabel());
    CtBlock forBlock = (CtBlock) forLoop.getBody();
    assertEquals(7, forBlock.getStatements().size());
    CtIf firstForIf = (CtIf) forBlock.getStatement(1);
    CtIf secondForIf = (CtIf) forBlock.getStatement(2);
    CtIf thirdForIf = (CtIf) forBlock.getStatement(3);
    CtIf fourthForIf = (CtIf) forBlock.getStatement(4);
    CtBreak breakItself = (CtBreak) forBlock.getStatement(6);
    CtContinue continueFor = (CtContinue) ((CtBlock) firstForIf.getThenStatement()).getStatement(0);
    assertSame(forLoop, continueFor.getLabelledStatement());
    CtContinue continueWhile = (CtContinue) ((CtBlock) secondForIf.getThenStatement()).getStatement(0);
    assertSame(ctWhile, continueWhile.getLabelledStatement());
    CtContinue continueDo = (CtContinue) ((CtBlock) thirdForIf.getThenStatement()).getStatement(0);
    assertSame(ctDo, continueDo.getLabelledStatement());
    CtBreak breakDo = (CtBreak) ((CtBlock) fourthForIf.getThenStatement()).getStatement(0);
    assertSame(ctDo, breakDo.getLabelledStatement());
    assertEquals("labelbreak", breakItself.getLabel());
    assertEquals("labelbreak", breakItself.getTargetLabel());
    assertSame(breakItself, breakItself.getLabelledStatement());
}
Also used : CtBreak(spoon.reflect.code.CtBreak) CtSwitch(spoon.reflect.code.CtSwitch) CtIf(spoon.reflect.code.CtIf) CtWhile(spoon.reflect.code.CtWhile) CtBlock(spoon.reflect.code.CtBlock) CtStatement(spoon.reflect.code.CtStatement) CtCase(spoon.reflect.code.CtCase) NamedElementFilter(spoon.reflect.visitor.filter.NamedElementFilter) Launcher(spoon.Launcher) CtDo(spoon.reflect.code.CtDo) CtFor(spoon.reflect.code.CtFor) CtMethod(spoon.reflect.declaration.CtMethod) CtContinue(spoon.reflect.code.CtContinue) Test(org.junit.Test)

Aggregations

CtBlock (spoon.reflect.code.CtBlock)37 Test (org.junit.Test)24 CtStatement (spoon.reflect.code.CtStatement)17 CtIf (spoon.reflect.code.CtIf)15 Factory (spoon.reflect.factory.Factory)15 Launcher (spoon.Launcher)13 CtMethod (spoon.reflect.declaration.CtMethod)10 TypeFilter (spoon.reflect.visitor.filter.TypeFilter)9 CtElement (spoon.reflect.declaration.CtElement)7 CtInvocation (spoon.reflect.code.CtInvocation)5 CtTypeReference (spoon.reflect.reference.CtTypeReference)5 NamedElementFilter (spoon.reflect.visitor.filter.NamedElementFilter)5 ArrayList (java.util.ArrayList)4 CtCodeSnippetStatement (spoon.reflect.code.CtCodeSnippetStatement)4 CtClass (spoon.reflect.declaration.CtClass)4 File (java.io.File)3 List (java.util.List)3 CtAssignment (spoon.reflect.code.CtAssignment)3 CtBinaryOperator (spoon.reflect.code.CtBinaryOperator)3 SourcePosition (spoon.reflect.cu.SourcePosition)3