diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlow.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlow.java index 4ff041cac9cd..92aa9e85d99f 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlow.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlow.java @@ -93,11 +93,6 @@ public class ControlFlow { public int getInstructionOffset() { return myElementToStartOffsetMap.get(element); } - - @Override - public String toString() { - return String.valueOf(myElementToStartOffsetMap.get(element)); - } }; } @@ -107,11 +102,6 @@ public class ControlFlow { public int getInstructionOffset() { return myElementToEndOffsetMap.get(element); } - - @Override - public String toString() { - return String.valueOf(myElementToEndOffsetMap.get(element)); - } }; } @@ -127,8 +117,13 @@ public class ControlFlow { return result.toString(); } - public interface ControlFlowOffset { - int getInstructionOffset(); + public abstract static class ControlFlowOffset { + public abstract int getInstructionOffset(); + + @Override + public String toString() { + return String.valueOf(getInstructionOffset()); + } } static ControlFlowOffset deltaOffset(final ControlFlowOffset delegate, final int delta) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 0a3d9ce8b4eb..1077a6e9a2c9 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -922,32 +922,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { myTrapStack = myTrapStack.prepend(new Trap.TryCatch(statement, clauses)); } - Set closerExceptions = Collections.emptySet(); - Trap.TwrFinally twrFinallyDescriptor = null; - if (resourceList != null) { - resourceList.accept(this); - - closerExceptions = StreamEx.of(resourceList.iterator()).flatCollection(ExceptionUtil::getCloserExceptions).toSet(); - if (!closerExceptions.isEmpty()) { - twrFinallyDescriptor = new Trap.TwrFinally(resourceList, getStartOffset(resourceList)); - myTrapStack = myTrapStack.prepend(twrFinallyDescriptor); - } - } - - if (tryBlock != null) { - tryBlock.accept(this); - } - - if (twrFinallyDescriptor != null) { - assert myTrapStack.getHead() instanceof Trap.TwrFinally; - InstructionTransfer gotoEnd = new InstructionTransfer(getEndOffset(resourceList), getVariablesInside(tryBlock)); - controlTransfer(gotoEnd, FList.createFromReversed(ContainerUtil.createMaybeSingletonList(twrFinallyDescriptor))); - myTrapStack = myTrapStack.getTail(); - startElement(resourceList); - addThrows(null, closerExceptions.toArray(PsiClassType.EMPTY_ARRAY)); - addInstruction(new ControlTransferInstruction(null)); // DfaControlTransferValue is on stack - finishElement(resourceList); - } + processTryWithResources(resourceList, tryBlock); InstructionTransfer gotoEnd = new InstructionTransfer(getEndOffset(statement), getVariablesInside(tryBlock)); FList singleFinally = FList.createFromReversed(ContainerUtil.createMaybeSingletonList(finallyDescriptor)); @@ -980,6 +955,37 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { finishElement(statement); } + private void processTryWithResources(@Nullable PsiResourceList resourceList, @Nullable PsiCodeBlock tryBlock) { + Set closerExceptions = Collections.emptySet(); + Trap.TwrFinally twrFinallyDescriptor = null; + if (resourceList != null) { + resourceList.accept(this); + + closerExceptions = StreamEx.of(resourceList.iterator()).flatCollection(ExceptionUtil::getCloserExceptions).toSet(); + if (!closerExceptions.isEmpty()) { + twrFinallyDescriptor = new Trap.TwrFinally(resourceList, getStartOffset(resourceList)); + myTrapStack = myTrapStack.prepend(twrFinallyDescriptor); + } + } + + if (tryBlock != null) { + tryBlock.accept(this); + } + + if (twrFinallyDescriptor != null) { + assert myTrapStack.getHead() instanceof Trap.TwrFinally; + InstructionTransfer gotoEnd = new InstructionTransfer(getEndOffset(resourceList), getVariablesInside(tryBlock)); + controlTransfer(gotoEnd, FList.createFromReversed(ContainerUtil.createMaybeSingletonList(twrFinallyDescriptor))); + myTrapStack = myTrapStack.getTail().prepend(new Trap.InsideFinally(resourceList)); + startElement(resourceList); + addThrows(null, closerExceptions.toArray(PsiClassType.EMPTY_ARRAY)); + addInstruction(new ControlTransferInstruction(null)); // DfaControlTransferValue is on stack + finishElement(resourceList); + assert myTrapStack.getHead() instanceof Trap.InsideFinally; + myTrapStack = myTrapStack.getTail(); + } + } + @Override public void visitResourceList(PsiResourceList resourceList) { for (PsiResourceListElement resource : resourceList) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/controlTransfer.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/controlTransfer.kt index af1b08f6bf61..462a16dc5ecc 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/controlTransfer.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/controlTransfer.kt @@ -59,14 +59,23 @@ open class ControlTransferInstruction(val transfer: DfaControlTransferValue?) : fun getPossibleTargetInstructions(allInstructions: Array) = getPossibleTargetIndices().map { allInstructions[it] } - override fun toString() = transfer.toString() + override fun toString() = if (transfer == null) "RET" else "TRANSFER " + transfer.toString() } sealed class Trap(val anchor: PsiElement) { - class TryCatch(tryStatement : PsiTryStatement, val clauses: LinkedHashMap): Trap(tryStatement) - class TryFinally(val finallyBlock: PsiCodeBlock, val jumpOffset: ControlFlow.ControlFlowOffset): Trap(finallyBlock) - class TwrFinally(resourceList: PsiResourceList, val jumpOffset: ControlFlow.ControlFlowOffset): Trap(resourceList) - class InsideFinally(val finallyBlock: PsiCodeBlock): Trap(finallyBlock) + class TryCatch(tryStatement: PsiTryStatement, val clauses: LinkedHashMap) + : Trap(tryStatement) { + override fun toString(): String = "TryCatch -> " + clauses.values + } + class TryFinally(finallyBlock: PsiCodeBlock, val jumpOffset: ControlFlow.ControlFlowOffset): Trap(finallyBlock) { + override fun toString(): String = "TryFinally -> " + jumpOffset + } + class TwrFinally(resourceList: PsiResourceList, val jumpOffset: ControlFlow.ControlFlowOffset): Trap(resourceList) { + override fun toString(): String = "TwrFinally -> " + jumpOffset + } + class InsideFinally(finallyBlock: PsiElement): Trap(finallyBlock) { + override fun toString(): String = "InsideFinally" + } internal fun getPossibleTargets(): Collection { return when (this) { diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/TryWithResourcesCloseException.java b/java/java-tests/testData/inspection/dataFlow/fixture/TryWithResourcesCloseException.java index c8cb8435ec48..dc3e2c7b15d8 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/TryWithResourcesCloseException.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/TryWithResourcesCloseException.java @@ -1,4 +1,5 @@ import java.io.*; +import java.util.*; // IDEA-181860 class bugcheck { @@ -48,4 +49,20 @@ class bugcheck { // s is never null here return s.trim(); } + + static List inLoop(String[] paths) { + List strings = new ArrayList<>(); + for (String path : paths) { + try (BufferedReader br = new BufferedReader(new FileReader(path))) { + String s = br.readLine(); + if (s != null) { + strings.add(s); + } + } + catch (IOException e) { + e.printStackTrace(); + } + } + return strings; + } } \ No newline at end of file