diff --git a/java/java-impl/src/com/intellij/codeInspection/intermediaryVariable/ReturnSeparatedFromComputationInspection.java b/java/java-impl/src/com/intellij/codeInspection/intermediaryVariable/ReturnSeparatedFromComputationInspection.java index 57bf1758de6d..e2e006aa72af 100644 --- a/java/java-impl/src/com/intellij/codeInspection/intermediaryVariable/ReturnSeparatedFromComputationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/intermediaryVariable/ReturnSeparatedFromComputationInspection.java @@ -186,22 +186,20 @@ public class ReturnSeparatedFromComputationInspection extends BaseJavaBatchLocal } private static boolean isApplicable(@NotNull ControlFlow flow, @NotNull ReturnContext context) { - final int flowStart = flow.getStartOffset(context.returnScope); - final int flowEnd = flow.getEndOffset(context.returnScope); - if (flowStart < 0 || flowEnd < 0) return false; - - final int returnStartOffset = flow.getStartOffset(context.returnStatement); - final int returnEndOffset = flow.getEndOffset(context.returnStatement); - if (returnStartOffset < 0 || returnEndOffset < 0) return false; - if (hasChainedAssignmentsInScope(flow, context.returnedVariable, context.returnStatement)) { return false; } - - if (context.returnScope != context.variableScope && - ControlFlowUtil.hasObservableThrowExitPoints(flow, flowStart, flowEnd, - new PsiElement[]{context.refactoredStatement}, context.variableScope)) { - return false; + if (context.returnScope != context.variableScope) { + if (ControlFlowUtil.isVariableReadInFinally(flow, context.returnScope, context.variableScope, context.returnedVariable)) { + return false; + } + final int flowStart = flow.getStartOffset(context.returnScope); + final int flowEnd = flow.getEndOffset(context.returnScope); + if (flowStart < 0 || flowEnd < 0) return false; + if (ControlFlowUtil.hasObservableThrowExitPoints(flow, flowStart, flowEnd, + new PsiElement[]{context.refactoredStatement}, context.variableScope)) { + return false; + } } Mover mover = new Mover(flow, context.refactoredStatement, context.returnedVariable, context.returnType, true); diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java index 032d2e143a28..4b08e3e094a6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java @@ -258,6 +258,37 @@ public class ControlFlowUtil { return false; } + public static boolean isVariableReadInFinally(@NotNull ControlFlow flow, + @Nullable PsiElement startElement, + @NotNull PsiElement enclosingCodeFragment, + @NotNull PsiVariable variable) { + for (PsiElement element = startElement; element != null && element != enclosingCodeFragment; element = element.getParent()) { + if (element instanceof PsiCodeBlock) { + final PsiElement parent = element.getParent(); + if (parent instanceof PsiTryStatement) { + final PsiTryStatement tryStatement = (PsiTryStatement)parent; + if (tryStatement.getTryBlock() == element) { + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if (finallyBlock != null) { + final List instructions = flow.getInstructions(); + final int startOffset = flow.getStartOffset(finallyBlock); + final int endOffset = flow.getEndOffset(finallyBlock); + LOG.assertTrue(startOffset >= 0, "flow start"); + LOG.assertTrue(endOffset <= instructions.size(), "flow end"); + for (int i = startOffset; i < endOffset; i++) { + final Instruction instruction = instructions.get(i); + if (instruction instanceof ReadVariableInstruction && ((ReadVariableInstruction)instruction).variable == variable) { + return true; + } + } + } + } + } + } + } + return false; + } + public static List getInputVariables(ControlFlow flow, int start, int end) { List usedVariables = getUsedVariables(flow, start, end); ArrayList array = new ArrayList(usedVariables.size()); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/beforeReadInFinally.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/beforeReadInFinally.java new file mode 100644 index 000000000000..f77fe792c84d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation/beforeReadInFinally.java @@ -0,0 +1,14 @@ +// "Move 'return' closer to computation of the value of 'n'" "false" +class T { + int f(boolean b) { + int n = -1; + try { + if (b) throw new RuntimeException(); + n = 1; + return n; + } + finally { + System.out.println(n); + } + } +} \ No newline at end of file