Search in sources :

Example 1 with TemplateMatcher

use of spoon.template.TemplateMatcher in project spoon by INRIA.

the class TemplateTest method testTemplateMatcherWithWholePackage.

@Test
public void testTemplateMatcherWithWholePackage() throws Exception {
    Launcher spoon = new Launcher();
    spoon.addInputResource("./src/test/java/spoon/test/template/testclasses/ContextHelper.java");
    spoon.addInputResource("./src/test/java/spoon/test/template/testclasses/BServiceImpl.java");
    spoon.addTemplateResource(new FileSystemFile("./src/test/java/spoon/test/template/testclasses/SecurityCheckerTemplate.java"));
    spoon.buildModel();
    Factory factory = spoon.getFactory();
    CtClass<?> templateKlass = factory.Class().get(SecurityCheckerTemplate.class);
    CtMethod templateMethod = (CtMethod) templateKlass.getElements(new NamedElementFilter<>(CtMethod.class, "matcher1")).get(0);
    CtIf templateRoot = (CtIf) templateMethod.getBody().getStatement(0);
    TemplateMatcher matcher = new TemplateMatcher(templateRoot);
    List<CtElement> matches = matcher.find(factory.getModel().getRootPackage());
    assertEquals(1, matches.size());
    CtElement match = matches.get(0);
    assertTrue("Match is not a if", match instanceof CtIf);
    CtElement matchParent = match.getParent();
    assertTrue("Match parent is not a block", matchParent instanceof CtBlock);
    CtElement matchParentParent = matchParent.getParent();
    assertTrue("Match grand parent is not a method", matchParentParent instanceof CtMethod);
    CtMethod methodHello = (CtMethod) matchParentParent;
    assertEquals("Match grand parent is not a method called hello", "hello", methodHello.getSimpleName());
    CtElement methodParent = methodHello.getParent();
    assertTrue("Parent of the method is not a class", methodParent instanceof CtClass);
    CtClass bservice = (CtClass) methodParent;
    assertEquals("Parent of the method is not a class called BServiceImpl", "BServiceImpl", bservice.getSimpleName());
}
Also used : CtClass(spoon.reflect.declaration.CtClass) CtBlock(spoon.reflect.code.CtBlock) CtElement(spoon.reflect.declaration.CtElement) TemplateMatcher(spoon.template.TemplateMatcher) Launcher(spoon.Launcher) Factory(spoon.reflect.factory.Factory) FileSystemFile(spoon.support.compiler.FileSystemFile) CtMethod(spoon.reflect.declaration.CtMethod) CtIf(spoon.reflect.code.CtIf) Test(org.junit.Test)

Example 2 with TemplateMatcher

use of spoon.template.TemplateMatcher 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 3 with TemplateMatcher

use of spoon.template.TemplateMatcher in project spoon by INRIA.

the class TemplateTest method testTemplateMatcherMatchTwoSnippets.

@Test
public void testTemplateMatcherMatchTwoSnippets() throws Exception {
    Launcher spoon = new Launcher();
    spoon.addInputResource("./src/test/java/spoon/test/template/testclasses/TwoSnippets.java");
    spoon.addTemplateResource(new FileSystemFile("./src/test/java/spoon/test/template/testclasses/SecurityCheckerTemplate.java"));
    spoon.buildModel();
    Factory factory = spoon.getFactory();
    CtClass<?> templateKlass = factory.Class().get(SecurityCheckerTemplate.class);
    CtMethod templateMethod = (CtMethod) templateKlass.getElements(new NamedElementFilter<>(CtMethod.class, "matcher1")).get(0);
    CtIf templateRoot = (CtIf) templateMethod.getBody().getStatement(0);
    TemplateMatcher matcher = new TemplateMatcher(templateRoot);
    // match using legacy TemplateMatcher#find method
    List<CtElement> matches = matcher.find(factory.getModel().getRootPackage());
    assertEquals(2, matches.size());
    CtElement match1 = matches.get(0);
    CtElement match2 = matches.get(1);
    assertTrue(match1.equals(match2));
    // match using TemplateMatcher#matches method and query filter
    matches = factory.getModel().filterChildren(matcher).list();
    assertEquals(2, matches.size());
    match1 = matches.get(0);
    match2 = matches.get(1);
    assertTrue(match1.equals(match2));
}
Also used : CtElement(spoon.reflect.declaration.CtElement) TemplateMatcher(spoon.template.TemplateMatcher) Launcher(spoon.Launcher) Factory(spoon.reflect.factory.Factory) FileSystemFile(spoon.support.compiler.FileSystemFile) CtMethod(spoon.reflect.declaration.CtMethod) CtIf(spoon.reflect.code.CtIf) Test(org.junit.Test)

