Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(delete): Allows delete any element in a Spoon AST. #423

Merged
merged 1 commit into from
Dec 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/main/java/spoon/reflect/declaration/CtElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,9 @@ <E extends CtElement> List<E> getAnnotatedChildren(
* be called to check and fix parents after manipulating the model.
*/
void updateAllParentsBelow();

/*
* Deletes the element. For instance, delete a statement from its containing block. Warning: it may result in an incorrect AST, use at your own risk.
*/
void delete();
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,11 @@ public <E extends CtElement> E setAnnotations(List<CtAnnotation<? extends Annota
return (E) this;
}

@Override
public void delete() {
replace(null);
}

public <E extends CtElement> E addAnnotation(CtAnnotation<? extends Annotation> annotation) {
if ((List<?>) this.annotations == (List<?>) emptyList()) {
this.annotations = new ArrayList<CtAnnotation<? extends Annotation>>(ANNOTATIONS_CONTAINER_DEFAULT_CAPACITY);
Expand Down
249 changes: 249 additions & 0 deletions src/test/java/spoon/test/delete/DeleteTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
package spoon.test.delete;

import org.junit.Test;
import spoon.reflect.code.CtAssignment;
import spoon.reflect.code.CtCase;
import spoon.reflect.code.CtIf;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtSwitch;
import spoon.reflect.declaration.CtAnnotation;
import spoon.reflect.declaration.CtAnonymousExecutable;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtConstructor;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtParameter;
import spoon.reflect.factory.Factory;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.test.TestUtils;
import spoon.test.delete.testclasses.Adobada;

import java.lang.annotation.Annotation;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

public class DeleteTest {
@Test
public void testDeleteAStatementInAnonymousExecutable() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final List<CtAnonymousExecutable> anonymousExecutables = adobada.getAnonymousExecutables();
final CtAnonymousExecutable instanceExec = anonymousExecutables.get(0);

assertEquals(2, instanceExec.getBody().getStatements().size());

final CtStatement statement = instanceExec.getBody().getStatement(1);
statement.delete();

assertEquals(1, instanceExec.getBody().getStatements().size());
assertFalse(instanceExec.getBody().getStatements().contains(statement));
}

@Test
public void testDeleteAStatementInStaticAnonymousExecutable() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final List<CtAnonymousExecutable> anonymousExecutables = adobada.getAnonymousExecutables();
final CtAnonymousExecutable staticExec = anonymousExecutables.get(1);

assertEquals(2, staticExec.getBody().getStatements().size());

final CtStatement statement = staticExec.getBody().getStatement(1);
statement.delete();

assertEquals(1, staticExec.getBody().getStatements().size());
assertFalse(staticExec.getBody().getStatements().contains(statement));
}

@Test
public void testDeleteAStatementInConstructor() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final CtConstructor<Adobada> constructor = adobada.getConstructor();

assertEquals(3, constructor.getBody().getStatements().size());

final CtStatement statement = constructor.getBody().getStatement(1);
statement.delete();

assertEquals(2, constructor.getBody().getStatements().size());
assertFalse(constructor.getBody().getStatements().contains(statement));
}

@Test
public void testDeleteAStatementInMethod() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final CtMethod method = adobada.getMethod("m");

assertEquals(2, method.getBody().getStatements().size());

final CtStatement statement = method.getBody().getStatement(1);
statement.delete();

assertEquals(1, method.getBody().getStatements().size());
assertFalse(method.getBody().getStatements().contains(statement));
}

@Test
public void testDeleteReturn() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final CtMethod method = adobada.getMethod("m2");

assertEquals(1, method.getBody().getStatements().size());

final CtStatement statement = method.getBody().getStatement(0);
statement.delete();

assertEquals(0, method.getBody().getStatements().size());
assertFalse(method.getBody().getStatements().contains(statement));
}

@Test
public void testDeleteStatementInCase() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final CtMethod method = adobada.getMethod("m3");
final CtCase aCase = method.getElements(new TypeFilter<>(CtCase.class)).get(0);

assertEquals(2, aCase.getStatements().size());

final CtStatement statement = aCase.getStatements().get(1);
statement.delete();

