Search in sources :

Example 11 with CtRole

use of spoon.reflect.path.CtRole in project spoon by INRIA.

the class CtScannerTest method testScannerCallsAllProperties.

@Test
public void testScannerCallsAllProperties() throws Exception {
    // contract: CtScanner must visit all metamodel properties and use correct CtRole!
    final Launcher launcher = new Launcher();
    launcher.addInputResource("./src/main/java/spoon/reflect/");
    launcher.run();
    CtTypeReference<?> ctElementRef = launcher.getFactory().createCtTypeReference(CtElement.class);
    CtTypeReference<?> ctRefRef = launcher.getFactory().createCtTypeReference(CtReference.class);
    CtClass<?> scannerCtClass = (CtClass<?>) launcher.getFactory().Type().get(CtScanner.class);
    List<String> problems = new ArrayList<>();
    Set<String> ignoredInvocations = new HashSet(Arrays.asList("scan", "enter", "exit"));
    SpoonMetaModel metaModel = new SpoonMetaModel(new File("./src/main/java"));
    // collect all scanner visit methods, to check if all were checked
    Map<String, CtMethod<?>> scannerVisitMethodsByName = new HashMap<>();
    scannerCtClass.getAllMethods().forEach(m -> {
        if (m.getSimpleName().startsWith("visit")) {
            scannerVisitMethodsByName.put(m.getSimpleName(), m);
        }
    });
    class Counter {

        int nbChecks = 0;
    }
    Counter c = new Counter();
    for (MetamodelConcept leafConcept : metaModel.getConcepts()) {
        // we only consider leaf, actual classes of the metamodel (eg CtInvocation) and not abstract ones (eg CtModifiable)
        if (leafConcept.getKind() != MMTypeKind.LEAF) {
            continue;
        }
        CtMethod<?> visitMethod = scannerVisitMethodsByName.remove("visit" + leafConcept.getName());
        assertNotNull("CtScanner#" + "visit" + leafConcept.getName() + "(...) not found", visitMethod);
        Set<String> calledMethods = new HashSet<>();
        Set<String> checkedMethods = new HashSet<>();
        // go over the roles and the corresponding fields of this type
        leafConcept.getRoleToProperty().forEach((role, mmField) -> {
            if (mmField.isDerived()) {
                // return of the lambda
                return;
            }
            // ignore fields, which doesn't return CtElement
            if (mmField.getItemValueType().isSubtypeOf(ctElementRef) == false) {
                // return of the lambda
                return;
            }
            MMMethod getter = mmField.getMethod(MMMethodKind.GET);
            checkedMethods.add(getter.getSignature());
            // System.out.println("checking "+m.getSignature() +" in "+visitMethod.getSignature());
            // now, we collect at least one invocation to this getter in the visit method
            CtInvocation invocation = visitMethod.filterChildren(new TypeFilter<CtInvocation>(CtInvocation.class) {

                @Override
                public boolean matches(CtInvocation element) {
                    if (ignoredInvocations.contains(element.getExecutable().getSimpleName())) {
                        return false;
                    }
                    calledMethods.add(element.getExecutable().getSignature());
                    return super.matches(element) && element.getExecutable().getSimpleName().equals(getter.getName());
                }
            }).first();
            if (getter.getName().equals("getComments") && leafConcept.getModelInterface().isSubtypeOf(ctRefRef)) {
                // one cannot set comments on references see the @UnsettableProperty of CtReference#setComments
                return;
            }
            // contract: there ia at least one invocation to all non-derived, role-based getters in the visit method of the Scanner
            if (invocation == null) {
                problems.add("no " + getter.getSignature() + " in " + visitMethod);
            } else {
                c.nbChecks++;
                // System.out.println(invocation.toString());
                // contract: the scan method is called with the same role as the one set on field / property
                CtRole expectedRole = metaModel.getRoleOfMethod((CtMethod<?>) invocation.getExecutable().getDeclaration());
                CtInvocation<?> scanInvocation = invocation.getParent(CtInvocation.class);
                String realRoleName = ((CtFieldRead<?>) scanInvocation.getArguments().get(0)).getVariable().getSimpleName();
                if (expectedRole.name().equals(realRoleName) == false) {
                    problems.add("Wrong role " + realRoleName + " used in " + scanInvocation.getPosition());
                }
            }
        });
        calledMethods.removeAll(checkedMethods);
        // contract: CtScanner only calls methods that have a role and the associated getter
        if (calledMethods.size() > 0) {
            problems.add("CtScanner " + visitMethod.getPosition() + " calls unexpected methods: " + calledMethods);
        }
    }
    // contract: all visit* methods in CtScanner have been checked
    if (scannerVisitMethodsByName.isEmpty() == false) {
        problems.add("These CtScanner visit methods were not checked: " + scannerVisitMethodsByName.keySet());
    }
    if (problems.size() > 0) {
        fail(String.join("\n", problems));
    }
    assertTrue("not enough checks", c.nbChecks >= 200);
}
Also used : SpoonMetaModel(spoon.test.metamodel.SpoonMetaModel) MMMethod(spoon.test.metamodel.MMMethod) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) TypeFilter(spoon.reflect.visitor.filter.TypeFilter) CtClass(spoon.reflect.declaration.CtClass) CtInvocation(spoon.reflect.code.CtInvocation) Launcher(spoon.Launcher) CtRole(spoon.reflect.path.CtRole) File(java.io.File) MetamodelConcept(spoon.test.metamodel.MetamodelConcept) CtMethod(spoon.reflect.declaration.CtMethod) HashSet(java.util.HashSet) Test(org.junit.Test)

