[java-dfa] IDEA-333294 Support Unit 5.8 assertInstanceOf in dataflow

GitOrigin-RevId: 5a772af8968128e8a95465d2ab5a42cb09006d3a
This commit is contained in:
Tagir Valeev
2023-09-28 10:30:00 +00:00
committed by intellij-monorepo-bot
parent 477648476f
commit d7160411f2
5 changed files with 75 additions and 3 deletions
@@ -294,8 +294,8 @@ public class CFGBuilder {
* @param anchor element to bind this instruction to
* @return this builder
*/
public CFGBuilder isInstance(PsiMethodCallExpression anchor) {
return add(new InstanceofInstruction(new JavaExpressionAnchor(anchor), true));
public CFGBuilder isInstance(@Nullable PsiMethodCallExpression anchor) {
return add(new InstanceofInstruction(anchor == null ? null : new JavaExpressionAnchor(anchor), true));
}
/**
@@ -2560,6 +2560,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
new AssertJInliner(), new OptionalChainInliner(), new LambdaInliner(), new CollectionUpdateInliner(),
new StreamChainInliner(), new MapUpdateInliner(), new AssumeInliner(), new ClassMethodsInliner(),
new AssertAllInliner(), new BoxingInliner(), new SimpleMethodInliner(),
new TransformInliner(), new EnumCompareInliner(), new IndexOfInliner()
new TransformInliner(), new EnumCompareInliner(), new IndexOfInliner(), new AssertInstanceOfInliner()
};
}
@@ -0,0 +1,41 @@
// 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.jvm.problems.ContractFailureProblem;
import com.intellij.codeInspection.dataFlow.types.DfTypes;
import com.intellij.codeInspection.dataFlow.value.RelationType;
import com.intellij.psi.*;
import com.siyeh.ig.callMatcher.CallMatcher;
import com.siyeh.ig.psiutils.MethodCallUtils;
import org.jetbrains.annotations.NotNull;
public final class AssertInstanceOfInliner implements CallInliner {
private static final CallMatcher ASSERT_INSTANCE_OF = CallMatcher.staticCall("org.junit.jupiter.api.Assertions", "assertInstanceOf");
@Override
public boolean tryInlineCall(@NotNull CFGBuilder builder, @NotNull PsiMethodCallExpression call) {
if (!ASSERT_INSTANCE_OF.matches(call)) return false;
PsiExpression[] expressions = call.getArgumentList().getExpressions();
if (expressions.length < 2 || expressions.length > 3) return false;
PsiExpression wantedClass = expressions[0];
PsiExpression objectToTest = expressions[1];
builder.pushExpression(wantedClass)
.pushExpression(objectToTest)
.boxUnbox(objectToTest, PsiType.getJavaLangObject(call.getManager(), call.getResolveScope()))
.splice(2, 0, 0, 1);
if (expressions.length == 3) {
builder.pushExpression(expressions[2]).pop();
}
builder.isInstance(null)
.ensure(RelationType.EQ, DfTypes.TRUE, new ContractFailureProblem(call), CommonClassNames.JAVA_LANG_ASSERTION_ERROR)
.pop();
return true;
}
@Override
public boolean mayInferPreciseType(@NotNull PsiExpression expression) {
PsiParameter argument = MethodCallUtils.getParameterForArgument(expression);
return argument != null && ASSERT_INSTANCE_OF.methodMatches((PsiMethod)argument.getDeclarationScope());
}
}
@@ -0,0 +1,18 @@
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
public class AssertInstanceOf {
void test(Object str) {
assertInstanceOf(String.class, str);
if(<warning descr="Condition 'str instanceof String' is always 'true'">str instanceof String</warning>) {
}
<warning descr="The call to 'assertInstanceOf' always fails with an exception">assertInstanceOf</warning>(Number.class, str);
}
void test2(Object obj) {
int x;
assertInstanceOf(String.class, obj, "hello " + (x = (obj instanceof Number ? 1 : 2)));
if (<warning descr="Condition 'x == 2' is always 'true'">x == 2</warning>) {
}
}
}
@@ -209,4 +209,17 @@ public class HardcodedContractsTest extends DataFlowInspectionTestCase {
}""");
checkHighlighting();
}
public void testAssertInstanceOf() {
myFixture.addClass("""
package org.junit.jupiter.api;
import java.util.function.Supplier;
public final class Assertions {
public static native <T> T assertInstanceOf(Class<T> expectedType, Object actualValue);
public static <T> T assertInstanceOf(Class<T> expectedType, Object actualValue, String message);
public static <T> T assertInstanceOf(Class<T> expectedType, Object actualValue, Supplier<String> messageSupplier);
}
""");
checkHighlighting();
}
}