Skip to content

Commit

Permalink
add query factory and use it
Browse files Browse the repository at this point in the history
  • Loading branch information
pvojtechovsky committed Jan 11, 2017
1 parent 954c371 commit 8833c26
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 14 deletions.
12 changes: 12 additions & 0 deletions src/main/java/spoon/reflect/factory/Factory.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
import spoon.reflect.reference.CtUnboundVariableReference;
import spoon.reflect.reference.CtVariableReference;
import spoon.reflect.reference.CtWildcardReference;
import spoon.reflect.visitor.chain.CtQuery;

import java.lang.annotation.Annotation;
import java.util.List;
Expand Down Expand Up @@ -150,6 +151,8 @@ public interface Factory {

ConstructorFactory Constructor(); // used 3 times

QueryFactory Query();

/**
* @see CodeFactory#createAnnotation(CtTypeReference)
*/
Expand Down Expand Up @@ -762,4 +765,13 @@ public interface Factory {
*/
CtTypeParameterReference createTypeParameterReference(String name);

/**
* @see QueryFactory#createQuery()
*/
CtQuery createQuery();

/**
* @see QueryFactory#createQuery(Object))
*/
CtQuery createQuery(Object input);
}
23 changes: 23 additions & 0 deletions src/main/java/spoon/reflect/factory/FactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
import spoon.reflect.reference.CtUnboundVariableReference;
import spoon.reflect.reference.CtVariableReference;
import spoon.reflect.reference.CtWildcardReference;
import spoon.reflect.visitor.chain.CtQuery;
import spoon.support.DefaultCoreFactory;
import spoon.support.StandardEnvironment;

Expand Down Expand Up @@ -335,6 +336,19 @@ public TypeFactory Type() {
return type;
}

private transient QueryFactory query;

/**
* The query sub-factory.
*/
@Override
public QueryFactory Query() {
if (query == null) {
query = new QueryFactory(this);
}
return query;
}

/**
* A constructor that takes the parent factory
*/
Expand Down Expand Up @@ -1024,4 +1038,13 @@ public CtTypeParameterReference createTypeParameterReference(String name) {
return Type().createTypeParameterReference(name);
}

@Override
public CtQuery createQuery() {
return Query().createQuery();
}

@Override
public CtQuery createQuery(Object input) {
return Query().createQuery(input);
}
}
51 changes: 51 additions & 0 deletions src/main/java/spoon/reflect/factory/QueryFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Copyright (C) 2006-2016 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.reflect.factory;

import spoon.reflect.visitor.chain.CtQuery;
import spoon.reflect.visitor.chain.CtQueryImpl;

/**
* A factory to create some queries on the Spoon metamodel.
*/
public class QueryFactory extends SubFactory {

/**
* Creates the evaluation factory.
*/
public QueryFactory(Factory factory) {
super(factory);
}

/**
* Creates a unbound query. Use {@link CtQuery#setInput(Object...)}
* before {@link CtQuery#forEach(spoon.reflect.visitor.chain.CtConsumer)}
* or {@link CtQuery#list()} is called
*/
public CtQuery createQuery() {
return new CtQueryImpl();
}

/**
* Creates a bound query. Use directly
* {@link CtQuery#forEach(spoon.reflect.visitor.chain.CtConsumer)}
* or {@link CtQuery#list()} to evaluate the query
*/
public CtQuery createQuery(Object input) {
return new CtQueryImpl(input);
}
}
11 changes: 7 additions & 4 deletions src/main/java/spoon/support/SerializationModelStreamer.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import spoon.reflect.declaration.CtElement;
import spoon.reflect.factory.Factory;
import spoon.reflect.visitor.CtScanner;
import spoon.reflect.visitor.Filter;

