[Bug]: wrong output for try with resources (variable ends up several times in initializer list)
xzel23 opened this issue · comments
Describe the bug
Spoon produces wrong output for try-with-resources without resource declaration. In the example, foo1() and bar1() that both contain a resource declaration produce correct results. The output for the other methods is incorrect, the variable should be present only once in the expression in parentheses.
Note that try-with-resources was changed in Java 9 to explicitly allow using final or effectively final variables in the try-with-resources list.
Actually I have another case, where try (in) { ... }
gets transformed to the non-compilable try { ... }
but I cannot reproduce with a simplified example, so I report these apparent failures first.
Source code you are trying to analyze/transform
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
class Issue {
public static void foo1() throws FileNotFoundException {
try (PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
writer.println("foo");
}
}
public static void bar1() throws FileNotFoundException {
try (PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
writer.println("bar");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void foo2() throws FileNotFoundException {
PrintWriter writer = new PrintWriter(new File("testWrite.txt"));
try (writer) {
writer.println("foo");
}
}
public static void bar2() throws FileNotFoundException {
PrintWriter writer = new PrintWriter(new File("testWrite.txt"));
try (writer) {
writer.println("bar");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void foo3(PrintWriter writer) throws FileNotFoundException {
try (writer) {
writer.println("foo");
}
}
public static void bar3(PrintWriter writer) throws FileNotFoundException {
try (writer) {
writer.println("bar");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Source code for your Spoon processing
import spoon.Launcher;
import spoon.processing.AbstractProcessor;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtType;
public class Main {
public static void main(String[] args) {
// Create and configure a Spoon launcher
Launcher launcher = new Launcher();
launcher.addProcessor(new NoOperationProcessor());
launcher.addInputResource("src/test/resources/Issue.java");
launcher.run();
launcher.getModel().getAllTypes().stream()
.map(CtType::toString)
.forEach(System.out::println);
}
// Create a no-operation processor
static class NoOperationProcessor extends AbstractProcessor<CtElement> {
@Override
public void process(CtElement element) {
// Do nothing
}
}
}
Actual output
class Issue {
public static void foo1() throws java.io.FileNotFoundException {
try (java.io.PrintWriter writer = new java.io.PrintWriter(new java.io.File("testWrite.txt"))) {
writer.println("foo");
}
}
public static void bar1() throws java.io.FileNotFoundException {
try (java.io.PrintWriter writer = new java.io.PrintWriter(new java.io.File("testWrite.txt"))) {
writer.println("bar");
} catch (java.lang.Exception e) {
e.printStackTrace();
}
}
public static void foo2() throws java.io.FileNotFoundException {
java.io.PrintWriter writer = new java.io.PrintWriter(new java.io.File("testWrite.txt"));
try (writer;writer;writer) {
writer.println("foo");
}
}
public static void bar2() throws java.io.FileNotFoundException {
java.io.PrintWriter writer = new java.io.PrintWriter(new java.io.File("testWrite.txt"));
try (writer;writer;writer) {
writer.println("bar");
} catch (java.lang.Exception e) {
e.printStackTrace();
}
}
public static void foo3(java.io.PrintWriter writer) throws java.io.FileNotFoundException {
try (writer;writer) {
writer.println("foo");
}
}
public static void bar3(java.io.PrintWriter writer) throws java.io.FileNotFoundException {
try (writer;writer) {
writer.println("bar");
} catch (java.lang.Exception e) {
e.printStackTrace();
}
}
}
Expected output
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
class Issue {
public static void foo1() throws FileNotFoundException {
try (PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
writer.println("foo");
}
}
public static void bar1() throws FileNotFoundException {
try (PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
writer.println("bar");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void foo2() throws FileNotFoundException {
PrintWriter writer = new PrintWriter(new File("testWrite.txt"));
try (writer) {
writer.println("foo");
}
}
public static void bar2() throws FileNotFoundException {
PrintWriter writer = new PrintWriter(new File("testWrite.txt"));
try (writer) {
writer.println("bar");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void foo3(PrintWriter writer) throws FileNotFoundException {
try (writer) {
writer.println("foo");
}
}
public static void bar3(PrintWriter writer) throws FileNotFoundException {
try (writer) {
writer.println("bar");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Spoon Version
10.4.1
JVM Version
17
What operating system are you using?
macOS Ventura 13.5.2
I can confirm this bug, even with compliance level >= 9 and also without the processor. It is caused by
spoon/src/main/java/spoon/support/compiler/jdt/ParentExiter.java
Lines 1067 to 1079 in 02c9e04
which incorrectly searches for declarations in other mehods as well. Generally, there might be a better solution to this.