diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java index e2779e31b04c..eb486e47ee56 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java @@ -689,7 +689,7 @@ public class CFGBuilder { } // Unknown function flushFields(); - myAnalyzer.addConditionalRuntimeThrow(); + myAnalyzer.addConditionalErrorThrow(); PsiType functionalInterfaceType = functionalExpression.getType(); myAnalyzer.addMethodThrows(LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType), null); PsiType returnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType); 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 b458c698e036..bad93d7e26f8 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 @@ -129,6 +129,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { return myCodeFragment; } + @NotNull private PsiClassType createClassType(GlobalSearchScope scope, String fqn) { PsiClass aClass = JavaPsiFacade.getInstance(myProject).findClass(fqn, scope); if (aClass != null) return JavaPsiFacade.getElementFactory(myProject).createType(aClass); @@ -1028,7 +1029,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { finishElement(statement); } - void addConditionalRuntimeThrow() { + void addConditionalErrorThrow() { if (!shouldHandleException()) { return; } @@ -1036,10 +1037,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { pushUnknown(); final ConditionalGotoInstruction ifNoException = addInstruction(new ConditionalGotoInstruction(null, false, null)); - pushUnknown(); - final ConditionalGotoInstruction ifError = addInstruction(new ConditionalGotoInstruction(null, false, null)); - throwException(myExceptionCache.get(JAVA_LANG_RUNTIME_EXCEPTION), null); - ifError.setOffset(myCurrentFlow.getInstructionCount()); throwException(myExceptionCache.get(JAVA_LANG_ERROR), null); ifNoException.setOffset(myCurrentFlow.getInstructionCount()); @@ -1145,7 +1142,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { pushTrap(new InsideFinally(resourceList)); startElement(resourceList); addInstruction(new FlushFieldsInstruction()); - addThrows(null, closerExceptions.toArray(PsiClassType.EMPTY_ARRAY)); + addThrows(null, closerExceptions); controlTransfer(new ExitFinallyTransfer(twrFinallyDescriptor), FList.emptyList()); // DfaControlTransferValue is on stack finishElement(resourceList); popTrap(InsideFinally.class); @@ -1489,7 +1486,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { addInstruction(new UnwrapSpecialFieldInstruction(SpecialField.UNBOX)); } else if (TypeConversionUtil.isPrimitiveAndNotNull(actualType) && TypeConversionUtil.isAssignableFromPrimitiveWrapper(expectedType)) { - addConditionalRuntimeThrow(); + addConditionalErrorThrow(); PsiType boxedType = ((PsiPrimitiveType)actualType).getBoxedType(context); addInstruction(new BoxingInstruction(boxedType)); } @@ -1648,13 +1645,17 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { } void addMethodThrows(PsiMethod method, @Nullable PsiElement explicitCall) { - if (method != null && shouldHandleException()) { - addThrows(explicitCall, method.getThrowsList().getReferencedTypes()); + if (shouldHandleException()) { + addThrows(explicitCall, method == null ? Collections.emptyList() : Arrays.asList(method.getThrowsList().getReferencedTypes())); } } - private void addThrows(@Nullable PsiElement explicitCall, PsiClassType[] refs) { - for (PsiClassType ref : refs) { + private void addThrows(@Nullable PsiElement explicitCall, Collection exceptions) { + List allExceptions = new ArrayList<>(exceptions); + allExceptions.add(myExceptionCache.get(JAVA_LANG_ERROR).getThrowable().getPsiType()); + allExceptions.add(myExceptionCache.get(JAVA_LANG_RUNTIME_EXCEPTION).getThrowable().getPsiType()); + List refs = PsiDisjunctionType.flattenAndRemoveDuplicates(allExceptions); + for (PsiType ref : refs) { pushUnknown(); ConditionalGotoInstruction cond = new ConditionalGotoInstruction(null, false, null); addInstruction(cond); @@ -1743,7 +1744,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { } void addBareCall(@Nullable PsiMethodCallExpression expression, @NotNull PsiReferenceExpression reference) { - addConditionalRuntimeThrow(); + addConditionalErrorThrow(); PsiMethod method = ObjectUtils.tryCast(reference.resolve(), PsiMethod.class); List contracts = method == null ? Collections.emptyList() : @@ -1766,7 +1767,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, PsiType.BOOLEAN)); ConditionalGotoInstruction ifNotFail = new ConditionalGotoInstruction(null, true, null); addInstruction(ifNotFail); - addInstruction(new ReturnInstruction(myFactory.controlTransfer(new ExceptionTransfer(null), myTrapStack), anchor)); + addInstruction(new ReturnInstruction(myFactory.controlTransfer(myExceptionCache.get(JAVA_LANG_THROWABLE), myTrapStack), anchor)); ifNotFail.setOffset(myCurrentFlow.getInstructionCount()); } @@ -1852,7 +1853,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { handleEscapedVariables(anonymousClass); } - addConditionalRuntimeThrow(); + addConditionalErrorThrow(); DfaValue precalculatedNewValue = getPrecalculatedNewValue(expression); List contracts = constructor == null ? Collections.emptyList() : JavaMethodContractUtil.getMethodContracts(constructor); addInstruction(new MethodCallInstruction(expression, precalculatedNewValue, DfaUtil.addRangeContracts(constructor, contracts))); 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 62d6caeb6d99..0e8833e1bf2a 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 @@ -43,7 +43,7 @@ interface TransferTarget { /** @return next instruction states assuming no traps */ fun dispatch(state: DfaMemoryState, runner: DataFlowRunner) : List = emptyList() } -data class ExceptionTransfer(val throwable: DfaPsiType?) : TransferTarget { +data class ExceptionTransfer(val throwable: DfaPsiType) : TransferTarget { override fun toString(): String = "Exception($throwable)" } data class InstructionTransfer(val offset: ControlFlow.ControlFlowOffset, private val toFlush: List) : TransferTarget { diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/LambdaWritesArrayInTry.java b/java/java-tests/testData/inspection/dataFlow/fixture/LambdaWritesArrayInTry.java new file mode 100644 index 000000000000..5c98b843fa6c --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/LambdaWritesArrayInTry.java @@ -0,0 +1,17 @@ +class App { + static void f(Runnable r) { + r.run(); + } + + public static void main(String[] args) { + RuntimeException[] exception = {null}; + try { + f(() -> { + exception[0] = new RuntimeException(); + throw exception[0]; + }); + } catch (RuntimeException e) { + System.out.println(e == exception[0]); // was false-positive + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java index af4cff7ac9dc..cfce24858aa6 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java @@ -245,4 +245,5 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase { doTest(); } + public void testLambdaWritesArrayInTry() { doTest(); } } \ No newline at end of file