Example 12 with CtRole

use of spoon.reflect.path.CtRole in project spoon by INRIA.

the class CtScannerTest method testScan.

@Test
public void testScan() throws Exception {
    // contract: all AST nodes are visisted through method "scan"
    Launcher launcher;
    launcher = new Launcher();
    launcher.getEnvironment().setNoClasspath(true);
    launcher.addInputResource("src/test/resources/noclasspath/draw2d");
    launcher.buildModel();
    class Counter {

        int nEnter = 0;

        int nExit = 0;

        int nObject = 0;

        int nElement = 0;

        Deque<CollectionContext> contexts = new ArrayDeque<>();
    }
    ;
    Counter counter = new Counter();
    launcher.getModel().getRootPackage().accept(new CtScanner() {

        @Override
        public void scan(Object o) {
            counter.nObject++;
            super.scan(o);
        }

        @Override
        public void scan(CtElement o) {
            counter.nElement++;
            super.scan(o);
        }

        @Override
        public void enter(CtElement o) {
            counter.nEnter++;
            super.enter(o);
        }

        @Override
        public void exit(CtElement o) {
            counter.nExit++;
            super.exit(o);
        }
    });
    // interesting, this is never called because of covariance, only CtElement or Collection is called
    assertEquals(0, counter.nObject);
    // this is a coarse-grain check to see if the scanner changes
    // no more exec ref in paramref
    assertEquals(3616, counter.nElement);
    assertEquals(2396, counter.nEnter);
    assertEquals(2396, counter.nExit);
    // contract: all AST nodes which are part of Collection or Map are visited first by method "scan(Collection|Map)" and then by method "scan(CtElement)"
    Counter counter2 = new Counter();
    launcher.getModel().getRootPackage().accept(new CtScanner() {

        @Override
        public void scan(Object o) {
            counter2.nObject++;
            super.scan(o);
        }

        @Override
        public void scan(CtRole role, CtElement o) {
            if (o == null) {
                // there is no collection involved in scanning of this single value NULL attribute
                assertNull(counter2.contexts.peek().col);
            } else {
                RoleHandler rh = RoleHandlerHelper.getRoleHandler(o.getParent().getClass(), role);
                if (rh.getContainerKind() == ContainerKind.SINGLE) {
                    // there is no collection involved in scanning of this single value attribute
                    assertNull(counter2.contexts.peek().col);
                } else {
                    counter2.contexts.peek().assertRemoveSame(o);
                }
            }
            counter2.nElement++;
            super.scan(o);
        }

        @Override
        public void scan(CtRole role, Collection<? extends CtElement> elements) {
            // contract: before processed collection is finished before it starts with next collection
            counter2.contexts.peek().initCollection(elements);
            super.scan(role, elements);
            // contract: all elements of collection are processed in previous super.scan call
            counter2.contexts.peek().assertCollectionIsEmpty();
        }

        @Override
        public void scan(CtRole role, Map<String, ? extends CtElement> elements) {
            // contract: before processed collection is finished before it starts with next collection
            counter2.contexts.peek().initCollection(elements.values());
            super.scan(role, elements);
            // contract: all elements of collection are processed in previous super.scan call
            counter2.contexts.peek().assertCollectionIsEmpty();
        }

        @Override
        public void enter(CtElement o) {
            counter2.nEnter++;
            counter2.contexts.push(new CollectionContext());
        }

        @Override
        public void exit(CtElement o) {
            counter2.nExit++;
            counter2.contexts.peek().assertCollectionIsEmpty();
            counter2.contexts.pop();
        }
    });
    assertEquals(counter.nObject, counter2.nObject);
    assertEquals(counter.nElement, counter2.nElement);
    assertEquals(counter.nEnter, counter2.nEnter);
    assertEquals(counter.nExit, counter2.nExit);
}
Also used : CtElement(spoon.reflect.declaration.CtElement) RoleHandler(spoon.reflect.meta.RoleHandler) Deque(java.util.Deque) ArrayDeque(java.util.ArrayDeque) Launcher(spoon.Launcher) CtRole(spoon.reflect.path.CtRole) Test(org.junit.Test)