assertEquals(1, aCase.getStatements().size());
assertFalse(aCase.getStatements().contains(statement));
}

@Test
public void testDeleteACaseOfASwitch() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final CtMethod method = adobada.getMethod("m3");
final CtSwitch aSwitch = method.getElements(new TypeFilter<>(CtSwitch.class)).get(0);
final CtCase aCase = (CtCase) aSwitch.getCases().get(1);

assertEquals(2, aSwitch.getCases().size());

aCase.delete();

assertEquals(1, aSwitch.getCases().size());
assertFalse(aSwitch.getCases().contains(aCase));
}

@Test
public void testDeleteMethod() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final CtMethod method = adobada.getMethod("m4", factory.Type().INTEGER_PRIMITIVE, factory.Type().FLOAT_PRIMITIVE, factory.Type().STRING);

assertEquals(4, adobada.getMethods().size());

method.delete();

assertEquals(3, adobada.getMethods().size());
assertFalse(adobada.getMethods().contains(method));
}

@Test
public void testDeleteParameterOfMethod() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final CtMethod method = adobada.getMethod("m4", factory.Type().INTEGER_PRIMITIVE, factory.Type().FLOAT_PRIMITIVE, factory.Type().STRING);
final CtParameter param = (CtParameter) method.getParameters().get(1);

assertEquals(3, method.getParameters().size());

param.delete();

assertEquals(2, method.getParameters().size());
assertFalse(method.getParameters().contains(param));
}

@Test
public void testDeleteBodyOfAMethod() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final CtMethod method = adobada.getMethod("m");

assertNotNull(method.getBody());

method.getBody().delete();

assertNull(method.getBody());
}

@Test
public void testDeleteAnnotationOnAClass() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

assertEquals(1, adobada.getAnnotations().size());
final CtAnnotation<? extends Annotation> annotation = adobada.getAnnotations().get(0);

annotation.delete();

assertEquals(0, adobada.getAnnotations().size());
assertFalse(adobada.getAnnotations().contains(annotation));
}

@Test
public void testDeleteAClassTopLevel() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);
final CtPackage aPackage = adobada.getParent(CtPackage.class);

assertEquals(1, aPackage.getTypes().size());

adobada.delete();

assertEquals(0, aPackage.getTypes().size());
assertFalse(aPackage.getTypes().contains(adobada));
}

@Test
public void testDeleteConditionInACondition() throws Exception {
final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final CtMethod method = adobada.getMethod("m4", factory.Type().INTEGER_PRIMITIVE, factory.Type().FLOAT_PRIMITIVE, factory.Type().STRING);
final CtIf anIf = method.getElements(new TypeFilter<>(CtIf.class)).get(0);

assertNotNull(anIf.getCondition());

anIf.getCondition().delete();

assertNull(anIf.getCondition());
}

@Test
public void testDeleteChainOfAssignment() throws Exception {

final Factory factory = TestUtils.build(Adobada.class);
final CtClass<Adobada> adobada = factory.Class().get(Adobada.class);

final CtMethod method = adobada.getMethod("m4", factory.Type().INTEGER_PRIMITIVE, factory.Type().FLOAT_PRIMITIVE, factory.Type().STRING);
final CtAssignment chainOfAssignment = method.getElements(new TypeFilter<>(CtAssignment.class)).get(0);

assertNotNull(chainOfAssignment.getAssignment());

chainOfAssignment.getAssignment().delete();

assertNull(chainOfAssignment.getAssignment());
}
}
53 changes: 53 additions & 0 deletions src/test/java/spoon/test/delete/testclasses/Adobada.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package spoon.test.delete.testclasses;

@Deprecated
public class Adobada {
{
int i;
int j;
}

static {
int i;
int j;
}

public Adobada() {
int i;
int j;
}

public void m() {
int i;
int j;
}

public Adobada m2() {
return new Adobada() {
@Override
public void m() {
int i;
int j;
}
};
}

public void m3() {
switch (1) {
case 1:
int i;
int j;
default:
int o;
int b;
}
}

public void m4(int i, float j, String s) {
if (true) {
System.err.println("");
}
int k;
j = i = k = 3;
}
}