Search in sources :

Example 91 with CtType

use of spoon.reflect.declaration.CtType in project spoon by INRIA.

the class APITest method testSetterInNodes.

@Test
public void testSetterInNodes() throws Exception {
    // that the new value is != null to avoid NPE when we set the parent.
    class SetterMethodWithoutCollectionsFilter extends TypeFilter<CtMethod<?>> {

        private final List<CtTypeReference<?>> collections = new ArrayList<>(4);

        public SetterMethodWithoutCollectionsFilter(Factory factory) {
            super(CtMethod.class);
            for (Class<?> aCollectionClass : Arrays.asList(Collection.class, List.class, Map.class, Set.class)) {
                collections.add(factory.Type().createReference(aCollectionClass));
            }
        }

        @Override
        public boolean matches(CtMethod<?> element) {
            boolean isSetter = isSetterMethod(element);
            boolean isNotSubType = !isSubTypeOfCollection(element);
            // setter with unsettableProperty should not respect the contract, as well as derived properties
            boolean doesNotHaveUnsettableAnnotation = doesNotHaveUnsettableAnnotation(element);
            boolean isNotSetterForADerivedProperty = isNotSetterForADerivedProperty(element);
            boolean superMatch = super.matches(element);
            return isSetter && doesNotHaveUnsettableAnnotation && isNotSetterForADerivedProperty && isNotSubType && superMatch;
        }

        private boolean isNotSetterForADerivedProperty(CtMethod<?> method) {
            String methodName = method.getSimpleName();
            String getterName = methodName.replace("set", "get");
            if (getterName.equals(methodName)) {
                return false;
            }
            CtType<?> zeClass = (CtType) method.getParent();
            List<CtMethod<?>> getterMethods = zeClass.getMethodsByName(getterName);
            if (getterMethods.size() != 1) {
                return false;
            }
            CtMethod<?> getterMethod = getterMethods.get(0);
            return (getterMethod.getAnnotation(DerivedProperty.class) == null);
        }

        private boolean doesNotHaveUnsettableAnnotation(CtMethod<?> element) {
            return (element.getAnnotation(UnsettableProperty.class) == null);
        }

        private boolean isSubTypeOfCollection(CtMethod<?> element) {
            final List<CtParameter<?>> parameters = element.getParameters();
            if (parameters.size() != 1) {
                return false;
            }
            final CtTypeReference<?> type = parameters.get(0).getType();
            for (CtTypeReference<?> aCollectionRef : collections) {
                if (type.isSubtypeOf(aCollectionRef) || type.equals(aCollectionRef)) {
                    return true;
                }
            }
            return false;
        }

        private boolean isSetterMethod(CtMethod<?> element) {
            final List<CtParameter<?>> parameters = element.getParameters();
            if (parameters.size() != 1) {
                return false;
            }
            final CtTypeReference<?> typeParameter = parameters.get(0).getType();
            final CtTypeReference<CtElement> ctElementRef = element.getFactory().Type().createReference(CtElement.class);
            // isSubtypeOf will return true in case of equality
            boolean isSubtypeof = typeParameter.isSubtypeOf(ctElementRef);
            if (!isSubtypeof) {
                return false;
            }
            return element.getSimpleName().startsWith("set") && element.getDeclaringType().getSimpleName().startsWith("Ct") && element.getBody() != null;
        }
    }
    class CheckNotNullToSetParentMatcher extends CtElementImpl {

        public TemplateParameter<CtVariableAccess<?>> _parameter_access_;

        public void matcher() {
            if (_parameter_access_.S() != null) {
                _parameter_access_.S().setParent(this);
            }
        }

        @Override
        @Local
        public void accept(CtVisitor visitor) {
        }
    }
    final Launcher launcher = new Launcher();
    launcher.setArgs(new String[] { "--output-type", "nooutput" });
    launcher.getEnvironment().setNoClasspath(true);
    // Implementations
    launcher.addInputResource("./src/main/java/spoon/support/reflect/code");
    launcher.addInputResource("./src/main/java/spoon/support/reflect/declaration");
    launcher.addInputResource("./src/main/java/spoon/support/reflect/reference");
    launcher.addInputResource("./src/test/java/" + this.getClass().getCanonicalName().replace(".", "/") + ".java");
    // Needed for #isSubTypeOf method.
    launcher.addInputResource("./src/main/java/spoon/reflect/");
    launcher.buildModel();
    // Template matcher.
    CtClass<CheckNotNullToSetParentMatcher> matcherCtClass = launcher.getFactory().Class().get(CheckNotNullToSetParentMatcher.class);
    CtIf templateRoot = matcherCtClass.getMethod("matcher").getBody().getStatement(0);
    final List<CtMethod<?>> setters = Query.getElements(launcher.getFactory(), new SetterMethodWithoutCollectionsFilter(launcher.getFactory()));
    assertTrue("Number of setters found null", setters.size() > 0);
    for (CtStatement statement : setters.stream().map((Function<CtMethod<?>, CtStatement>) ctMethod -> ctMethod.getBody().getStatement(0)).collect(Collectors.toList())) {
        // First statement should be a condition to protect the setter of the parent.
        assertTrue("Check the method " + statement.getParent(CtMethod.class).getSignature() + " in the declaring class " + statement.getParent(CtType.class).getQualifiedName(), statement instanceof CtIf);
        CtIf ifCondition = (CtIf) statement;
        TemplateMatcher matcher = new TemplateMatcher(templateRoot);
        assertEquals("Check the number of if in method " + statement.getParent(CtMethod.class).getSignature() + " in the declaring class " + statement.getParent(CtType.class).getQualifiedName(), 1, matcher.find(ifCondition).size());
    }
}
Also used : Factory(spoon.reflect.factory.Factory) CtParameter(spoon.reflect.declaration.CtParameter) TypeFilter(spoon.reflect.visitor.filter.TypeFilter) Function(java.util.function.Function) CtStatement(spoon.reflect.code.CtStatement) List(java.util.List) ArrayList(java.util.ArrayList) CtVisitor(spoon.reflect.visitor.CtVisitor) CtElement(spoon.reflect.declaration.CtElement) CtIf(spoon.reflect.code.CtIf) TemplateParameter(spoon.template.TemplateParameter) CtElementImpl(spoon.support.reflect.declaration.CtElementImpl) CtType(spoon.reflect.declaration.CtType) TemplateMatcher(spoon.template.TemplateMatcher) Launcher(spoon.Launcher) CtMethod(spoon.reflect.declaration.CtMethod) Test(org.junit.Test)

