Search in sources :

Example 21 with CtLocalVariable

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

the class CastTest method testTypeAnnotationOnCast.

@Test
public void testTypeAnnotationOnCast() throws Exception {
    final CtType<Castings> aCastings = buildClass(Castings.class);
    final CtLocalVariable local = aCastings.getMethod("bar").getElements(new TypeFilter<>(CtLocalVariable.class)).get(0);
    assertEquals(1, ((CtTypeReference) local.getDefaultExpression().getTypeCasts().get(0)).getAnnotations().size());
    assertEquals("((java.lang.@spoon.test.casts.Castings.TypeAnnotation(integer = 1)" + System.lineSeparator() + "String) (\"\"))", local.getDefaultExpression().toString());
}
Also used : CtTypeReference(spoon.reflect.reference.CtTypeReference) TypeFilter(spoon.reflect.visitor.filter.TypeFilter) CtLocalVariable(spoon.reflect.code.CtLocalVariable) Test(org.junit.Test)

Example 22 with CtLocalVariable

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

the class CommentTest method testInLineComment.

@Test
public void testInLineComment() {
    Factory f = getSpoonFactory();
    CtClass<?> type = (CtClass<?>) f.Type().get(InlineComment.class);
    String strType = type.toString();
    List<CtComment> comments = type.getElements(new TypeFilter<CtComment>(CtComment.class));
    // verify that the number of comment present in the AST is correct
    assertEquals(64, comments.size());
    // verify that all comments present in the AST is printed
    for (CtComment comment : comments) {
        if (comment.getCommentType() == CtComment.CommentType.FILE) {
            // the header of the file is not printed with the toString
            continue;
        }
        assertNotNull(comment.getParent());
        assertTrue(comment.toString() + ":" + comment.getParent() + " is not printed", strType.contains(comment.toString()));
    }
    assertEquals(3, type.getComments().size());
    assertEquals(CtComment.CommentType.FILE, type.getComments().get(0).getCommentType());
    assertEquals(createFakeComment(f, "comment class"), type.getComments().get(1));
    CtField<?> field = type.getField("field");
    assertEquals(3, field.getComments().size());
    assertEquals(createFakeComment(f, "Comment Field"), field.getComments().get(0));
    assertEquals("// Comment Field" + newLine + "// comment field 2" + newLine + "// comment in field" + newLine + "private int field = 10;", field.toString());
    CtAnonymousExecutable ctAnonymousExecutable = type.getAnonymousExecutables().get(0);
    assertEquals(1, ctAnonymousExecutable.getComments().size());
    assertEquals(createFakeComment(f, "comment static block"), ctAnonymousExecutable.getComments().get(0));
    assertEquals(createFakeComment(f, "comment inside static"), ctAnonymousExecutable.getBody().getStatement(0));
    assertEquals("// comment static block" + newLine + "static {" + newLine + "    // comment inside static" + newLine + "}", ctAnonymousExecutable.toString());
    CtConstructor constructor = type.getConstructor();
    assertEquals(1, constructor.getComments().size());
    assertEquals(createFakeComment(f, "comment constructor"), constructor.getComments().get(0));
    // index 0 is the implicit super call
    assertEquals(createFakeComment(f, "Comment in constructor"), constructor.getBody().getStatement(1));
    assertEquals("// comment constructor" + newLine + "public InlineComment() {" + newLine + "    // Comment in constructor" + newLine + "}", constructor.toString());
    CtMethod<Object> m = type.getMethod("m");
    assertEquals(1, m.getComments().size());
    assertEquals(createFakeComment(f, "comment method"), m.getComments().get(0));
    assertEquals(createFakeComment(f, "comment empty method block"), m.getBody().getStatement(0));
    assertEquals("// comment method" + newLine + "public void m() {" + newLine + "    // comment empty method block" + newLine + "}", m.toString());
    CtMethod<Object> m1 = type.getMethod("m1");
    CtSwitch ctSwitch = m1.getBody().getStatement(0);
    assertEquals(createFakeComment(f, "comment switch"), ctSwitch.getComments().get(0));
    assertEquals("// comment switch" + newLine + "switch (1) {" + newLine + "    // before first case" + newLine + "    case 0 :" + newLine + "        // comment case 0: empty case" + newLine + "    case 1 :" + newLine + "        // comment case 1" + newLine + "        int i = 0;" + newLine + "    default :" + newLine + "        // comment default" + newLine + "}", ctSwitch.toString());
    CtFor ctFor = m1.getBody().getStatement(1);
    assertEquals(createFakeComment(f, "comment for"), ctFor.getComments().get(0));
    assertEquals("// comment for" + newLine + "for (int i = 0; i < 10; i++) {" + newLine + "    // comment for block" + newLine + "}", ctFor.toString());
    CtIf ctIf = m1.getBody().getStatement(2);
    assertEquals(createFakeComment(f, "comment if"), ctIf.getComments().get(0));
    assertEquals("// comment if" + newLine + "if ((1 % 2) == 0) {" + newLine + "    // comment unary operator" + newLine + "    (field)++;" + newLine + "}", ctIf.toString());
    CtConstructorCall ctConstructorCall = m1.getBody().getStatement(3);
    assertEquals(createFakeComment(f, "comment constructor call"), ctConstructorCall.getComments().get(0));
    assertEquals("// comment constructor call" + newLine + "new spoon.test.comment.testclasses.InlineComment()", ctConstructorCall.toString());
    CtInvocation ctInvocation = m1.getBody().getStatement(4);
    assertEquals(createFakeComment(f, "comment invocation"), ctInvocation.getComments().get(0));
    assertEquals("// comment invocation" + newLine + "this.m()", ctInvocation.toString());
    CtLocalVariable ctLocalVariable = m1.getBody().getStatement(5);
    assertEquals(createFakeComment(f, "comment local variable"), ctLocalVariable.getComments().get(0));
    assertEquals("// comment local variable" + newLine + "int i = 0", ctLocalVariable.toString());
    CtLocalVariable ctLocalVariable2 = m1.getBody().getStatement(6);
    assertEquals(createFakeComment(f, "comment multi assignments"), ctLocalVariable2.getComments().get(0));
    assertEquals("// comment multi assignments" + newLine + "int j = 2", ctLocalVariable2.toString());
    CtDo ctDo = m1.getBody().getStatement(7);
    assertEquals(createFakeComment(f, "comment dowhile"), ctDo.getComments().get(0));
    assertEquals("// comment dowhile" + newLine + "do {" + newLine + "    // comment in do while" + newLine + "    i++;" + newLine + "    // comment end do while" + newLine + "} while (i < 10 )", ctDo.toString());
    CtTry ctTry = m1.getBody().getStatement(8);
    assertEquals(createFakeComment(f, "comment try"), ctTry.getComments().get(0));
    assertEquals("// comment try" + newLine + "try {" + newLine + "    // comment in try" + newLine + "    i++;" + newLine + "}// between" + newLine + "// try/catch" + newLine + " catch (java.lang.Exception e) {" + newLine + "    // comment in catch" + newLine + "}", ctTry.toString());
    CtSynchronized ctSynchronized = m1.getBody().getStatement(9);
    assertEquals(createFakeComment(f, "comment synchronized"), ctSynchronized.getComments().get(0));
    assertEquals("// comment synchronized" + newLine + "synchronized(this) {" + newLine + "    // comment in synchronized" + newLine + "}", ctSynchronized.toString());
    CtLocalVariable ctLocalVariable1 = m1.getBody().getStatement(10);
    CtConditional ctConditional = (CtConditional) ctLocalVariable1.getDefaultExpression();
    assertEquals(createFakeComment(f, "comment after condition CtConditional"), ctConditional.getCondition().getComments().get(0));
    assertEquals(createFakeComment(f, "comment before then CtConditional"), ctConditional.getThenExpression().getComments().get(0));
    assertEquals(createFakeComment(f, "comment after then CtConditional"), ctConditional.getThenExpression().getComments().get(1));
    assertEquals(createFakeComment(f, "comment before else CtConditional"), ctConditional.getElseExpression().getComments().get(0));
    assertEquals(createFakeComment(f, "comment after else CtConditional"), ctLocalVariable1.getComments().get(0));
    assertEquals("java.lang.Double dou = (i == 1// comment after condition CtConditional" + newLine + ") ? // comment before then CtConditional" + newLine + "null// comment after then CtConditional" + newLine + " : // comment before else CtConditional" + newLine + "new java.lang.Double((j / ((double) (i - 1))))", ctLocalVariable1.toString());
    CtNewArray ctNewArray = (CtNewArray) ((CtLocalVariable) m1.getBody().getStatement(11)).getDefaultExpression();
    assertEquals(createFakeComment(f, "last comment at the end of array"), ctNewArray.getComments().get(0));
    CtElement arrayValue = (CtElement) ctNewArray.getElements().get(0);
    assertEquals(createFakeComment(f, "comment before array value"), arrayValue.getComments().get(0));
    assertEquals(createFakeComment(f, "comment after array value"), arrayValue.getComments().get(1));
    CtLocalVariable ctLocalVariableString = m1.getBody().getStatement(12);
    assertEquals(createFakeComment(f, "comment multi line string"), ((CtBinaryOperator) ((CtBinaryOperator) ctLocalVariableString.getDefaultExpression()).getRightHandOperand()).getLeftHandOperand().getComments().get(0));
    assertEquals("\"\" + (\"\"// comment multi line string" + newLine + " + \"\")", ctLocalVariableString.getDefaultExpression().toString());
    ctLocalVariable1 = m1.getBody().getStatement(13);
    ctConditional = (CtConditional) ctLocalVariable1.getDefaultExpression();
    assertEquals("boolean c = (i == 1) ? // comment before then boolean CtConditional" + newLine + "i == 1// comment after then boolean CtConditional" + newLine + " : i == 2", ctLocalVariable1.toString());
    CtReturn ctReturn = m1.getBody().getStatement(14);
    assertEquals(createFakeComment(f, "comment return"), ctReturn.getComments().get(0));
    assertEquals("// comment return" + newLine + "return", ctReturn.toString());
    CtMethod m2 = type.getMethodsByName("m2").get(0);
    assertEquals(6, m2.getComments().size());
    CtParameter ctParameter = (CtParameter) m2.getParameters().get(0);
    assertEquals(4, ctParameter.getComments().size());
    assertEquals("// comment before type" + newLine + "// comment after parameter" + newLine + "// comment before throws" + newLine + "// comment before exception 1" + newLine + "// comment before exception 2" + newLine + "// comment before block" + newLine + "public void m2(// comment before name" + newLine + "// comment before parameters" + newLine + "// comment before type parameter" + newLine + "// comment before name parameter" + newLine + "int i) throws java.lang.Error, java.lang.Exception {" + newLine + "}", m2.toString());
}
Also used : CtConditional(spoon.reflect.code.CtConditional) CtComment(spoon.reflect.code.CtComment) CtSwitch(spoon.reflect.code.CtSwitch) DefaultCoreFactory(spoon.support.DefaultCoreFactory) Factory(spoon.reflect.factory.Factory) CtParameter(spoon.reflect.declaration.CtParameter) CtTry(spoon.reflect.code.CtTry) CtNewArray(spoon.reflect.code.CtNewArray) CtSynchronized(spoon.reflect.code.CtSynchronized) InlineComment(spoon.test.comment.testclasses.InlineComment) CtInvocation(spoon.reflect.code.CtInvocation) CtReturn(spoon.reflect.code.CtReturn) CtDo(spoon.reflect.code.CtDo) CtFor(spoon.reflect.code.CtFor) CtBinaryOperator(spoon.reflect.code.CtBinaryOperator) CtElement(spoon.reflect.declaration.CtElement) CtLocalVariable(spoon.reflect.code.CtLocalVariable) CtIf(spoon.reflect.code.CtIf) CtConstructor(spoon.reflect.declaration.CtConstructor) CtClass(spoon.reflect.declaration.CtClass) CtConstructorCall(spoon.reflect.code.CtConstructorCall) CtAnonymousExecutable(spoon.reflect.declaration.CtAnonymousExecutable) CtMethod(spoon.reflect.declaration.CtMethod) Test(org.junit.Test)

