Skip to content

Commit

Permalink
feat(filter): adds LineFilter to reason about statements in blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
tdurieux authored and monperrus committed May 31, 2016
1 parent 7f7fbaf commit 73ff189
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 5 deletions.
3 changes: 2 additions & 1 deletion doc/filter.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Filter
tags: [quering]
keywords: quering, query, filter, ast, elements
last_updated: October 5, 2015
last_updated: May 27, 2016
---

Spoon aims at giving developers a way to query code elements in
Expand Down Expand Up @@ -33,6 +33,7 @@ Filter class | Description
`CompositeFilter` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/visitor/filter/CompositeFilter.html)) | defines a composite filter, which can compose several filters together by using `FilteringOperator` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/visitor/filter/FilteringOperator.html)).
`OverridingMethodFilter` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/visitor/filter/OverridingMethodFilter.html)) | get all overriding methods from the method given.
`OverriddenMethodFilter` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/visitor/filter/OverriddenMethodFilter.html)) | get all overridden methods from the method given.
`LineFilter` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/visitor/filter/LineFilter.html)) | get all elements that can be considered as line of code (e.g. directly contained in a block, or a then statement).

See below a code example about the usage of these filters. Three filters of
them are used. The first returns all AST nodes of type `CtAssignment` ([javadoc](http://spoon.gforge.inria.fr/mvnsites/spoon-core/apidocs/spoon/reflect/code/CtAssignment.html)).
Expand Down
72 changes: 72 additions & 0 deletions src/main/java/spoon/reflect/visitor/filter/LineFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Copyright (C) 2006-2015 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.visitor.filter;

import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtIf;
import spoon.reflect.code.CtLoop;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtStatementList;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.ParentNotInitializedException;

/**
* This filter matches all elements that can be considered as line of code (e.g. directly contained in a block, or a then statement). This discards CtStatement that are not used as statement (such as a method call used as RHS).
* <pre>
* // lines of a method
* List&lt;CtStatement&gt; lines = method.getElements(new LineFilter());
* // find the parent that is used as a statement (in a block or in a branch)
* CtStatement parentStatement = element.getParent(new LineFilter());
* </pre>
*/
public class LineFilter extends TypeFilter<CtStatement> {

/**
* Creates the filter.
*/
public LineFilter() {
super(CtStatement.class);
}

@Override
public boolean matches(CtStatement element) {
if (!super.matches(element)) {
return false;
}
if (element instanceof CtBlock) {
return false;
}
CtElement parent;
try {
parent = element.getParent();
} catch (ParentNotInitializedException e) {
return false;
}
if (parent instanceof CtStatementList) {
return true;
}
if (parent instanceof CtIf) {
CtIf anIf = (CtIf) parent;
return element.equals(anIf.getThenStatement()) || element.equals(anIf.getElseStatement());
}
if (parent instanceof CtLoop) {
CtLoop loop = (CtLoop) parent;
return loop.getBody().equals(element);
}
return false;
}
}
51 changes: 47 additions & 4 deletions src/test/java/spoon/test/filters/FilterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
import org.junit.Before;
import org.junit.Test;
import spoon.Launcher;
import spoon.compiler.SpoonResourceHelper;
import spoon.reflect.code.CtCFlowBreak;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtFieldAccess;
import spoon.reflect.code.CtIf;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.code.CtLoop;
import spoon.reflect.code.CtNewClass;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtSwitch;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtExecutable;
Expand All @@ -27,6 +30,7 @@
import spoon.reflect.visitor.filter.FieldAccessFilter;
import spoon.reflect.visitor.filter.FilteringOperator;
import spoon.reflect.visitor.filter.InvocationFilter;
import spoon.reflect.visitor.filter.LineFilter;
import spoon.reflect.visitor.filter.NameFilter;
import spoon.reflect.visitor.filter.OverriddenMethodFilter;
import spoon.reflect.visitor.filter.OverridingMethodFilter;
Expand All @@ -41,6 +45,7 @@
import spoon.test.filters.testclasses.SubTostada;
import spoon.test.filters.testclasses.Tacos;
import spoon.test.filters.testclasses.Tostada;
import spoon.testing.utils.ModelUtils;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -58,9 +63,7 @@ public class FilterTest {

@Before
public void setup() throws Exception {
Launcher spoon = new Launcher();
factory = spoon.createFactory();
spoon.createCompiler(factory, SpoonResourceHelper.resources("./src/test/java/spoon/test/filters/Foo.java")).build();
factory = ModelUtils.build(Foo.class);
}

@Test
Expand All @@ -79,6 +82,46 @@ public void testReturnOrThrowFilter() throws Exception {
assertEquals(2, expressions.size());
}

@Test
public void testLineFilter() throws Exception {
CtType<FooLine> foo = ModelUtils.buildClass(FooLine.class);
CtMethod method = foo.getMethod("simple");
List<CtStatement> expressions = method.getElements(new LineFilter());
assertEquals(3, expressions.size());
assertNull(expressions.get(0).getParent(new LineFilter()));

method = foo.getMethod("loopBlock");
expressions = method.getElements(new LineFilter());
assertEquals(2, expressions.size());
assertNull(expressions.get(0).getParent(new LineFilter()));
assertTrue(expressions.get(1).getParent(new LineFilter()) instanceof CtLoop);

method = foo.getMethod("loopNoBlock");
expressions = method.getElements(new LineFilter());
assertEquals(2, expressions.size());
assertNull(expressions.get(0).getParent(new LineFilter()));
assertTrue(expressions.get(1).getParent(new LineFilter()) instanceof CtLoop);

method = foo.getMethod("ifBlock");
expressions = method.getElements(new LineFilter());
assertEquals(2, expressions.size());
assertNull(expressions.get(0).getParent(new LineFilter()));
assertTrue(expressions.get(1).getParent(new LineFilter()) instanceof CtIf);

method = foo.getMethod("ifNoBlock");
expressions = method.getElements(new LineFilter());
assertEquals(2, expressions.size());
assertNull(expressions.get(0).getParent(new LineFilter()));
assertTrue(expressions.get(1).getParent(new LineFilter()) instanceof CtIf);

method = foo.getMethod("switchBlock");
expressions = method.getElements(new LineFilter());
assertEquals(3, expressions.size());
assertNull(expressions.get(0).getParent(new LineFilter()));
assertTrue(expressions.get(1).getParent(new LineFilter()) instanceof CtSwitch);
assertTrue(expressions.get(2).getParent(new LineFilter()) instanceof CtSwitch);
}


@Test
public void testFieldAccessFilter() throws Exception {
Expand Down
41 changes: 41 additions & 0 deletions src/test/java/spoon/test/filters/FooLine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package spoon.test.filters;

class FooLine {
void simple() {
int x = 3;
int z = 0;
System.out.println(z);
}

void loopBlock() {
for(int i = 0; i < 10; i++) {
System.out.println(i);
}
}

void loopNoBlock() {
for(int i = 0; i < 10; i++)
System.out.println(i);
}

void ifBlock() {
if (3 < 4) {
System.out.println("if");
}
}

void ifNoBlock() {
if (3 < 4)
System.out.println("if");
}

void switchBlock() {
switch ("test") {
case "test":
break;
default:
System.out.println("switch");
}
}
}

0 comments on commit 73ff189

Please sign in to comment.