Search in sources :

Example 1 with MMMethod

use of spoon.test.metamodel.MMMethod 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 2 with MMMethod

use of spoon.test.metamodel.MMMethod 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)

Aggregations

ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 CtRole (spoon.reflect.path.CtRole)2 MMMethod (spoon.test.metamodel.MMMethod)2 SpoonMetaModel (spoon.test.metamodel.SpoonMetaModel)2 File (java.io.File)1 FileOutputStream (java.io.FileOutputStream)1 IOException (java.io.IOException)1 OutputStreamWriter (java.io.OutputStreamWriter)1 Writer (java.io.Writer)1 HashSet (java.util.HashSet)1 Test (org.junit.Test)1 Launcher (spoon.Launcher)1 CtInvocation (spoon.reflect.code.CtInvocation)1 CtNewArray (spoon.reflect.code.CtNewArray)1 CtClass (spoon.reflect.declaration.CtClass)1 CtMethod (spoon.reflect.declaration.CtMethod)1 PrinterHelper (spoon.reflect.visitor.PrinterHelper)1 TypeFilter (spoon.reflect.visitor.filter.TypeFilter)1 MMMethodKind (spoon.test.metamodel.MMMethodKind)1