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

fix: VisitorPartialEvaluator #1800

Merged
merged 2 commits into from
Jan 1, 2018
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import spoon.reflect.code.CtAssignment;
import spoon.reflect.code.CtBinaryOperator;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtCatch;
import spoon.reflect.code.CtCatchVariable;
import spoon.reflect.code.CtComment;
import spoon.reflect.code.CtConditional;
Expand Down Expand Up @@ -252,7 +253,12 @@ public <R> void visitCtBlock(CtBlock<R> block) {
for (CtStatement s : block.getStatements()) {
CtElement res = evaluate(s);
if (res != null) {
b.addStatement((CtStatement) res);
if (res instanceof CtStatement) {
b.addStatement((CtStatement) res);
} else {
//the context expectes statement. We cannot simplify in this case
b.addStatement(s);
}
}
// do not copy unreachable statements
if (flowEnded) {
Expand Down Expand Up @@ -383,6 +389,7 @@ public void visitCtIf(CtIf ifElement) {
public <T> void visitCtInvocation(CtInvocation<T> invocation) {
CtInvocation<T> i = invocation.getFactory().Core().createInvocation();
i.setExecutable(invocation.getExecutable());
i.setTypeCasts(invocation.getTypeCasts());
boolean constant = true;
i.setTarget(evaluate(invocation.getTarget()));
if ((i.getTarget() != null) && !(i.getTarget() instanceof CtLiteral)) {
Expand Down Expand Up @@ -423,17 +430,38 @@ public <T> void visitCtInvocation(CtInvocation<T> invocation) {
try {
// System.err.println("invocking "+i);
r = RtHelper.invoke(i);
CtLiteral<T> l = invocation.getFactory().Core().createLiteral();
l.setValue(r);
setResult(l);
return;
if (isLiteralType(r)) {
CtLiteral<T> l = invocation.getFactory().Core().createLiteral();
l.setValue(r);
setResult(l);
return;
}
} catch (Exception e) {
}
}
}
setResult(i);
}

private boolean isLiteralType(Object object) {
if (object == null) {
return true;
}
if (object instanceof String) {
return true;
}
if (object instanceof Number) {
return true;
}
if (object instanceof Character) {
return true;
}
if (object instanceof Class) {
return true;
}
return false;
}

@Override
public <T> void visitCtField(CtField<T> f) {
CtField<T> r = f.clone();
Expand Down Expand Up @@ -474,6 +502,13 @@ public void visitCtThrow(CtThrow throwStatement) {
flowEnded = true;
}

@Override
public void visitCtCatch(CtCatch catchBlock) {
super.visitCtCatch(catchBlock);
//the flowEnded = true set by throw in catch block does not stops flow of parent
flowEnded = false;
}

public <T> void visitCtUnaryOperator(CtUnaryOperator<T> operator) {
CtExpression<?> operand = evaluate(operator.getOperand());
if (operand instanceof CtLiteral) {
Expand Down
36 changes: 35 additions & 1 deletion src/test/java/spoon/test/eval/EvalTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,41 @@ public void testDoNotSimplify() throws Exception {
assertEquals("java.lang.System.out.println((((\"enter: \" + className) + \" - \") + methodName))", b.getStatements().get(0).toString());
}

@Test
public void testDoNotSimplifyCasts() throws Exception {
CtClass<?> type = build("spoon.test.eval", "ToEvaluate");
assertEquals("ToEvaluate", type.getSimpleName());

CtBlock<?> b = type.getMethodsByName("testDoNotSimplifyCasts").get(0).getBody();
assertEquals(1, b.getStatements().size());
b = b.partiallyEvaluate();
assertEquals("return ((U) ((java.lang.Object) (spoon.test.eval.ToEvaluate.castTarget(element).getClass())))", b.getStatements().get(0).toString());
}

@Test
public void testTryCatchAndStatement() throws Exception {
CtClass<?> type = build("spoon.test.eval", "ToEvaluate");
assertEquals("ToEvaluate", type.getSimpleName());

CtBlock<?> b = type.getMethodsByName("tryCatchAndStatement").get(0).getBody();
assertEquals(2, b.getStatements().size());
b = b.partiallyEvaluate();
assertEquals(2, b.getStatements().size());
}

@Test
public void testDoNotSimplifyToExpressionWhenStatementIsExpected() throws Exception {
CtClass<?> type = build("spoon.test.eval", "ToEvaluate");
assertEquals("ToEvaluate", type.getSimpleName());

CtBlock<?> b = type.getMethodsByName("simplifyOnlyWhenPossible").get(0).getBody();
assertEquals(3, b.getStatements().size());
b = b.partiallyEvaluate();
assertEquals("spoon.test.eval.ToEvaluate.class.getName()", b.getStatements().get(0).toString());
assertEquals("java.lang.System.out.println(spoon.test.eval.ToEvaluate.getClassLoader())", b.getStatements().get(1).toString());
assertEquals("return \"spoon.test.eval.ToEvaluate\"", b.getStatements().get(2).toString());
}

@Test
public void testVisitorPartialEvaluator_binary() throws Exception {
Launcher launcher = new Launcher();
Expand Down Expand Up @@ -114,5 +149,4 @@ public void testVisitorPartialEvaluatorScanner() throws Exception {
// the if has been removed
assertEquals(0, foo.getElements(new TypeFilter<>(CtIf.class)).size());
}

}
29 changes: 29 additions & 0 deletions src/test/java/spoon/test/eval/ToEvaluate.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package spoon.test.eval;

import spoon.reflect.declaration.CtElement;

public class ToEvaluate {

static final String S1 = "S1";
Expand Down Expand Up @@ -43,4 +45,31 @@ public static void testDoNotSimplify(String className, String methodName) {
// this code must not be simplified
java.lang.System.out.println(((("enter: " + className) + " - ") + methodName));
}

public static <U> U testDoNotSimplifyCasts(CtElement element) {
// this code must not be simplified
return ((U) ((Object) (castTarget(element).getClass())));
}

private static <T> T castTarget(CtElement element) {
return (T) element;
}

private static String tryCatchAndStatement(CtElement element) {
try {
element.getClass();
} catch (RuntimeException e) {
throw e;
}
return "This must not be removed";
}

private static String simplifyOnlyWhenPossible(CtElement element) {
//this must not be simplified because literal is not a statement.
ToEvaluate.class.getName();
//this must not be simplified because ClassLoader instance is not a literal
System.out.println(ToEvaluate.class.getClassLoader());
//this can be simplified because return expects expression
return ToEvaluate.class.getName();
}
}