From 00c5cf35f62f274789003349852b5d9ee3d13754 Mon Sep 17 00:00:00 2001 From: tdurieux Date: Sat, 5 Dec 2015 13:20:26 +0100 Subject: [PATCH 1/2] [fix #304] Refactor Snippet helper --- .../spoon/reflect/factory/ClassFactory.java | 4 +- .../spoon/reflect/factory/PackageFactory.java | 2 +- .../compiler/SnippetCompilationHelper.java | 121 ++++++------------ 3 files changed, 39 insertions(+), 88 deletions(-) diff --git a/src/main/java/spoon/reflect/factory/ClassFactory.java b/src/main/java/spoon/reflect/factory/ClassFactory.java index e168e87aadc..a7ffbedfc28 100644 --- a/src/main/java/spoon/reflect/factory/ClassFactory.java +++ b/src/main/java/spoon/reflect/factory/ClassFactory.java @@ -61,9 +61,9 @@ public CtClass create(CtPackage owner, String simpleName) { CtClass c = factory.Core().createClass(); c.setSimpleName(simpleName); if (owner.getTypes().contains(c)) { - owner.getTypes().remove(c); + owner.removeType(c); } - owner.getTypes().add(c); + owner.addType(c); c.setParent(owner); return c; } diff --git a/src/main/java/spoon/reflect/factory/PackageFactory.java b/src/main/java/spoon/reflect/factory/PackageFactory.java index 2ae8e9bf903..0500f992e9f 100644 --- a/src/main/java/spoon/reflect/factory/PackageFactory.java +++ b/src/main/java/spoon/reflect/factory/PackageFactory.java @@ -58,7 +58,7 @@ public CtElement getParent() throws ParentNotInitializedException { @Override public String getSimpleName() { - return ""; + return super.getSimpleName(); } @Override diff --git a/src/main/java/spoon/support/compiler/SnippetCompilationHelper.java b/src/main/java/spoon/support/compiler/SnippetCompilationHelper.java index 9032e0dd892..31edfbf53fd 100644 --- a/src/main/java/spoon/support/compiler/SnippetCompilationHelper.java +++ b/src/main/java/spoon/support/compiler/SnippetCompilationHelper.java @@ -12,26 +12,27 @@ import spoon.reflect.code.CtReturn; import spoon.reflect.code.CtStatement; import spoon.reflect.declaration.CtClass; +import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtMethod; import spoon.reflect.declaration.CtParameter; import spoon.reflect.declaration.CtType; import spoon.reflect.declaration.ModifierKind; import spoon.reflect.factory.Factory; import spoon.reflect.reference.CtTypeReference; -import spoon.reflect.visitor.Filter; -import spoon.reflect.visitor.Query; import spoon.support.compiler.jdt.JDTSnippetCompiler; import spoon.support.reflect.declaration.CtElementImpl; public class SnippetCompilationHelper { + private static final String WRAPPER_CLASS_NAME = "Wrapper"; + private static final String WRAPPER_METHOD_NAME = "wrap"; + public static void compileAndReplaceSnippetsIn(CtType c) { Factory f = c.getFactory(); CtType workCopy = c; Set backup = EnumSet.noneOf(ModifierKind.class); backup.addAll(workCopy.getModifiers()); - - workCopy.getModifiers().remove(ModifierKind.PUBLIC); + workCopy.removeModifier(ModifierKind.PUBLIC); try { build(f, workCopy.toString()); @@ -39,7 +40,6 @@ public static void compileAndReplaceSnippetsIn(CtType c) { // restore modifiers c.setModifiers(backup); } - } public static CtStatement compileStatement(CtCodeSnippetStatement st) @@ -47,64 +47,41 @@ public static CtStatement compileStatement(CtCodeSnippetStatement st) return internalCompileStatement(st); } - private static CtStatement internalCompileStatement(CtStatement st) { + private static CtStatement internalCompileStatement(CtElement st) { Factory f = st.getFactory(); CtClass w = createWrapper(st, f); - compile(f, w); + build(f, w); - CtType c = f.Type().get("Wrapper"); + CtType c = f.Type().get(WRAPPER_CLASS_NAME); // Get the part we want - CtMethod wrapper = Query.getElements(c, new Filter>() { - - public boolean matches(CtMethod element) { - return element.getSimpleName().equals("wrap"); - } - - }).get(0); + CtMethod wrapper = c.getMethod(WRAPPER_METHOD_NAME); CtStatement ret = wrapper.getBody().getStatements().get(0); // Clean up c.getPackage().getTypes().remove(c); - // check typing? - return ret; } - private static CtClass createWrapper(CtStatement st, Factory f) { - CtClass w = f.Class().create("Wrapper"); - - CtBlock body = f.Core().createBlock(); - - body.addStatement(st); - - Set x = EnumSet.noneOf(ModifierKind.class); + @SuppressWarnings("unchecked") + public static CtExpression compileExpression( + CtCodeSnippetExpression expr) throws SnippetCompilationError { - f.Method().create( - w, - x, - f.Type().createReference(void.class), - "wrap", - CtElementImpl.>emptyList(), - CtElementImpl - .>emptySet(), - body); + CtReturn ret = (CtReturn) internalCompileStatement(expr); - return w; + return ret.getReturnedExpression(); } - private static void compile(Factory f, CtType w) - throws SnippetCompilationError { + private static void build(Factory f, CtType w) { String contents = w.toString(); build(f, contents); - } private static void build(Factory f, String contents) { @@ -113,63 +90,37 @@ private static void build(Factory f, String contents) { try { builder.build(); } catch (Exception e) { - throw new ModelBuildingException( - "snippet compilation error while compiling: " + contents, e); + throw new ModelBuildingException("snippet compilation error while compiling: " + contents, e); } } - @SuppressWarnings("unchecked") - public static CtExpression compileExpression( - CtCodeSnippetExpression expr) throws SnippetCompilationError { - // create wrapping template - - Factory f = expr.getFactory(); - CtClass w = createWrapper(expr, f); - - String contents = w.toString(); - - build(f, contents); - - CtType c = f.Type().get("Wrapper"); - - // Get the part we want - - CtMethod wrapper = Query.getElements(c, new Filter>() { - - public boolean matches(CtMethod element) { - return element.getSimpleName().equals("wrap"); - } - - }).get(0); - - CtReturn ret = (CtReturn) wrapper.getBody().getStatements() - .get(0); + private static CtClass createWrapper(CtElement element, Factory f) { + CtClass w = f.Class().create(WRAPPER_CLASS_NAME); // Clean up (delete wrapper from factory) - c.getPackage().getTypes().remove(c); - - return ret.getReturnedExpression(); - } - - private static CtClass createWrapper( - CtExpression st, Factory f) { - CtClass w = f.Class().create("Wrapper"); - - CtBlock body = f.Core().createBlock(); - CtReturn ret = f.Core().createReturn(); - ret.setReturnedExpression(st); - body.addStatement(ret); + w.getPackage().getTypes().remove(w); + + CtBlock body = f.Core().createBlock(); + + CtTypeReference returnType = f.Type().VOID_PRIMITIVE; + if (element instanceof CtStatement) { + body.addStatement((CtStatement) element); + } else if (element instanceof CtExpression) { + CtReturn ret = f.Core().createReturn(); + ret.setReturnedExpression((CtExpression) element); + body.addStatement(ret); + returnType = f.Type().OBJECT; + } - Set x = EnumSet.noneOf(ModifierKind.class); + Set modifiers = EnumSet.noneOf(ModifierKind.class); f.Method().create( w, - x, - f.Type().createReference(Object.class), - "wrap", + modifiers, + returnType, + WRAPPER_METHOD_NAME, CtElementImpl.>emptyList(), - CtElementImpl - .>emptySet(), + CtElementImpl.>emptySet(), body); return w; From a196f15aabaca8edc5cbea68b4688b71f3bfaa9e Mon Sep 17 00:00:00 2001 From: GerardPaligot Date: Tue, 8 Dec 2015 11:20:09 +0100 Subject: [PATCH 2/2] test(snippet): A snippet can be compiled with a context. --- .../java/spoon/test/snippets/SnippetTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/spoon/test/snippets/SnippetTest.java b/src/test/java/spoon/test/snippets/SnippetTest.java index 79e0a3dcea8..cf815e4d1c6 100644 --- a/src/test/java/spoon/test/snippets/SnippetTest.java +++ b/src/test/java/spoon/test/snippets/SnippetTest.java @@ -3,9 +3,13 @@ import org.junit.Test; import spoon.reflect.code.CtBinaryOperator; import spoon.reflect.code.CtCodeSnippetExpression; +import spoon.reflect.code.CtConstructorCall; import spoon.reflect.code.CtExpression; +import spoon.reflect.code.CtInvocation; +import spoon.reflect.code.CtLocalVariable; import spoon.reflect.declaration.CtClass; import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtPackage; import spoon.reflect.factory.Factory; import spoon.test.TestUtils; @@ -63,4 +67,17 @@ public void testCompileSnippetSeveralTimes() throws Exception { assertTrue(thirdCompile instanceof CtBinaryOperator); assertEquals("1 > 3", thirdCompile.toString()); } + + @Test + public void testCompileSnippetWithContext() throws Exception { + // contract: a snippet object can be compiled with a context in the factory. + try { + // Add a class in the context. + factory.Class().create("AClass"); + // Try to compile a snippet with a context. + factory.Code().createCodeSnippetStatement("int i = 1;").compile(); + } catch (ClassCastException e) { + fail(); + } + } }