Example 4 with TemplateMatcher

use of spoon.template.TemplateMatcher in project spoon by INRIA.

the class TemplateTest method testTemplateMatcher.

@Test
public void testTemplateMatcher() throws Exception {
    // contract: the given templates should match the expected elements
    Launcher spoon = new Launcher();
    Factory factory = spoon.getFactory();
    spoon.createCompiler(factory, SpoonResourceHelper.resources("./src/test/java/spoon/test/template/testclasses/bounds/CheckBound.java"), SpoonResourceHelper.resources("./src/test/java/spoon/test/template/testclasses/bounds/CheckBoundMatcher.java")).build();
    {
        // testing matcher1
        CtClass<?> templateKlass = factory.Class().get(CheckBoundMatcher.class);
        CtClass<?> klass = factory.Class().get(CheckBound.class);
        CtIf templateRoot = (CtIf) ((CtMethod) templateKlass.getElements(new NamedElementFilter<>(CtMethod.class, "matcher1")).get(0)).getBody().getStatement(0);
        TemplateMatcher matcher = new TemplateMatcher(templateRoot);
        assertEquals(2, matcher.find(klass).size());
        assertThat(asList("foo", "fbar"), is(klass.filterChildren(matcher).map((CtElement e) -> e.getParent(CtMethod.class).getSimpleName()).list()));
    }
    {
        // testing matcher2
        CtClass<?> templateKlass = factory.Class().get(CheckBoundMatcher.class);
        CtClass<?> klass = factory.Class().get(CheckBound.class);
        CtIf templateRoot = (CtIf) ((CtMethod) templateKlass.getElements(new NamedElementFilter<>(CtMethod.class, "matcher2")).get(0)).getBody().getStatement(0);
        TemplateMatcher matcher = new TemplateMatcher(templateRoot);
        assertEquals(1, matcher.find(klass).size());
        assertThat(asList("bov"), is(klass.filterChildren(matcher).map((CtElement e) -> e.getParent(CtMethod.class).getSimpleName()).list()));
    }
    {
        // testing matcher3
        CtClass<?> templateKlass = factory.Class().get(CheckBoundMatcher.class);
        CtClass<?> klass = factory.Class().get(CheckBound.class);
        CtIf templateRoot = (CtIf) ((CtMethod) templateKlass.getElements(new NamedElementFilter<>(CtMethod.class, "matcher3")).get(0)).getBody().getStatement(0);
        TemplateMatcher matcher = new TemplateMatcher(templateRoot);
        assertEquals(2, matcher.find(klass).size());
        assertThat(asList("foo", "fbar"), is(klass.filterChildren(matcher).map((CtElement e) -> e.getParent(CtMethod.class).getSimpleName()).list()));
    }
    {
        // testing matcher4
        CtClass<?> templateKlass = factory.Class().get(CheckBoundMatcher.class);
        CtClass<?> klass = factory.Class().get(CheckBound.class);
        CtIf templateRoot = (CtIf) ((CtMethod) templateKlass.getElements(new NamedElementFilter<>(CtMethod.class, "matcher4")).get(0)).getBody().getStatement(0);
        TemplateMatcher matcher = new TemplateMatcher(templateRoot);
        assertEquals(3, matcher.find(klass).size());
        assertThat(asList("foo", "foo2", "fbar"), is(klass.filterChildren(matcher).map((CtElement e) -> e.getParent(CtMethod.class).getSimpleName()).list()));
    }
    {
        // testing matcher5
        CtClass<?> templateKlass = factory.Class().get(CheckBoundMatcher.class);
        CtClass<?> klass = factory.Class().get(CheckBound.class);
        CtIf templateRoot = (CtIf) ((CtMethod) templateKlass.getElements(new NamedElementFilter<>(CtMethod.class, "matcher5")).get(0)).getBody().getStatement(0);
        TemplateMatcher matcher = new TemplateMatcher(templateRoot);
        assertEquals(6, matcher.find(klass).size());
        assertThat(asList("foo", "foo2", "fbar", "baz", "bou", "bov"), is(klass.filterChildren(matcher).map((CtElement e) -> e.getParent(CtMethod.class).getSimpleName()).list()));
    }
    {
        // testing matcher6
        CtClass<?> templateKlass = factory.Class().get(CheckBoundMatcher.class);
        CtClass<?> klass = factory.Class().get(CheckBound.class);
        CtIf templateRoot = (CtIf) ((CtMethod) templateKlass.getElements(new NamedElementFilter<>(CtMethod.class, "matcher6")).get(0)).getBody().getStatement(0);
        TemplateMatcher matcher = new TemplateMatcher(templateRoot);
        assertEquals(2, matcher.find(klass).size());
        assertThat(asList("baz", "bou"), is(klass.filterChildren(matcher).map((CtElement e) -> e.getParent(CtMethod.class).getSimpleName()).list()));
    }
    // testing with named elements, at the method level
    {
        CtClass<?> templateKlass = factory.Class().get(CheckBoundMatcher.class);
        CtClass<?> klass = factory.Class().get(CheckBound.class);
        CtMethod meth = (CtMethod) templateKlass.getElements(new NamedElementFilter<>(CtMethod.class, "matcher3")).get(0);
        // exact match
        meth.setSimpleName("foo");
        TemplateMatcher matcher = new TemplateMatcher(meth);
        List<CtMethod> ctElements = matcher.find(klass);
        assertEquals(1, ctElements.size());
        assertEquals("foo", ctElements.get(0).getSimpleName());
    }
    {
        // contract: the name to be matched does not have to be an exact match
        CtClass<?> templateKlass = factory.Class().get(CheckBoundMatcher.class);
        CtClass<?> klass = factory.Class().get(CheckBound.class);
        CtMethod meth = (CtMethod) templateKlass.getElements(new NamedElementFilter<>(CtMethod.class, "matcher5")).get(0);
        // together with the appropriate @Parameter _w_, this means
        // we match all methods with name f*, because parameter _w_ acts as a wildcard
        meth.setSimpleName("f_w_");
        TemplateMatcher matcher = new TemplateMatcher(meth);
        List<CtMethod> ctElements = matcher.find(klass);
        assertEquals(3, ctElements.size());
        assertEquals("foo", ctElements.get(0).getSimpleName());
        assertEquals("foo2", ctElements.get(1).getSimpleName());
        assertEquals("fbar", ctElements.get(2).getSimpleName());
    }
}
Also used : CheckBoundMatcher(spoon.test.template.testclasses.bounds.CheckBoundMatcher) CtClass(spoon.reflect.declaration.CtClass) CheckBound(spoon.test.template.testclasses.bounds.CheckBound) CtElement(spoon.reflect.declaration.CtElement) NamedElementFilter(spoon.reflect.visitor.filter.NamedElementFilter) TemplateMatcher(spoon.template.TemplateMatcher) Launcher(spoon.Launcher) Factory(spoon.reflect.factory.Factory) Arrays.asList(java.util.Arrays.asList) List(java.util.List) ArrayList(java.util.ArrayList) CtIf(spoon.reflect.code.CtIf) CtMethod(spoon.reflect.declaration.CtMethod) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)4 Launcher (spoon.Launcher)4 CtIf (spoon.reflect.code.CtIf)4 CtElement (spoon.reflect.declaration.CtElement)4 CtMethod (spoon.reflect.declaration.CtMethod)4 Factory (spoon.reflect.factory.Factory)4 TemplateMatcher (spoon.template.TemplateMatcher)4 ArrayList (java.util.ArrayList)2 List (java.util.List)2 CtClass (spoon.reflect.declaration.CtClass)2 FileSystemFile (spoon.support.compiler.FileSystemFile)2 Arrays.asList (java.util.Arrays.asList)1 Function (java.util.function.Function)1 CtBlock (spoon.reflect.code.CtBlock)1 CtStatement (spoon.reflect.code.CtStatement)1 CtParameter (spoon.reflect.declaration.CtParameter)1 CtType (spoon.reflect.declaration.CtType)1 CtVisitor (spoon.reflect.visitor.CtVisitor)1 NamedElementFilter (spoon.reflect.visitor.filter.NamedElementFilter)1 TypeFilter (spoon.reflect.visitor.filter.TypeFilter)1