import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -51,13 +52,15 @@ public Factory load(InputStream in) throws IOException {
try {
ObjectInputStream ois = new ObjectInputStream(in);
final Factory f = (Factory) ois.readObject();
new CtScanner() {
//create query using factory directly
//because any try to call CtElement#map or CtElement#filterChildren will fail on uninitialized factory
f.createQuery(f.getModel().getRootPackage()).filterChildren(new Filter<CtElement>() {
@Override
public void enter(CtElement e) {
public boolean matches(CtElement e) {
e.setFactory(f);
super.enter(e);
return false;
}
}.scan(f.Package().getAll());
}).list();
ois.close();
return f;
} catch (ClassNotFoundException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import spoon.reflect.visitor.Filter;
import spoon.reflect.visitor.ModelConsistencyChecker;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.chain.CtQueryImpl;
import spoon.reflect.visitor.chain.CtFunction;
import spoon.reflect.visitor.chain.CtConsumableFunction;
import spoon.reflect.visitor.chain.CtQuery;
Expand Down Expand Up @@ -261,17 +260,17 @@ public <E extends CtElement> List<E> getElements(Filter<E> filter) {

@Override
public <I> CtQuery map(CtConsumableFunction<I> queryStep) {
return new CtQueryImpl(this).map(queryStep);
return factory.Query().createQuery(this).map(queryStep);
}

@Override
public <I, R> CtQuery map(CtFunction<I, R> function) {
return new CtQueryImpl(this).map(function);
return factory.Query().createQuery(this).map(function);
}

@Override
public <P extends CtElement> CtQuery filterChildren(Filter<P> predicate) {
return new CtQueryImpl(this).filterChildren(predicate);
return factory.Query().createQuery(this).filterChildren(predicate);
}

public <T extends CtReference> List<T> getReferences(Filter<T> filter) {
Expand Down
12 changes: 6 additions & 6 deletions src/test/java/spoon/test/filters/FilterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ public void testElementMapFunction() throws Exception {
public void testElementMapFunctionOtherContracts() throws Exception {
// contract: when a function returns an array, all non-null values are sent to the next step
final Launcher launcher = new Launcher();
CtQueryImpl q = new CtQueryImpl().map((String s)->new String[]{"a", null, s});
CtQuery q = launcher.getFactory().Query().createQuery().map((String s)->new String[]{"a", null, s});
List<String> list = q.setInput(null).list();
assertEquals(0, list.size());

Expand All @@ -642,14 +642,14 @@ public void testElementMapFunctionOtherContracts() throws Exception {
assertEquals("c", list.get(1));

// contract: when input is null then the query function is not called at all.
CtQueryImpl q2 = new CtQueryImpl().map((String s)->{ throw new AssertionError();});
CtQuery q2 = launcher.getFactory().Query().createQuery().map((String s)->{ throw new AssertionError();});
assertEquals(0, q2.setInput(null).list().size());
}
@Test
public void testElementMapFunctionNull() throws Exception {
// contract: when a function returns null, it is discarded at the next step
final Launcher launcher = new Launcher();
CtQueryImpl q = new CtQueryImpl().map((String s)->null);
CtQuery q = launcher.getFactory().Query().createQuery().map((String s)->null);
List<String> list = q.setInput("c").list();
assertEquals(0, list.size());
}
Expand Down Expand Up @@ -692,7 +692,7 @@ public void testReuseOfBaseQuery() throws Exception {
CtClass<?> cls2 = launcher.getFactory().Class().get(Tostada.class);

// here is the query
CtQuery q = new CtQueryImpl().map((CtClass c) -> c.getSimpleName());
CtQuery q = launcher.getFactory().Query().createQuery().map((CtClass c) -> c.getSimpleName());
// using it on a first input
assertEquals("Tacos", q.setInput(cls).list().get(0));
// using it on a second input
Expand Down Expand Up @@ -744,7 +744,7 @@ class Context {
CtClass<?> cls = launcher.getFactory().Class().get(Tacos.class);

// first query
CtQuery allChildPublicClasses = new CtQueryImpl().filterChildren((CtClass clazz)->clazz.hasModifier(ModifierKind.PUBLIC));
CtQuery allChildPublicClasses = launcher.getFactory().Query().createQuery().filterChildren((CtClass clazz)->clazz.hasModifier(ModifierKind.PUBLIC));

// second query,involving the first query
CtQuery q = launcher.getFactory().Package().getRootPackage().map((CtElement in)->allChildPublicClasses.setInput(in).list());
Expand All @@ -759,7 +759,7 @@ class Context {
context.count=0; //reset

// again second query, but now with CtConsumableFunction
CtQuery q2 = launcher.getFactory().Package().getRootPackage().map((CtElement in, CtConsumer<Object> out)->allChildPublicClasses.setInput(in).forEach(x -> out.accept(x)));
CtQuery q2 = launcher.getFactory().Package().getRootPackage().map((CtElement in, CtConsumer<Object> out)->allChildPublicClasses.setInput(in).forEach(out));

// now the assertions
q2.forEach((CtElement clazz)->{
Expand Down

0 comments on commit 8833c26

Please sign in to comment.