Example 92 with CtType

use of spoon.reflect.declaration.CtType in project spoon by INRIA.

the class MetamodelTest method testRoleOnField.

@Test
public void testRoleOnField() {
    // contract: all non-final fields must be annotated with {@link spoon.reflect.annotations.MetamodelPropertyField}
    SpoonAPI implementations = new Launcher();
    implementations.addInputResource("src/main/java/spoon/support/reflect");
    implementations.buildModel();
    Factory factory = implementations.getFactory();
    CtTypeReference metamodelPropertyField = factory.Type().get(MetamodelPropertyField.class).getReference();
    final List<String> result = new ArrayList();
    List<CtField> fieldWithoutAnnotation = (List<CtField>) implementations.getModel().getElements(new TypeFilter<CtField>(CtField.class) {

        @Override
        public boolean matches(CtField candidate) {
            if (candidate.hasModifier(ModifierKind.FINAL) || candidate.hasModifier(ModifierKind.STATIC) || candidate.hasModifier(ModifierKind.TRANSIENT)) {
                return false;
            }
            if (// not a role
            "parent".equals(candidate.getSimpleName()) || "metadata".equals(candidate.getSimpleName()) || // cache field
            "valueOfMethod".equals(candidate.getSimpleName())) {
                return false;
            }
            CtClass parent = candidate.getParent(CtClass.class);
            return parent != null && (parent.isSubtypeOf(candidate.getFactory().createCtTypeReference(CtReference.class)) || parent.isSubtypeOf(candidate.getFactory().createCtTypeReference(CtElement.class)));
        }
    }).stream().map(x -> {
        result.add(x.toString());
        return x;
    }).filter(f -> f.getAnnotation(metamodelPropertyField) == null).collect(Collectors.toList());
    assertTrue(result.contains("@spoon.reflect.annotations.MetamodelPropertyField(role = spoon.reflect.path.CtRole.IS_SHADOW)\nboolean isShadow;"));
    assertTrue(result.contains("@spoon.reflect.annotations.MetamodelPropertyField(role = spoon.reflect.path.CtRole.TYPE)\nspoon.reflect.reference.CtTypeReference<T> type;"));
    assertTrue(result.size() > 100);
    Assert.assertEquals(Collections.emptyList(), fieldWithoutAnnotation);
    final CtTypeReference propertySetter = factory.Type().get(PropertySetter.class).getReference();
    final CtTypeReference propertyGetter = factory.Type().get(PropertyGetter.class).getReference();
    List<CtField> fields = factory.getModel().getElements(new AnnotationFilter<CtField>(MetamodelPropertyField.class));
    for (CtField field : fields) {
        CtClass parent = field.getParent(CtClass.class);
        CtExpression roleExpression = field.getAnnotation(metamodelPropertyField).getValue("role");
        List<String> roles = new ArrayList<>();
        if (roleExpression instanceof CtFieldRead) {
            roles.add(((CtFieldRead) roleExpression).getVariable().getSimpleName());
        } else if (roleExpression instanceof CtNewArray) {
            List<CtFieldRead> elements = ((CtNewArray) roleExpression).getElements();
            for (int i = 0; i < elements.size(); i++) {
                CtFieldRead ctFieldRead = elements.get(i);
                roles.add(ctFieldRead.getVariable().getSimpleName());
            }
        }
        CtQuery superQuery = parent.map(new SuperInheritanceHierarchyFunction());
        List<CtMethod> methods = superQuery.map((CtType type) -> type.getMethodsAnnotatedWith(propertyGetter, propertySetter)).list();
        boolean setterFound = false;
        boolean getterFound = false;
        for (CtMethod method : methods) {
            CtAnnotation getterAnnotation = method.getAnnotation(propertyGetter);
            CtAnnotation setterAnnotation = method.getAnnotation(propertySetter);
            if (getterAnnotation != null) {
                getterFound |= roles.contains(((CtFieldRead) getterAnnotation.getValue("role")).getVariable().getSimpleName());
            }
            if (setterAnnotation != null) {
                setterFound |= roles.contains(((CtFieldRead) setterAnnotation.getValue("role")).getVariable().getSimpleName());
            }
        }
        assertTrue(roles + " must have a getter in " + parent.getQualifiedName(), getterFound);
        assertTrue(roles + " must have a setter in " + parent.getQualifiedName(), setterFound);
    }
}
Also used : Arrays(java.util.Arrays) Launcher(spoon.Launcher) IsEqual.equalTo(org.hamcrest.core.IsEqual.equalTo) CtRole(spoon.reflect.path.CtRole) ArrayList(java.util.ArrayList) CtType(spoon.reflect.declaration.CtType) CtElement(spoon.reflect.declaration.CtElement) SpoonAPI(spoon.SpoonAPI) CtExpression(spoon.reflect.code.CtExpression) CtNewArray(spoon.reflect.code.CtNewArray) Metamodel(spoon.Metamodel) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) CtQuery(spoon.reflect.visitor.chain.CtQuery) TypeFilter(spoon.reflect.visitor.filter.TypeFilter) CtField(spoon.reflect.declaration.CtField) CtReference(spoon.reflect.reference.CtReference) MetamodelPropertyField(spoon.reflect.annotations.MetamodelPropertyField) SuperInheritanceHierarchyFunction(spoon.reflect.visitor.filter.SuperInheritanceHierarchyFunction) Set(java.util.Set) Assert.assertTrue(org.junit.Assert.assertTrue) Test(org.junit.Test) Factory(spoon.reflect.factory.Factory) PropertySetter(spoon.reflect.annotations.PropertySetter) Collectors(java.util.stream.Collectors) CtTypeReference(spoon.reflect.reference.CtTypeReference) List(java.util.List) CtAnnotation(spoon.reflect.declaration.CtAnnotation) AnnotationFilter(spoon.reflect.visitor.filter.AnnotationFilter) CtClass(spoon.reflect.declaration.CtClass) ModifierKind(spoon.reflect.declaration.ModifierKind) CtFieldRead(spoon.reflect.code.CtFieldRead) Assert(org.junit.Assert) Collections(java.util.Collections) PropertyGetter(spoon.reflect.annotations.PropertyGetter) CtMethod(spoon.reflect.declaration.CtMethod) ArrayList(java.util.ArrayList) Factory(spoon.reflect.factory.Factory) TypeFilter(spoon.reflect.visitor.filter.TypeFilter) CtNewArray(spoon.reflect.code.CtNewArray) CtTypeReference(spoon.reflect.reference.CtTypeReference) CtField(spoon.reflect.declaration.CtField) PropertyGetter(spoon.reflect.annotations.PropertyGetter) ArrayList(java.util.ArrayList) List(java.util.List) SpoonAPI(spoon.SpoonAPI) SuperInheritanceHierarchyFunction(spoon.reflect.visitor.filter.SuperInheritanceHierarchyFunction) CtAnnotation(spoon.reflect.declaration.CtAnnotation) CtFieldRead(spoon.reflect.code.CtFieldRead) CtExpression(spoon.reflect.code.CtExpression) PropertySetter(spoon.reflect.annotations.PropertySetter) CtQuery(spoon.reflect.visitor.chain.CtQuery) MetamodelPropertyField(spoon.reflect.annotations.MetamodelPropertyField) CtClass(spoon.reflect.declaration.CtClass) CtType(spoon.reflect.declaration.CtType) Launcher(spoon.Launcher) CtMethod(spoon.reflect.declaration.CtMethod) Test(org.junit.Test)

