[java-dfa] More annotations; annotations for comparators; warn on nullity violation from methodref return

GitOrigin-RevId: d0b1a4967d361f409d4d25562c595e2812fc8044
This commit is contained in:
Tagir Valeev
2024-09-19 19:06:26 +00:00
committed by intellij-monorepo-bot
parent 5b16802ed3
commit c3ecaaa190
7 changed files with 202 additions and 5 deletions
@@ -61,9 +61,14 @@ public class MethodReferenceInstruction extends ExpressionPushingInstruction {
NullabilityProblemKind.callMethodRefNPE.problem(methodRef, null));
}
List<? extends MethodContract> contracts = JavaMethodContractUtil.getMethodCallContracts(method, null);
if (contracts.isEmpty() || !JavaMethodContractUtil.isPure(method)) return;
PsiType returnType = substitutor.substitute(method.getReturnType());
DfaValue defaultResult = interpreter.getFactory().fromDfType(typedObject(returnType, DfaPsiUtil.getElementNullability(returnType, method)));
Nullability expectedNullability = DfaPsiUtil.getTypeNullability(LambdaUtil.getFunctionalInterfaceReturnType(methodRef));
if (expectedNullability == Nullability.NOT_NULL) {
CheckNotNullInstruction.checkNotNullable(interpreter, state, defaultResult,
NullabilityProblemKind.nullableFunctionReturn.problem(methodRef, null));
}
if (contracts.isEmpty() || !JavaMethodContractUtil.isPure(method)) return;
Set<DfaCallState> currentStates = Collections.singleton(new DfaCallState(state.createClosureState(), callArguments, defaultResult));
JavaMethodReferenceReturnAnchor anchor = new JavaMethodReferenceReturnAnchor(methodRef);
DfaValue[] args = callArguments.toArray();
@@ -0,0 +1,12 @@
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class ComparatorComparingContract {
Comparator<MyObj> comparatorMR = Comparator.comparing(<warning descr="Function may return null, but it's not allowed here">MyObj::getName</warning>);
Comparator<MyObj> comparatorLambda = Comparator.comparing(myObj -> <warning descr="Expression 'myObj.getName()' might evaluate to null but is returned by the method declared as @NotNull">myObj.getName()</warning>);
interface MyObj {
@Nullable String getName();
}
}
@@ -1,8 +1,13 @@
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class NullabilityJdk9 {
public class NullabilityJdk11 {
void test() {
void test(List<String> input) {
List<String> listArray = List.of(new String[]{"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", <warning descr="'null' is stored to an array of @NotNull elements">null</warning>});
if (<warning descr="Condition 'List.copyOf(input).get(12) == null' is always 'false'">List.copyOf(input).get(12) == null</warning>) {}
List<Integer> list = List.of(1,2,3,<warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>);
Set<String> set = Set.of("foo", "bar", <warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>, "baz");
Map<String, Integer> map = Map.of("x", <warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>,
@@ -12,4 +17,9 @@ public class NullabilityJdk9 {
Integer[] array = null;
List<Integer> list1 = List.of(<warning descr="Passing 'null' argument to parameter annotated as @NotNull">array</warning>);
}
void cmp(Comparator<@NotNull String> cmp) {
if (cmp.compare(<warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>, "hello") == 0) return;
if (Comparator.nullsFirst(cmp).compare(null, "hello") == 0) return;
}
}
@@ -17,6 +17,10 @@ public class DataFlowInspection11Test extends DataFlowInspectionTestCase {
return JavaTestUtil.getJavaTestDataPath() + "/inspection/dataFlow/fixture/";
}
public void testNullabilityJdk11() { doTest();}
public void testComparatorComparingContract() { doTest();}
public void testStreamCollector10Inlining() { doTest(); }
public void testStreamFlatMapOptional() {doTest();}
@@ -18,7 +18,6 @@ public class DataFlowInspection9Test extends DataFlowInspectionTestCase {
return JavaTestUtil.getJavaTestDataPath() + "/inspection/dataFlow/fixture/";
}
public void testNullabilityJdk9() { doTest();}
public void testMutabilityJdk9() { doTest();}
public void testMutabilityInferred() { doTest(); }
public void testObjectsRequireNonNullElse() { doTest(); }
@@ -2679,6 +2679,158 @@
<val name="pure" val="true"/>
</annotation>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; comparing(java.util.function.Function&lt;? super T,? extends U&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; comparing(java.util.function.Function&lt;? super T,? extends U&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.NotNull' typePath="/2/*"/>
</item>
<item
name='java.util.Comparator java.util.Comparator&lt;T&gt; comparing(java.util.function.Function&lt;? super T,? extends U&gt;, java.util.Comparator&lt;? super U&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
</item>
<item
name='java.util.Comparator java.util.Comparator&lt;T&gt; comparing(java.util.function.Function&lt;? super T,? extends U&gt;, java.util.Comparator&lt;? super U&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='java.util.Comparator java.util.Comparator&lt;T&gt; comparing(java.util.function.Function&lt;? super T,? extends U&gt;, java.util.Comparator&lt;? super U&gt;) 1'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; comparingDouble(java.util.function.ToDoubleFunction&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; comparingDouble(java.util.function.ToDoubleFunction&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; comparingInt(java.util.function.ToIntFunction&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; comparingInt(java.util.function.ToIntFunction&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; comparingLong(java.util.function.ToLongFunction&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; comparingLong(java.util.function.ToLongFunction&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; naturalOrder()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; nullsFirst(java.util.Comparator&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.Nullable' typePath="/1"/>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; nullsFirst(java.util.Comparator&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.Nullable'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; nullsLast(java.util.Comparator&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.Nullable' typePath="/1"/>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; nullsLast(java.util.Comparator&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.Nullable'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; reverseOrder()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; reversed()'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparing(java.util.Comparator&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparing(java.util.Comparator&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparing(java.util.function.Function&lt;? super T,? extends U&gt;)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparing(java.util.function.Function&lt;? super T,? extends U&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.NotNull' typePath="/2/*"/>
</item>
<item
name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparing(java.util.function.Function&lt;? super T,? extends U&gt;, java.util.Comparator&lt;? super U&gt;)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparing(java.util.function.Function&lt;? super T,? extends U&gt;, java.util.Comparator&lt;? super U&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparing(java.util.function.Function&lt;? super T,? extends U&gt;, java.util.Comparator&lt;? super U&gt;) 1'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparingDouble(java.util.function.ToDoubleFunction&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparingDouble(java.util.function.ToDoubleFunction&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparingInt(java.util.function.ToIntFunction&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparingInt(java.util.function.ToIntFunction&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparingLong(java.util.function.ToLongFunction&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Comparator java.util.Comparator&lt;T&gt; thenComparingLong(java.util.function.ToLongFunction&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.Date Date(int, int, int)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
@@ -230,13 +230,28 @@
<item name='java.util.function.Predicate java.util.function.Predicate&lt;T&gt; and(java.util.function.Predicate&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.function.Predicate java.util.function.Predicate&lt;T&gt; isEqual(java.lang.Object)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
</item>
<item name='java.util.function.Predicate java.util.function.Predicate&lt;T&gt; negate()'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.function.Predicate java.util.function.Predicate&lt;T&gt; or(java.util.function.Predicate&lt;? super T&gt;)'>
<item name='java.util.function.Predicate java.util.function.Predicate&lt;T&gt; not(java.util.function.Predicate&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.function.Predicate java.util.function.Predicate&lt;T&gt; not(java.util.function.Predicate&lt;? super T&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.util.function.Predicate java.util.function.Predicate&lt;T&gt; or(java.util.function.Predicate&lt;? super T&gt;)'>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="pure" val="true"/>
</annotation>