Example 13 with CtRole

use of spoon.reflect.path.CtRole in project spoon by INRIA.

the class CtModuleImpl method addModuleDirectiveAt.

@Override
public <T extends CtModule> T addModuleDirectiveAt(int position, CtModuleDirective moduleDirective) {
    if (moduleDirective == null) {
        return (T) this;
    }
    if (this.moduleDirectives == CtElementImpl.<CtModuleDirective>emptyList()) {
        this.moduleDirectives = new SortedList<>(new CtLineElementComparator());
    }
    if (!this.moduleDirectives.contains(moduleDirective)) {
        moduleDirective.setParent(this);
        CtRole role = this.computeRoleFromModuleDirectory(moduleDirective);
        getFactory().getEnvironment().getModelChangeListener().onListAdd(this, role, this.moduleDirectives, position, moduleDirective);
        this.moduleDirectives.add(position, moduleDirective);
    }
    return (T) this;
}
Also used : CtLineElementComparator(spoon.support.comparator.CtLineElementComparator) CtRole(spoon.reflect.path.CtRole)

Example 14 with CtRole

use of spoon.reflect.path.CtRole in project spoon by INRIA.

the class RoleHandlersGenerator method process.

@Override
public void process() {
    SpoonMetaModel metaModel = new SpoonMetaModel(getFactory());
    // all root super MMFields
    List<MetamodelProperty> superFields = new ArrayList<>();
    metaModel.getConcepts().forEach(mmConcept -> {
        mmConcept.getRoleToProperty().forEach((role, rim) -> {
            addUniqueObject(superFields, rim.getRootSuperField());
        });
    });
    superFields.sort((a, b) -> {
        int d = a.getRole().name().compareTo(b.getRole().name());
        if (d != 0) {
            return d;
        }
        return a.getOwnerConcept().getName().compareTo(b.getOwnerConcept().getName());
    });
    PrinterHelper concept = new PrinterHelper(getFactory().getEnvironment());
    superFields.forEach(mmField -> {
        concept.write(mmField.getOwnerConcept().getName() + " CtRole." + mmField.getRole().name()).writeln().incTab().write("ItemType: ").write(mmField.getValueType().toString()).writeln();
        for (MMMethodKind mk : MMMethodKind.values()) {
            MMMethod mmMethod = mmField.getMethod(mk);
            if (mmMethod != null) {
                concept.write(mk.name()).write(": ").write(mmMethod.getSignature()).write(" : ").write(mmMethod.getReturnType().toString()).writeln();
            }
        }
        concept.decTab();
        concept.write("----------------------------------------------------------").writeln();
    });
    try (Writer w = new OutputStreamWriter(new FileOutputStream(file("target/report/concept.txt")))) {
        w.write(concept.toString());
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    CtType<?> template = getTemplate("spoon.generating.meta.ModelRoleHandlerTemplate");
    CtClass<?> modelRoleHandlersClass = Substitution.createTypeFromTemplate(TARGET_PACKAGE + ".ModelRoleHandlers", template, new HashMap<>());
    CtNewArray<?> roleHandlersFieldExpr = (CtNewArray<?>) modelRoleHandlersClass.getField("roleHandlers").getDefaultExpression();
    superFields.forEach(rim -> {
        Map<String, Object> params = new HashMap<>();
        params.put("$getterName$", rim.getMethod(MMMethodKind.GET).getName());
        if (rim.getMethod(MMMethodKind.SET) != null) {
            params.put("$setterName$", rim.getMethod(MMMethodKind.SET).getName());
        }
        params.put("$Role$", getFactory().Type().createReference(CtRole.class));
        params.put("ROLE", rim.getRole().name());
        params.put("$TargetType$", rim.getOwnerConcept().getModelInterface().getReference());
        // params.put("AbstractHandler", getFactory().Type().createReference("spoon.reflect.meta.impl.AbstractRoleHandler"));
        params.put("AbstractHandler", getRoleHandlerSuperTypeQName(rim));
        params.put("Node", rim.getOwnerConcept().getModelInterface().getReference());
        params.put("ValueType", fixMainValueType(getRoleHandlerSuperTypeQName(rim).endsWith("SingleHandler") ? rim.getValueType() : rim.getItemValueType()));
        CtClass<?> modelRoleHandlerClass = Substitution.createTypeFromTemplate(getHandlerName(rim), getTemplate("spoon.generating.meta.RoleHandlerTemplate"), params);
        if (rim.getMethod(MMMethodKind.SET) == null) {
            modelRoleHandlerClass.getMethodsByName("setValue").forEach(m -> m.delete());
        }
        modelRoleHandlerClass.addModifier(ModifierKind.STATIC);
        modelRoleHandlersClass.addNestedType(modelRoleHandlerClass);
        roleHandlersFieldExpr.addElement(getFactory().createCodeSnippetExpression("new " + modelRoleHandlerClass.getSimpleName() + "()"));
    });
}
Also used : SpoonMetaModel(spoon.test.metamodel.SpoonMetaModel) MMMethod(spoon.test.metamodel.MMMethod) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) IOException(java.io.IOException) CtNewArray(spoon.reflect.code.CtNewArray) PrinterHelper(spoon.reflect.visitor.PrinterHelper) FileOutputStream(java.io.FileOutputStream) MetamodelProperty(spoon.test.metamodel.MetamodelProperty) CtRole(spoon.reflect.path.CtRole) OutputStreamWriter(java.io.OutputStreamWriter) MMMethodKind(spoon.test.metamodel.MMMethodKind) OutputStreamWriter(java.io.OutputStreamWriter) Writer(java.io.Writer)

