diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java index e3d13152e6a3..4ce5270446e1 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java @@ -33,6 +33,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Predicate; public class DataFlowRunner { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.DataFlowRunner"); @@ -42,7 +43,7 @@ public class DataFlowRunner { private final MultiMap myNestedClosures = new MultiMap<>(); // Closures which were registered for previous instruction and can be queried by visitor // to adjust them somehow - private final List myStackTopClosures = new ArrayList<>(); + private final Map myStackTopClosures = new HashMap<>(); @NotNull private final DfaValueFactory myValueFactory; // Maximum allowed attempts to process instruction. Fail as too complex to process if certain instruction @@ -82,8 +83,12 @@ public class DataFlowRunner { return Collections.singletonList(createMemoryState()); } - List getStackTopClosures() { - return new ArrayList<>(myStackTopClosures); + void updateStackTopClosures(Predicate updater) { + myStackTopClosures.forEach((state, element) -> { + if(!updater.test(state)) { + myNestedClosures.remove(element, state); + } + }); } @NotNull @@ -293,14 +298,14 @@ public class DataFlowRunner { for (PsiMethod method : nestedClass.getMethods()) { PsiCodeBlock body = method.getBody(); if (body != null) { - myNestedClosures.putValue(body, createClosureState(state)); + createClosureState(body, state); } } for (PsiClassInitializer initializer : nestedClass.getInitializers()) { - myNestedClosures.putValue(initializer.getBody(), createClosureState(state)); + createClosureState(initializer.getBody(), state); } for (PsiField field : nestedClass.getFields()) { - myNestedClosures.putValue(field, createClosureState(state)); + createClosureState(field, state); } } @@ -308,15 +313,14 @@ public class DataFlowRunner { DfaMemoryState state = instructionState.getMemoryState(); PsiElement body = expr.getBody(); if (body != null) { - myNestedClosures.putValue(body, createClosureState(state)); + createClosureState(body, state); } } - @NotNull - private DfaMemoryState createClosureState(DfaMemoryState state) { + private void createClosureState(PsiElement anchor, DfaMemoryState state) { DfaMemoryState closureState = state.createClosureState(); - myStackTopClosures.add(closureState); - return closureState; + myStackTopClosures.put(closureState, anchor); + myNestedClosures.putValue(anchor, closureState); } @NotNull diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index b8d0bbdf8804..997cc662c476 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -373,7 +373,6 @@ public class StandardInstructionVisitor extends InstructionVisitor { if (methodName == null || !OPTIONAL_METHOD_NAMES.contains(methodName)) return Collections.emptyList(); PsiMethod method = call.resolveMethod(); if (method == null || !TypeUtils.isOptional(method.getContainingClass())) return Collections.emptyList(); - List closures = runner.getStackTopClosures(); DfaCallArguments arguments = popCall(instruction, runner, memState, false); DfaValue[] argValues = arguments.myArguments; DfaValue result = null; @@ -416,9 +415,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { case "transform": { DfaOptionalValue optional = factory.getOptionalFactory().getOptional(!methodName.startsWith("or")); DfaValue relation = factory.createCondition(arguments.myQualifier, RelationType.IS, optional); - for (DfaMemoryState closure : closures) { - closure.applyCondition(relation); - } + runner.updateStackTopClosures(state -> state.applyCondition(relation)); break; } default: diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/OptionalGetWithoutIsPresent.java b/java/java-tests/testData/inspection/dataFlow/fixture/OptionalGetWithoutIsPresent.java index 7b5584c51066..36299e7c0a6d 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/OptionalGetWithoutIsPresent.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/OptionalGetWithoutIsPresent.java @@ -371,4 +371,15 @@ class OptionalWithoutIsPresent { } String res = Optional.empty().orElseThrow(RuntimeException::new); } + + void testOrElseGet() { + final Optional a = Optional.ofNullable(Math.random() > 0.5 ? null:""); + final Optional b = Optional.ofNullable(Math.random() > 0.5 ? null:""); + if (a.isPresent() || b.isPresent()) { + String result = a.orElseGet(() -> b.get()); // no warning + System.out.println(result); + } + String result = a.orElseGet(() -> b.get()); + System.out.println(result); + } } \ No newline at end of file