Example 23 with CtLocalVariable

use of spoon.reflect.code.CtLocalVariable 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 24 with CtLocalVariable

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

the class CtLocalVariableReferenceImpl method getDeclaration.

@SuppressWarnings("unchecked")
@Override
public CtLocalVariable<T> getDeclaration() {
    // without a factory, we are not able to filter for local variables
    final Factory factory = getFactory();
    if (factory == null) {
        return null;
    }
    final String simpleName = getSimpleName();
    // handle the CtLocalVariableReference which were created by CtLocalVariable#getReference() and which are not yet part of model, so we cannot found them using standard rules
    if (parent instanceof CtLocalVariable) {
        CtLocalVariable<T> var = (CtLocalVariable<T>) parent;
        if (simpleName.equals(var.getSimpleName())) {
            return var;
        }
    }
    try {
        // successively iterate through all parents of this reference and
        // return first result (which must be the closest declaration
        // respecting visible scope)
        CtVariable<?> var = map(new PotentialVariableDeclarationFunction(simpleName)).first();
        if (var instanceof CtLocalVariable) {
            return (CtLocalVariable<T>) var;
        }
        if (var != null) {
            // handle it as not found
            return null;
        }
    } catch (ParentNotInitializedException e) {
    // handle this case as 'not found'
    }
    return null;
}
Also used : ParentNotInitializedException(spoon.reflect.declaration.ParentNotInitializedException) PotentialVariableDeclarationFunction(spoon.reflect.visitor.filter.PotentialVariableDeclarationFunction) Factory(spoon.reflect.factory.Factory) CtLocalVariable(spoon.reflect.code.CtLocalVariable)