Example 93 with CtType

use of spoon.reflect.declaration.CtType in project spoon by INRIA.

the class NoClasspathTest method testInheritanceInNoClassPathWithClasses.

@Test
public void testInheritanceInNoClassPathWithClasses() throws IOException {
    // contract: when using noclasspath in combination with a source classpath
    // spoon is able to resolve the inheritance between classes contained in source cp
    String sourceInputDirPath = "./src/test/resources/spoon/test/inheritance";
    String targetBinPath = "./target/spoon-nocp-bin";
    Launcher spoon = new Launcher();
    spoon.getEnvironment().setShouldCompile(true);
    spoon.addInputResource(sourceInputDirPath);
    spoon.setBinaryOutputDirectory(targetBinPath);
    spoon.run();
    spoon = new Launcher();
    spoon.getEnvironment().setNoClasspath(true);
    spoon.getEnvironment().setSourceClasspath(new String[] { targetBinPath });
    spoon.addInputResource(sourceInputDirPath + "/AnotherClass.java");
    spoon.buildModel();
    CtType anotherclass = spoon.getFactory().Type().get("org.acme.AnotherClass");
    assertEquals(1, anotherclass.getFields().size());
    CtField field = (CtField) anotherclass.getFields().get(0);
    CtTypeReference myClassReference = spoon.getFactory().Type().createReference("fr.acme.MyClass");
    assertEquals(myClassReference, field.getType());
    assertNotNull(myClassReference.getActualClass());
    CtTypeReference myInterfaceReference = spoon.getFactory().Type().createReference("org.myorganization.MyInterface");
    assertTrue(myClassReference.isSubtypeOf(myInterfaceReference));
    assertTrue(field.getType().isSubtypeOf(myInterfaceReference));
}
Also used : CtType(spoon.reflect.declaration.CtType) CtField(spoon.reflect.declaration.CtField) CtTypeReference(spoon.reflect.reference.CtTypeReference) Launcher(spoon.Launcher) Test(org.junit.Test)