Example 15 with CtRole

use of spoon.reflect.path.CtRole in project spoon by INRIA.

the class CtTypeImpl method removeTypeMember.

@Override
public boolean removeTypeMember(CtTypeMember member) {
    CtRole role;
    if (member instanceof CtMethod) {
        role = METHOD;
    } else if (member instanceof CtConstructor) {
        role = CONSTRUCTOR;
    } else if (member instanceof CtField) {
        role = FIELD;
    } else if (member instanceof CtAnonymousExecutable) {
        role = ANNONYMOUS_EXECUTABLE;
    } else {
        role = NESTED_TYPE;
    }
    if (typeMembers.size() == 1) {
        if (typeMembers.contains(member)) {
            getFactory().getEnvironment().getModelChangeListener().onListDelete(this, role, this.typeMembers, this.typeMembers.indexOf(member), member);
            typeMembers = emptyList();
            return true;
        } else {
            return false;
        }
    }
    if (typeMembers.contains(member)) {
        getFactory().getEnvironment().getModelChangeListener().onListDelete(this, role, this.typeMembers, this.typeMembers.indexOf(member), member);
        return typeMembers.remove(member);
    }
    return false;
}
Also used : CtField(spoon.reflect.declaration.CtField) CtRole(spoon.reflect.path.CtRole) CtAnonymousExecutable(spoon.reflect.declaration.CtAnonymousExecutable) CtMethod(spoon.reflect.declaration.CtMethod) CtConstructor(spoon.reflect.declaration.CtConstructor)

Aggregations

CtRole (spoon.reflect.path.CtRole)15 ArrayList (java.util.ArrayList)7 Test (org.junit.Test)6 HashSet (java.util.HashSet)4 CtMethod (spoon.reflect.declaration.CtMethod)4 RoleHandler (spoon.reflect.meta.RoleHandler)4 CtElement (spoon.reflect.declaration.CtElement)3 CtLineElementComparator (spoon.support.comparator.CtLineElementComparator)3 SpoonMetaModel (spoon.test.metamodel.SpoonMetaModel)3 File (java.io.File)2 HashMap (java.util.HashMap)2 Launcher (spoon.Launcher)2 SpoonException (spoon.SpoonException)2 CtBlock (spoon.reflect.code.CtBlock)2 CtAnonymousExecutable (spoon.reflect.declaration.CtAnonymousExecutable)2 CtClass (spoon.reflect.declaration.CtClass)2 CtConstructor (spoon.reflect.declaration.CtConstructor)2 CtField (spoon.reflect.declaration.CtField)2 MMMethod (spoon.test.metamodel.MMMethod)2 MetamodelProperty (spoon.test.metamodel.MetamodelProperty)2