Example 25 with CtLocalVariable

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

the class ImportTest method testImportStaticAndFieldAccess.

@Test
public void testImportStaticAndFieldAccess() throws Exception {
    // contract: Qualified field access and an import static should rewrite in fully qualified mode.
    final Launcher launcher = new Launcher();
    launcher.setArgs(new String[] { "--output-type", "nooutput" });
    launcher.addInputResource("./src/test/java/spoon/test/imports/testclasses/internal4/");
    launcher.addInputResource("./src/test/java/spoon/test/imports/testclasses/Tacos.java");
    launcher.buildModel();
    final CtType<Object> aTacos = launcher.getFactory().Type().get(Tacos.class);
    final CtStatement assignment = aTacos.getMethod("m").getBody().getStatement(0);
    assertTrue(assignment instanceof CtLocalVariable);
    assertEquals("spoon.test.imports.testclasses.internal4.Constants.CONSTANT.foo", ((CtLocalVariable) assignment).getAssignment().toString());
}
Also used : CtStatement(spoon.reflect.code.CtStatement) Launcher(spoon.Launcher) CtLocalVariable(spoon.reflect.code.CtLocalVariable) Test(org.junit.Test)

Aggregations

CtLocalVariable (spoon.reflect.code.CtLocalVariable)29 Test (org.junit.Test)21 Factory (spoon.reflect.factory.Factory)15 Launcher (spoon.Launcher)10 CtParameter (spoon.reflect.declaration.CtParameter)7 CtTypeReference (spoon.reflect.reference.CtTypeReference)7 TypeFilter (spoon.reflect.visitor.filter.TypeFilter)7 CtStatement (spoon.reflect.code.CtStatement)6 CtClass (spoon.reflect.declaration.CtClass)6 CtMethod (spoon.reflect.declaration.CtMethod)6 CtElement (spoon.reflect.declaration.CtElement)5 CtLocalVariableReference (spoon.reflect.reference.CtLocalVariableReference)5 List (java.util.List)4 CtComment (spoon.reflect.code.CtComment)4 CtTry (spoon.reflect.code.CtTry)4 CtField (spoon.reflect.declaration.CtField)4 CtType (spoon.reflect.declaration.CtType)4 CtAssignment (spoon.reflect.code.CtAssignment)3 CtCatchVariable (spoon.reflect.code.CtCatchVariable)3 CtExpression (spoon.reflect.code.CtExpression)3