Skip to content
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 @@ -55,6 +55,16 @@ public TreeVisitor<?, ExecutionContext> getVisitor() {
@Override
public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, ExecutionContext ctx) {
J.VariableDeclarations.NamedVariable v = super.visitVariable(variable, ctx);
if (v.getInitializer() == null) {
return v;
}

Expression initializer = (Expression) new ChangeType("java.util.Stack", "java.util.ArrayDeque", false)
.getVisitor().visitNonNull(v.getInitializer(), ctx, getCursor().getParentOrThrow());
if (initializer == v.getInitializer()) {
// Not a `Stack`, so skip the data flow analysis below, which is costly on every variable in the file
return v;
}

DataFlowSpec returned = new DataFlowSpec() {
@Override
Expand All @@ -68,9 +78,8 @@ public boolean isSink(DataFlowNode sinkNode) {
}
};

if (v.getInitializer() != null && FindLocalFlowPaths.noneMatch(getCursor(), returned)) {
v = v.withInitializer((Expression) new ChangeType("java.util.Stack", "java.util.ArrayDeque", false)
.getVisitor().visitNonNull(v.getInitializer(), ctx, getCursor().getParentOrThrow()));
if (FindLocalFlowPaths.noneMatch(getCursor(), returned)) {
v = v.withInitializer(initializer);
getCursor().putMessageOnFirstEnclosing(J.VariableDeclarations.class, "replace", true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,45 @@ void test(java.util.List<Test> result) {
);
}

@Issue("https://github.com/openrewrite/rewrite-analysis/issues/113")
@Test
void doNotFailOnDataFlowThroughNestedMethodInvocations() {
// Regression: dataflow was run for every initialized variable in the file, not just the `Stack`.
// On `Optional.ofNullable(a).orElse(opt.get())` the flow engine ping-ponged between the
// "argument to select" and "select to argument" steps until the stack overflowed.
rewriteRun(
//language=java
java(
"""
import java.util.Optional;
import java.util.Stack;

class Test {
String test(Optional<String> opt) {
Stack<Integer> stack = new Stack<>();
stack.push(1);
String a = "x";
return Optional.ofNullable(a).orElse(opt.get());
}
}
""",
"""
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Optional;
import java.util.Stack;

class Test {
String test(Optional<String> opt) {
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);
String a = "x";
return Optional.ofNullable(a).orElse(opt.get());
}
}
"""
)
);
}

}
Loading