diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/CFGBuilder.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/CFGBuilder.java
index 4f7392c68b13..ce29c75274ee 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/CFGBuilder.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/CFGBuilder.java
@@ -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));
}
/**
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/ControlFlowAnalyzer.java
index e6c755c6e679..89dcd7a5d4b0 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/ControlFlowAnalyzer.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/ControlFlowAnalyzer.java
@@ -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()
};
}
\ No newline at end of file
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inliner/AssertInstanceOfInliner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inliner/AssertInstanceOfInliner.java
new file mode 100644
index 000000000000..371651f44005
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inliner/AssertInstanceOfInliner.java
@@ -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());
+ }
+}
diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/AssertInstanceOf.java b/java/java-tests/testData/inspection/dataFlow/fixture/AssertInstanceOf.java
new file mode 100644
index 000000000000..452598fd347f
--- /dev/null
+++ b/java/java-tests/testData/inspection/dataFlow/fixture/AssertInstanceOf.java
@@ -0,0 +1,18 @@
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+
+public class AssertInstanceOf {
+ void test(Object str) {
+ assertInstanceOf(String.class, str);
+ if(str instanceof String) {
+ }
+ assertInstanceOf(Number.class, str);
+ }
+
+ void test2(Object obj) {
+ int x;
+ assertInstanceOf(String.class, obj, "hello " + (x = (obj instanceof Number ? 1 : 2)));
+ if (x == 2) {
+
+ }
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/HardcodedContractsTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/HardcodedContractsTest.java
index abad2c609fd6..2e80ee3380f1 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInspection/HardcodedContractsTest.java
+++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/HardcodedContractsTest.java
@@ -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 assertInstanceOf(Class expectedType, Object actualValue);
+ public static T assertInstanceOf(Class expectedType, Object actualValue, String message);
+ public static T assertInstanceOf(Class expectedType, Object actualValue, Supplier messageSupplier);
+ }
+ """);
+ checkHighlighting();
+ }
}