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 7af1a419cc09..2d8bedfaaafa 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 @@ -175,10 +175,31 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { private void finishElement(PsiElement element) { myCurrentFlow.finishElement(element); if (element instanceof PsiStatement && !(element instanceof PsiReturnStatement)) { - addInstruction(new FinishElementInstruction(element)); + List synthetics = getSynthetics(element); + FinishElementInstruction instruction = new FinishElementInstruction(element); + instruction.getVarsToFlush().addAll(synthetics); + addInstruction(instruction); } } + @NotNull + private List getSynthetics(PsiElement element) { + int startOffset = myCurrentFlow.getStartOffset(element).getInstructionOffset(); + List synthetics = new ArrayList<>(); + for (DfaValue value : myFactory.getValues()) { + if (value instanceof DfaVariableValue) { + DfaVariableValue var = (DfaVariableValue)value; + DfaVariableSource source = var.getSource(); + if (source instanceof Synthetic) { + if (((Synthetic)source).myLocation >= startOffset) { + synthetics.add(var); + } + } + } + } + return synthetics; + } + @Override public void visitErrorElement(PsiErrorElement element) { throw new CannotAnalyzeException(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java index 7ebdf5238ee2..8e2ee08c06ae 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java @@ -161,6 +161,4 @@ public interface DfaMemoryState { boolean isEphemeral(); boolean isEmptyStack(); - - void cleanUpTempVariables(); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 69ef8384bf04..3c7a54d31f17 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -606,12 +606,6 @@ public class DfaMemoryStateImpl implements DfaMemoryState { return myStack.isEmpty(); } - @Override - public void cleanUpTempVariables() { - List values = ContainerUtil.filter(myVariableStates.keySet(), ControlFlowAnalyzer::isTempVariable); - values.forEach(this::flushVariable); - } - @Override public boolean castTopOfStack(@NotNull DfaPsiType type) { DfaValue value = unwrap(peek()); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java index 21e621441956..94a30764ae67 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java @@ -415,7 +415,7 @@ public class StreamChainInliner implements CallInliner { void before(CFGBuilder builder) { if (myStreamSource == null) { PsiExpression arg = myCall.getArgumentList().getExpressions()[0]; - builder.pushExpression(arg).checkNotNull(arg, NullabilityProblemKind.passingNullableToNotNullParameter).pop(); + builder.evaluateFunction(arg); } super.before(builder); } @@ -426,13 +426,16 @@ public class StreamChainInliner implements CallInliner { builder.assignTo(myParameter).pop(); buildStreamCFG(builder, myChain, myStreamSource); } else { + PsiExpression arg = myCall.getArgumentList().getExpressions()[0]; PsiType outType = StreamApiUtil.getStreamElementType(myCall.getType()); - builder.pop() - .pushUnknown() - .ifConditionIs(true) - .doWhileUnknown() - .push(builder.getFactory().createTypeValue(outType, Nullability.UNKNOWN)) - .chain(myNext::iteration) + builder.invokeFunction(1, arg, Nullability.NULLABLE) + .ifNotNull() + .pushUnknown() + .ifConditionIs(true) + .doWhileUnknown() + .push(builder.getFactory().createTypeValue(outType, Nullability.UNKNOWN)) + .chain(myNext::iteration) + .end() .end() .end(); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FinishElementInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FinishElementInstruction.java index 7c109b7a4ed1..20a882a6898a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FinishElementInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FinishElementInstruction.java @@ -43,7 +43,6 @@ public class FinishElementInstruction extends Instruction { state.flushVariable(value); } } - state.cleanUpTempVariables(); return nextInstruction(runner, state); } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/FlatMapSideEffect.java b/java/java-tests/testData/inspection/dataFlow/fixture/FlatMapSideEffect.java new file mode 100644 index 000000000000..68d24c3c18ca --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/FlatMapSideEffect.java @@ -0,0 +1,34 @@ +import java.util.*; +import java.util.stream.*; + +// IDEA-200094 +class Main { + void flatMapAlwaysNull(List input) { + List side = new ArrayList<>(); + long count = input.stream().flatMap(e -> { + if(!e.isEmpty()) side.add(e); + return null; + }).count(); + if (side.isEmpty()) {} // not known + if (count > 0) {} + } + + public static void main(String[] args) { + new Main().myMethod(); + } + + private void myMethod() { + List numberOne = Collections.singletonList(1); + List collectionBeingModifiedSometimes = new ArrayList<>(); + + List numberTwo = numberOne.stream().flatMap(entry -> { + if (Math.random() > 0.5) { + collectionBeingModifiedSometimes.add(999); + } + return Stream.of(entry * 2); + }).collect(Collectors.toList()); + + String text = collectionBeingModifiedSometimes.size() == 0 ? "empty" : "nonempty"; + System.out.println("" + numberOne + " " + numberTwo + " " + text); + } +} \ 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 9fa0b36243af..a6c9a461757e 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java @@ -243,4 +243,5 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase { doTest(); } public void testObjectsEquals() { doTest(); } + public void testFlatMapSideEffect() { doTest(); } } \ No newline at end of file