Example 94 with CtType

use of spoon.reflect.declaration.CtType in project spoon by INRIA.

the class SpoonArchitectureEnforcerTest method testFactorySubFactory.

@Test
public void testFactorySubFactory() throws Exception {
    // contract:: all subfactory methods must also be in the main factory
    // this is very important for usability and discoverability
    final Launcher launcher = new Launcher();
    launcher.addInputResource("./src/main/java/spoon/reflect/factory");
    class SanityCheck {

        int val = 0;
    }
    ;
    SanityCheck sanityCheck = new SanityCheck();
    launcher.addProcessor(new AbstractManualProcessor() {

        @Override
        public void process() {
            CtType factoryImpl = getFactory().Interface().get(Factory.class);
            CtPackage factoryPackage = getFactory().Package().getOrCreate("spoon.reflect.factory");
            CtInterface itf = getFactory().Interface().create("MegaFactoryItf");
            CtClass impl = getFactory().Class().create("MegaFactory");
            for (CtType<?> t : factoryPackage.getTypes()) {
                // 
                if (t.getSimpleName().startsWith("Mega"))
                    continue;
                for (CtMethod<?> m : t.getMethods()) {
                    // we check only public methods
                    if (m.hasModifier(ModifierKind.PUBLIC) == false)
                        continue;
                    // we only consider factory methods
                    if (!m.getSimpleName().startsWith("create"))
                        continue;
                    // too generic, what should we create??
                    if (m.getSimpleName().equals("create")) {
                        String simpleNameType = m.getType().getSimpleName().replace("Ct", "");
                        CtMethod method = m.clone();
                        method.setSimpleName("create" + simpleNameType);
                        assertTrue(method.getSignature() + " (from " + t.getQualifiedName() + ") is not present in the main factory", factoryImpl.hasMethod(method));
                        continue;
                    }
                    // too generic, is it a fieldref? an execref? etc
                    if (m.getSimpleName().equals("createReference"))
                        continue;
                    if (m.getModifiers().contains(ModifierKind.ABSTRACT))
                        continue;
                    sanityCheck.val++;
                    // the core assertion
                    assertTrue(m.getSignature() + " is not present in the main factory", factoryImpl.hasMethod(m));
                }
            }
        }
    });
    launcher.run();
    assertTrue(sanityCheck.val > 100);
}
Also used : CtInterface(spoon.reflect.declaration.CtInterface) CtClass(spoon.reflect.declaration.CtClass) AbstractManualProcessor(spoon.processing.AbstractManualProcessor) CtType(spoon.reflect.declaration.CtType) Launcher(spoon.Launcher) Factory(spoon.reflect.factory.Factory) CtPackage(spoon.reflect.declaration.CtPackage) CtMethod(spoon.reflect.declaration.CtMethod) Test(org.junit.Test)

