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: fix snippet compilation when snippet follows a CtComment #3888

Merged
merged 3 commits into from
Apr 26, 2021
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
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() {
}
}