Skip to content
Open
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 @@ -125,6 +125,7 @@
import org.openide.text.NbDocument;
import org.openide.util.Exceptions;
import com.sun.source.tree.UnaryTree;
import com.sun.source.tree.YieldTree;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.Trees;
import com.sun.tools.javac.api.JavacScope;
Expand Down Expand Up @@ -1447,6 +1448,11 @@ public Boolean visitReturn(ReturnTree node, Void p) {
return true;
}

@Override
public Boolean visitYield(YieldTree node, Void p) {
return true;
}

@Override
public Boolean visitBreak(BreakTree node, Void p) {
Tree target = info.getTreeUtilities().getBreakContinueTarget(getCurrentPath());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.sun.source.tree.Tree;
import com.sun.source.tree.TypeParameterTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.tree.YieldTree;
import com.sun.source.util.SourcePositions;
import com.sun.source.util.TreePath;
import java.awt.GraphicsEnvironment;
Expand Down Expand Up @@ -262,6 +263,25 @@ static Fix computeIntroduceMethod(CompilationInfo info, int start, int end, Map<
returnType = methodReturnType;
returnAssignTo = null;
declareVariableForReturnValue = false;
} else if (exitsFromAllBranches && scanner.hasYields) {
returnType = info.getTypes().getNullType();
for (TreePath exit : scanner.selectionExits) {
if (exit.getLeaf().getKind() == Tree.Kind.YIELD) {
Tree target = info.getTreeUtilities().getBreakContinueTargetTree(exit);
TreePath switchExpr = exit;

while (switchExpr != null && switchExpr.getLeaf() != target) {
switchExpr = switchExpr.getParentPath();
}

if (switchExpr != null) {
returnType = info.getTrees().getTypeMirror(switchExpr);
break;
}
}
}
returnAssignTo = null;
declareVariableForReturnValue = false;
} else {
returnType = info.getTypes().getNoType(TypeKind.VOID);
returnAssignTo = null;
Expand Down Expand Up @@ -628,7 +648,11 @@ private void generateMethodInvocation(List<StatementTree> nueStatements, List<Ex
}
if (branchExit != null) {
if (returnSingleValue) {
nueStatements.add(make.Return(invocation));
if (branchExit.getLeaf().getKind() == Tree.Kind.YIELD) {
nueStatements.add(make.Yield(invocation));
} else {
nueStatements.add(make.Return(invocation));
}
} else {
StatementTree branch = null;
switch (branchExit.getLeaf().getKind()) {
Expand All @@ -641,6 +665,9 @@ private void generateMethodInvocation(List<StatementTree> nueStatements, List<Ex
case RETURN:
branch = make.Return(((ReturnTree) branchExit.getLeaf()).getExpression());
break;
case YIELD:
branch = make.Yield(((YieldTree) branchExit.getLeaf()).getValue());
break;
}
if (remappedReturn != null || exitsFromAllBranches) {
nueStatements.add(make.ExpressionStatement(invocation));
Expand Down Expand Up @@ -674,6 +701,13 @@ private ReturnTree makeExtractedReturn(boolean forceReturn) {
*/
private void makeReturnsFromExtractedMethod(List<StatementTree> methodStatements) {
if (returnSingleValue) {
for (TreePath resolved : resolvedExits) {
if (resolved.getLeaf().getKind() == Tree.Kind.YIELD) {
YieldTree yield = (YieldTree) resolved.getLeaf();

copy.rewrite(resolved.getLeaf(), make.Return(yield.getValue()));
}
}
return;
}
if (resolvedExits != null) {
Expand Down Expand Up @@ -728,7 +762,7 @@ private boolean resolveAndInitialize() {
resolvedExits.add(resolved);
}

returnSingleValue = exitsFromAllBranches && branchExit.getLeaf().getKind() == Tree.Kind.RETURN && outcomeVariable == null && returnType.getKind() != TypeKind.VOID;
returnSingleValue = exitsFromAllBranches && (branchExit.getLeaf().getKind() == Tree.Kind.RETURN || branchExit.getLeaf().getKind() == Tree.Kind.YIELD) && outcomeVariable == null && returnType.getKind() != TypeKind.VOID;
}
// initialization
make = copy.getTreeMaker();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ContinueTree;
import com.sun.source.tree.DoWhileLoopTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.ForLoopTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.LambdaExpressionTree;
Expand All @@ -31,6 +32,7 @@
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.source.tree.WhileLoopTree;
import com.sun.source.tree.YieldTree;
import com.sun.source.util.TreePath;
import org.netbeans.api.java.source.support.ErrorAwareTreePathScanner;
import java.util.ArrayList;
Expand Down Expand Up @@ -71,6 +73,7 @@ final class ScanStatement extends ErrorAwareTreePathScanner<Void, Void> {
private final Map<Tree, Iterable<? extends TreePath>> assignmentsForUse;
final Set<TreePathHandle> usedTypeVariables = new HashSet<TreePathHandle>();
boolean hasReturns = false;
boolean hasYields = false;
private boolean hasBreaks = false;
private boolean hasContinues = false;
private boolean secondPass = false;
Expand Down Expand Up @@ -236,6 +239,15 @@ public Void visitReturn(ReturnTree node, Void p) {
return super.visitReturn(node, p);
}

@Override
public Void visitYield(YieldTree node, Void p) {
if (isMethodCode() && phase == PHASE_INSIDE_SELECTION) {
selectionExits.add(getCurrentPath());
hasYields = true;
}
return super.visitYield(node, p);
}

@Override
public Void visitBreak(BreakTree node, Void p) {
if (isMethodCode() && phase == PHASE_INSIDE_SELECTION && !treesSeensInSelection.contains(info.getTreeUtilities().getBreakContinueTargetTree(getCurrentPath()))) {
Expand Down Expand Up @@ -313,6 +325,7 @@ String verifyExits(boolean exitsFromAllBranches) {
i += hasReturns ? 1 : 0;
i += hasBreaks ? 1 : 0;
i += hasContinues ? 1 : 0;
i += hasYields ? 1 : 0;
if (i > 1) {
return "ERR_Too_Many_Different_Exits"; // NOI18N
}
Expand All @@ -323,27 +336,40 @@ String verifyExits(boolean exitsFromAllBranches) {
boolean returnValueComputed = false;
TreePath returnValue = null;
for (TreePath tp : selectionExits) {
if (tp.getLeaf().getKind() == Tree.Kind.RETURN) {
if (tp.getLeaf().getKind() == Tree.Kind.RETURN || tp.getLeaf().getKind() == Tree.Kind.YIELD) {
if (!exitsFromAllBranches) {
ReturnTree rt = (ReturnTree) tp.getLeaf();
TreePath currentReturnValue = rt.getExpression() != null ? new TreePath(tp, rt.getExpression()) : null;
ExpressionTree value = switch (tp.getLeaf().getKind()) {
case RETURN -> ((ReturnTree) tp.getLeaf()).getExpression();
case YIELD -> ((YieldTree) tp.getLeaf()).getValue();
default -> throw new IllegalStateException(tp.getLeaf().getKind().name());
};

String errorKey = switch (tp.getLeaf().getKind()) {
case RETURN -> "ERR_Different_Return_Values"; // NOI18N
case YIELD -> "ERR_Different_Yield_Values"; // NOI18N
default -> throw new IllegalStateException(tp.getLeaf().getKind().name());
};

TreePath currentReturnValue = value != null ? new TreePath(tp, value) : null;

if (!returnValueComputed) {
returnValue = currentReturnValue;
returnValueComputed = true;
} else {
if (returnValue != null && currentReturnValue != null) {
Set<TreePath> candidates = SourceUtils.computeDuplicates(info, returnValue, currentReturnValue, cancel);
if (candidates.size() != 1 || candidates.iterator().next().getLeaf() != rt.getExpression()) {
return "ERR_Different_Return_Values"; // NOI18N
if (candidates.size() != 1 || candidates.iterator().next().getLeaf() != value) {
return errorKey;
}
} else {
if (returnValue != currentReturnValue) {
return "ERR_Different_Return_Values"; // NOI18N
return errorKey;
}
}
}
}
} else {
}
if (tp.getLeaf().getKind() != Tree.Kind.RETURN) {
Tree target = info.getTreeUtilities().getBreakContinueTargetTree(tp);
if (breakOrContinueTarget == null) {
breakOrContinueTarget = target;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,27 @@ public void testExitsAllBranchesSwitchDefaultMissing() throws Exception {
false);
}

public void testExitsAllBranchesYield() throws Exception {
performExitsTest(
"""
package test;
public class Test {
public int test(int param) {
return switch (param) {
default -> {
i|f (param == 0) {
yield 0;
} else {
yield 1;
}
}
};
}
}
""",
true);
}

private void performExitsTest(String code, boolean expected) throws Exception {
int caretPos = code.indexOf('|');
code = code.replace("|", "");
Expand Down
Loading
Loading