Example 95 with CtType

use of spoon.reflect.declaration.CtType in project spoon by INRIA.

the class SpoonTestHelpers method getSetterOf.

/**
 * returns the corresponding setter, if several are possible returns the lowest one in the hierarchy
 */
public static CtMethod<?> getSetterOf(CtType<?> baseType, CtMethod<?> getter) {
    String setterName = getter.getSimpleName().replaceFirst("^get", "set");
    Object[] tentativeSetters = baseType.getAllMethods().stream().filter(x -> x.getSimpleName().equals(setterName)).toArray();
    if (tentativeSetters.length == 0) {
        return null;
    }
    // return one that is as low as possible in the hierarchy
    for (Object o : tentativeSetters) {
        if (baseType.getPackage().getElements(new OverridingMethodFilter((CtMethod<?>) o)).size() == 0) {
            return (CtMethod<?>) o;
        }
    }
    // System.out.println(setterName+" "+tentativeSetters.length);
    return (CtMethod<?>) tentativeSetters[0];
}
Also used : SpoonMetaModel(spoon.test.metamodel.SpoonMetaModel) CtTypeReference(spoon.reflect.reference.CtTypeReference) List(java.util.List) CtType(spoon.reflect.declaration.CtType) CtElement(spoon.reflect.declaration.CtElement) OverridingMethodFilter(spoon.reflect.visitor.filter.OverridingMethodFilter) DerivedProperty(spoon.support.DerivedProperty) File(java.io.File) CtMethod(spoon.reflect.declaration.CtMethod) ArrayList(java.util.ArrayList) OverridingMethodFilter(spoon.reflect.visitor.filter.OverridingMethodFilter) CtMethod(spoon.reflect.declaration.CtMethod)

Aggregations

CtType (spoon.reflect.declaration.CtType)134 Test (org.junit.Test)67 Launcher (spoon.Launcher)60 ArrayList (java.util.ArrayList)42 CtMethod (spoon.reflect.declaration.CtMethod)38 CtTypeReference (spoon.reflect.reference.CtTypeReference)30 DefaultJavaPrettyPrinter (spoon.reflect.visitor.DefaultJavaPrettyPrinter)20 File (java.io.File)19 Factory (spoon.reflect.factory.Factory)19 PrettyPrinter (spoon.reflect.visitor.PrettyPrinter)19 List (java.util.List)18 Collectors (java.util.stream.Collectors)17 CtField (spoon.reflect.declaration.CtField)17 CtElement (spoon.reflect.declaration.CtElement)16 CtPackage (spoon.reflect.declaration.CtPackage)16 InputConfiguration (fr.inria.diversify.utils.sosiefier.InputConfiguration)14 IOException (java.io.IOException)12 SpoonException (spoon.SpoonException)12 DSpotCompiler (fr.inria.diversify.utils.compilation.DSpotCompiler)11 Set (java.util.Set)11