IDEA-170136 Null analysis inspection misses orElse(null);

This commit is contained in:
Tagir Valeev
2017-03-27 13:06:30 +07:00
parent ea34c4ebdf
commit 58dc190a9d
3 changed files with 65 additions and 1 deletions
@@ -51,7 +51,8 @@ public class StandardInstructionVisitor extends InstructionVisitor {
private static final Object ANY_VALUE = new Object();
private static final Set<String> 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<LongRangeSet> KNOWN_METHOD_RANGES = new CallMapper<LongRangeSet>()
.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":
@@ -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 <warning descr="Expression 'Optional.ofNullable(whatever).orElse(null)' might evaluate to null but is returned by the method declared as @NotNull">Optional.ofNullable(whatever).orElse(null)</warning>;
}
@NotNull
String nullable(Optional<String> opt) {
return <warning descr="Expression 'opt.orElse(null)' might evaluate to null but is returned by the method declared as @NotNull">opt.orElse(null)</warning>;
}
@NotNull
String ok(Optional<String> opt) {
return opt.orElse("");
}
@NotNull
String strangeButOk(Optional<String> opt) {
if(opt.isPresent()) {
return opt.orElse(null);
} else {
return "";
}
}
}
@@ -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;" +