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 6d1d14de2902..06a15d328efa 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 @@ -51,7 +51,8 @@ public class StandardInstructionVisitor extends InstructionVisitor { private static final Object ANY_VALUE = new Object(); private static final Set OPTIONAL_METHOD_NAMES = ContainerUtil - .set("of", "ofNullable", "fromNullable", "empty", "absent", "or", "orElseGet", "ifPresent", "map", "flatMap", "filter", "transform"); + .set("of", "ofNullable", "fromNullable", "empty", "absent", "or", "orElse", "orElseGet", "ifPresent", "map", "flatMap", "filter", + "transform"); private static final CallMapper KNOWN_METHOD_RANGES = new CallMapper() .register(CallMatcher.instanceCall("java.time.LocalDateTime", "getHour"), LongRangeSet.range(0, 23)) .register(CallMatcher.instanceCall("java.time.LocalDateTime", "getMinute", "getSecond"), LongRangeSet.range(0, 59)) @@ -276,6 +277,23 @@ public class StandardInstructionVisitor extends InstructionVisitor { case "absent": result = runner.getFactory().getOptionalFactory().getOptional(false); break; + case "orElse": + if (argValues != null && argValues.length == 1) { + switch (memState.checkOptional(qualifier)) { + case YES: + result = runner.getFactory().createTypeValue(instruction.getResultType(), Nullness.NOT_NULL); + break; + case NO: + result = argValues[0]; + break; + case UNSURE: + Nullness nullness = + memState.isNotNull(argValues[0]) ? Nullness.NOT_NULL : memState.isNull(argValues[0]) ? Nullness.NULLABLE : Nullness.UNKNOWN; + result = runner.getFactory().createTypeValue(instruction.getResultType(), nullness); + break; + } + } + break; case "filter": case "flatMap": case "ifPresent": diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/OptionalOrElse.java b/java/java-tests/testData/inspection/dataFlow/fixture/OptionalOrElse.java new file mode 100644 index 000000000000..8fa53bc5e1dc --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/OptionalOrElse.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +class OptionalOrElse { + @NotNull + Boolean bug(@Nullable Boolean whatever) { + return Optional.ofNullable(whatever).orElse(null); + } + + @NotNull + String nullable(Optional opt) { + return opt.orElse(null); + } + + @NotNull + String ok(Optional opt) { + return opt.orElse(""); + } + + @NotNull + String strangeButOk(Optional opt) { + if(opt.isPresent()) { + return opt.orElse(null); + } else { + return ""; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspection8Test.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspection8Test.java index 01f7e60bf389..1f37a1ec9577 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspection8Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspection8Test.java @@ -61,6 +61,7 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase { public void testGenericParameterNullity() { doTestWithCustomAnnotations(); } public void testOptionalOfNullable() { doTest(); } + public void testOptionalOrElse() { doTest(); } public void testOptionalIsPresent() { doTest(); } public void testOptionalGetWithoutIsPresent() { myFixture.addClass("package org.junit;" +