Skip to content

Commit

Permalink
fix: fix snippet compilation when snippet follows a CtComment (INRIA#…
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewbwogi authored and woutersmeenk committed Aug 29, 2021
1 parent fef6341 commit d2ea85e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 2 deletions.
20 changes: 18 additions & 2 deletions src/main/java/spoon/support/compiler/SnippetCompilationHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtReturn;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtComment;
import spoon.reflect.code.CtConstructorCall;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtCodeSnippet;
import spoon.reflect.declaration.CtElement;
Expand Down Expand Up @@ -67,11 +69,15 @@ public static void compileAndReplaceSnippetsIn(CtType<?> initialClass) {
initialClass.removeModifier(ModifierKind.PUBLIC);

// we need to delete the current class from its package
// otherwsise the new type is not added because it has the same fully qualified name
// otherwise the new type is not added because it has the same fully qualified name
initialClass.delete();

// add dummy statements for each comment so paths are same for initial and new class
CtType<?> clonedInitialClass = initialClass.clone();
addDummyStatements(clonedInitialClass);

try {
build(f, "package " + initialClass.getPackage().getQualifiedName() + ";" + initialClass.toString());
build(f, "package " + initialClass.getPackage().getQualifiedName() + ";" + clonedInitialClass.toString());
} finally {
// restore modifiers
initialClass.setModifiers(backup);
Expand All @@ -95,6 +101,16 @@ public static void compileAndReplaceSnippetsIn(CtType<?> initialClass) {
}
}

private static void addDummyStatements(CtType<?> clonedInitialClass) {
Factory factory = clonedInitialClass.getFactory();
CtConstructorCall call = factory.createConstructorCall(factory.createCtTypeReference(Object.class));
List<CtComment> list = clonedInitialClass.filterChildren(new TypeFilter<>(CtComment.class)).list();
for (CtComment comment : list) {
comment.insertBefore(call);
comment.delete();
}
}

public static CtStatement compileStatement(CtCodeSnippetStatement st)
throws SnippetCompilationError {
return internalCompileStatement(st, st.getFactory().Type().VOID_PRIMITIVE);
Expand Down
33 changes: 33 additions & 0 deletions src/test/java/spoon/test/snippets/SnippetTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.code.CtReturn;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtComment;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtMethod;
Expand Down Expand Up @@ -164,4 +166,35 @@ After the call to CtType().compileAndReplaceSnippetsIn,
assertEquals(factory.createVariableRead(reference, false), lastStatement.getTarget()); // the target of the inserted invocation has been resolved as the reference of the declared object "s"
}

@Test
public void testCompileSnippetsWithCtComment() {
// contract: snippets are correctly compiled when followed by a CtComment
final Launcher launcher = new Launcher();
launcher.addInputResource("src/test/resources/snippet/SnippetCommentResource.java");
launcher.buildModel();
Factory factory = launcher.getFactory();
final CtClass<?> testClass = factory.Class().get("snippet.test.resources.SnippetCommentResource");
CtMethod method = testClass.getMethodsByName("modifiedMethod").get(0);
CtBlock body = method.getBody();
body.addStatement(body.getStatements().size()-1,launcher.getFactory().createInlineComment("inline comment"));
body.addStatement(body.getStatements().size()-1,launcher.getFactory().createCodeSnippetStatement("invokedMethod()"));
CtBlock innerBlock = body.getStatement(0);
innerBlock.addStatement(0,factory.createCodeSnippetStatement("invokedMethod()"));
body.addStatement(0,factory.createComment("block comment", CtComment.CommentType.BLOCK));

testClass.compileAndReplaceSnippets();

assertTrue(body.getStatements().get(0) instanceof CtComment);
assertTrue(body.getStatements().get(1) instanceof CtBlock);
assertTrue(body.getStatements().get(2) instanceof CtComment);
assertTrue(body.getStatements().get(3) instanceof CtInvocation);
assertTrue(body.getStatements().get(4) instanceof CtReturn);
assertTrue(innerBlock.getStatements().get(0) instanceof CtInvocation);
assertEquals(5,body.getStatements().size());
assertEquals(1,innerBlock.getStatements().size());
assertEquals(0,body.getStatements().get(0).getComments().size());
assertEquals(0,body.getStatements().get(1).getComments().size());
assertEquals(0,body.getStatements().get(2).getComments().size());
assertEquals(0,body.getStatements().get(3).getComments().size());
}
}
13 changes: 13 additions & 0 deletions src/test/resources/snippet/SnippetCommentResource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package snippet.test.resources;

public class SnippetCommentResource {

public void modifiedMethod() {
{
}
return;
}

void invokedMethod() {
}
}

0 comments on commit d2ea85e

Please sign in to comment.