mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-dfa] Native support of ObjectUtils.{all,any}[not]Null methods
Fixes IDEA-373254 Recognized ObjectUtils.allNotNull method in data flow inspection (at least, my understanding of it) GitOrigin-RevId: 5bf63072a84b22a3a5de58d53c8521f1296a0fd1
This commit is contained in:
committed by
intellij-monorepo-bot
parent
43effd21ae
commit
ee1c23f88b
@@ -298,6 +298,20 @@ public class CFGBuilder {
|
||||
return add(new ResultOfInstruction(new JavaExpressionAnchor(expression)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate instructions to apply a boolean 'not' operation to top stack value
|
||||
* <p>
|
||||
* Stack before: ... value
|
||||
* <p>
|
||||
* Stack after: ... not(value)
|
||||
*
|
||||
* @return this builder
|
||||
*/
|
||||
public CFGBuilder not() {
|
||||
add(new NotInstruction(null));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate instructions to perform an Class.isInstance operation
|
||||
* <p>
|
||||
|
||||
+1
-1
@@ -2752,7 +2752,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
private static final CallInliner[] INLINERS = {
|
||||
new AssertJInliner(), new OptionalChainInliner(), new LambdaInliner(), new CollectionUpdateInliner(),
|
||||
new StreamChainInliner(), new MapUpdateInliner(), new AssumeInliner(), new ClassMethodsInliner(),
|
||||
new AssertAllInliner(), new BoxingInliner(), new SimpleMethodInliner(), new AccessorInliner(),
|
||||
new AssertAllInliner(), new AllNotNullInliner(), new BoxingInliner(), new SimpleMethodInliner(), new AccessorInliner(),
|
||||
new TransformInliner(), new EnumCompareInliner(), new IndexOfInliner(), new AssertInstanceOfInliner()
|
||||
};
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection.dataFlow.java.inliner;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.java.CFGBuilder;
|
||||
import com.intellij.codeInspection.dataFlow.types.DfTypes;
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.PsiMethodCallExpression;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
import com.siyeh.ig.psiutils.MethodCallUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.siyeh.ig.callMatcher.CallMatcher.anyOf;
|
||||
import static com.siyeh.ig.callMatcher.CallMatcher.staticCall;
|
||||
|
||||
/**
|
||||
* JUnit5 Assertions.assertAll
|
||||
*/
|
||||
public class AllNotNullInliner implements CallInliner {
|
||||
private static final CallMatcher NULL_TESTS =
|
||||
anyOf(
|
||||
staticCall("org.apache.commons.lang3.ObjectUtils", "allNull").parameterTypes("java.lang.Object..."),
|
||||
staticCall("org.apache.commons.lang3.ObjectUtils", "allNotNull").parameterTypes("java.lang.Object..."),
|
||||
staticCall("org.apache.commons.lang3.ObjectUtils", "anyNull").parameterTypes("java.lang.Object..."),
|
||||
staticCall("org.apache.commons.lang3.ObjectUtils", "anyNotNull").parameterTypes("java.lang.Object...")
|
||||
);
|
||||
|
||||
@Override
|
||||
public boolean tryInlineCall(@NotNull CFGBuilder builder, @NotNull PsiMethodCallExpression call) {
|
||||
if (!NULL_TESTS.matches(call) || !MethodCallUtils.isVarArgCall(call)) return false;
|
||||
PsiExpression[] args = call.getArgumentList().getExpressions();
|
||||
String methodName = call.getMethodExpression().getReferenceName();
|
||||
PsiClassType objectType = PsiType.getJavaLangObject(call.getManager(), call.getResolveScope());
|
||||
boolean allMatchResult = "allNotNull".equals(methodName) || "allNull".equals(methodName);
|
||||
builder.push(DfTypes.booleanValue(!allMatchResult));
|
||||
for (PsiExpression arg : args) {
|
||||
builder.pushExpression(arg)
|
||||
.boxUnbox(arg, objectType);
|
||||
if ("allNotNull".equals(methodName) || "anyNull".equals(methodName)) {
|
||||
builder.ifNotNull();
|
||||
} else {
|
||||
builder.ifNull();
|
||||
}
|
||||
}
|
||||
builder.not();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
builder.end();
|
||||
}
|
||||
builder.resultOf(call);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.apache.commons.lang3;
|
||||
|
||||
class ObjectUtils {
|
||||
public static native boolean allNotNull(final Object... values);
|
||||
public static native boolean allNull(final Object... values);
|
||||
public static native boolean anyNotNull(final Object... values);
|
||||
public static native boolean anyNull(final Object... values);
|
||||
}
|
||||
|
||||
class Test {
|
||||
void use(Object o1, Object o2, Object o3, Object o4) {
|
||||
if (ObjectUtils.allNull(o1, o2, o3, o4)) {
|
||||
if (<warning descr="Condition 'o1 == null' is always 'true'">o1 == null</warning>) {}
|
||||
if (<warning descr="Condition 'o2 == null' is always 'true'">o2 == null</warning>) {}
|
||||
if (<warning descr="Condition 'o3 == null' is always 'true'">o3 == null</warning>) {}
|
||||
if (<warning descr="Condition 'o4 == null' is always 'true'">o4 == null</warning>) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.allNull(o1, o2, o3, o4)' is always 'true'">ObjectUtils.allNull(o1, o2, o3, o4)</warning>) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.anyNull(o1, o2, o3, o4)' is always 'true'">ObjectUtils.anyNull(o1, o2, o3, o4)</warning>) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.anyNotNull(o1, o2, o3, o4)' is always 'false'">ObjectUtils.anyNotNull(o1, o2, o3, o4)</warning>) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.allNotNull(o1, o2, o3, o4)' is always 'false'">ObjectUtils.allNotNull(o1, o2, o3, o4)</warning>) {}
|
||||
}
|
||||
if (ObjectUtils.anyNull(o1, o2, o3, o4)) {
|
||||
if (o1 != null) {
|
||||
if (o2 != null) {
|
||||
if (o3 != null) {
|
||||
if (<warning descr="Condition 'o4 != null' is always 'false'">o4 != null</warning>) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ObjectUtils.allNull(o1, o2, o3, o4)) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.anyNull(o1, o2, o3, o4)' is always 'true'">ObjectUtils.anyNull(o1, o2, o3, o4)</warning>) {}
|
||||
if (ObjectUtils.anyNotNull(o1, o2, o3, o4)) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.allNotNull(o1, o2, o3, o4)' is always 'false'">ObjectUtils.allNotNull(o1, o2, o3, o4)</warning>) {}
|
||||
}
|
||||
if (ObjectUtils.anyNotNull(o1, o2, o3, o4)) {
|
||||
if (o1 == null) {
|
||||
if (o2 == null) {
|
||||
if (o3 == null) {
|
||||
if (<warning descr="Condition 'o4 == null' is always 'false'">o4 == null</warning>) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (<warning descr="Condition 'ObjectUtils.allNull(o1, o2, o3, o4)' is always 'false'">ObjectUtils.allNull(o1, o2, o3, o4)</warning>) {}
|
||||
if (ObjectUtils.anyNull(o1, o2, o3, o4)) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.anyNotNull(o1, o2, o3, o4)' is always 'true'">ObjectUtils.anyNotNull(o1, o2, o3, o4)</warning>) {}
|
||||
if (ObjectUtils.allNotNull(o1, o2, o3, o4)) {}
|
||||
}
|
||||
if (ObjectUtils.allNotNull(o1, o2, o3, o4)) {
|
||||
if (<warning descr="Condition 'o1 != null' is always 'true'">o1 != null</warning>) {}
|
||||
if (<warning descr="Condition 'o2 != null' is always 'true'">o2 != null</warning>) {}
|
||||
if (<warning descr="Condition 'o3 != null' is always 'true'">o3 != null</warning>) {}
|
||||
if (<warning descr="Condition 'o4 != null' is always 'true'">o4 != null</warning>) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.allNull(o1, o2, o3, o4)' is always 'false'">ObjectUtils.allNull(o1, o2, o3, o4)</warning>) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.anyNull(o1, o2, o3, o4)' is always 'false'">ObjectUtils.anyNull(o1, o2, o3, o4)</warning>) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.anyNotNull(o1, o2, o3, o4)' is always 'true'">ObjectUtils.anyNotNull(o1, o2, o3, o4)</warning>) {}
|
||||
if (<warning descr="Condition 'ObjectUtils.allNotNull(o1, o2, o3, o4)' is always 'true'">ObjectUtils.allNotNull(o1, o2, o3, o4)</warning>) {}
|
||||
}
|
||||
}
|
||||
|
||||
void box(int i1, int i2, int i3, int i4) {
|
||||
if (<warning descr="Condition 'ObjectUtils.allNotNull(i1, i2, i3, i4)' is always 'true'">ObjectUtils.allNotNull(i1, i2, i3, i4)</warning>) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,4 +188,8 @@ public class DataFlowInspection21Test extends DataFlowInspectionTestCase {
|
||||
public void testSwitchNoUnreachableBranchesDueToUnresolvedType() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testObjectUtilsNullMethods() {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user