mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-inspections] IDEA-172900 "MethodHandle/VarHandle invocation arguments mismatch" false positive with varargs
GitOrigin-RevId: 49fa16434ab4e268ca8b667f118a4b97d71e20a4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
038044e84c
commit
5aba52d3ad
+42
-26
@@ -176,12 +176,22 @@ final class JavaLangReflectHandleInvocationChecker {
|
||||
if (actualArguments == null) return true;
|
||||
|
||||
final int requiredArgumentCount = lazyMethodSignature.size() - 1; // -1 excludes the return type
|
||||
if (!checkArgumentCount(actualArguments.expressions, requiredArgumentCount, argumentOffset, argumentList, holder)) return false;
|
||||
final boolean maybeVararg;
|
||||
if (!isExact && requiredArgumentCount > 0) {
|
||||
ReflectiveType type = lazyMethodSignature.get(requiredArgumentCount).get();
|
||||
maybeVararg = type.getType() instanceof PsiArrayType;
|
||||
} else {
|
||||
maybeVararg = false;
|
||||
}
|
||||
PsiExpression[] expressions = actualArguments.expressions;
|
||||
if (!maybeVararg || expressions.length < requiredArgumentCount - 1) {
|
||||
if (!checkArgumentCount(expressions, requiredArgumentCount, argumentOffset, argumentList, holder)) return false;
|
||||
}
|
||||
|
||||
LOG.assertTrue(actualArguments.expressions.length == requiredArgumentCount);
|
||||
for (int i = 0; i < requiredArgumentCount; i++) {
|
||||
final ReflectiveType requiredType = lazyMethodSignature.get(i + 1).get();
|
||||
checkArgumentType(actualArguments.expressions[i], requiredType, argumentList, isExact, holder);
|
||||
for (int i = 0; i < expressions.length; i++) {
|
||||
int parameterIndex = maybeVararg && i >= requiredArgumentCount - 1 ? requiredArgumentCount : i + 1;
|
||||
final ReflectiveType requiredType = lazyMethodSignature.get(parameterIndex).get();
|
||||
checkArgumentType(expressions[i], requiredType, argumentList, isExact, maybeVararg && i >= requiredArgumentCount - 1, holder);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -191,28 +201,34 @@ final class JavaLangReflectHandleInvocationChecker {
|
||||
@Nullable ReflectiveType requiredType,
|
||||
@NotNull PsiExpressionList argumentList,
|
||||
boolean isExact,
|
||||
boolean maybeVararg,
|
||||
@NotNull ProblemsHolder holder) {
|
||||
if (requiredType != null) {
|
||||
final PsiType actualType = argument.getType();
|
||||
if (actualType != null) {
|
||||
if (!isCompatible(requiredType, actualType, isExact)) {
|
||||
if (PsiTreeUtil.isAncestor(argumentList, argument, false)) {
|
||||
holder.registerProblem(argument,
|
||||
JavaBundle.message(isExact
|
||||
? "inspection.reflect.handle.invocation.argument.not.exact"
|
||||
: "inspection.reflection.invocation.argument.not.assignable",
|
||||
requiredType.getQualifiedName()));
|
||||
}
|
||||
if (requiredType == null) return;
|
||||
final PsiType actualType = argument.getType();
|
||||
if (actualType == null) return;
|
||||
if (!isCompatible(requiredType, actualType, isExact)) {
|
||||
if (maybeVararg) {
|
||||
ReflectiveType componentType = requiredType.getArrayComponentType();
|
||||
if (componentType != null) {
|
||||
requiredType = componentType;
|
||||
if (isCompatible(requiredType, actualType, isExact)) return;
|
||||
}
|
||||
else if (requiredType.isPrimitive()) {
|
||||
final PsiExpression definition = findDefinition(argument);
|
||||
if (definition != null && PsiType.NULL.equals(definition.getType())) {
|
||||
if (PsiTreeUtil.isAncestor(argumentList, argument, false)) {
|
||||
holder.registerProblem(argument,
|
||||
JavaBundle.message("inspection.reflect.handle.invocation.primitive.argument.null",
|
||||
requiredType.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PsiTreeUtil.isAncestor(argumentList, argument, false)) {
|
||||
holder.registerProblem(argument,
|
||||
JavaBundle.message(isExact
|
||||
? "inspection.reflect.handle.invocation.argument.not.exact"
|
||||
: "inspection.reflection.invocation.argument.not.assignable",
|
||||
requiredType.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
else if (requiredType.isPrimitive()) {
|
||||
final PsiExpression definition = findDefinition(argument);
|
||||
if (definition != null && PsiType.NULL.equals(definition.getType())) {
|
||||
if (PsiTreeUtil.isAncestor(argumentList, argument, false)) {
|
||||
holder.registerProblem(argument,
|
||||
JavaBundle.message("inspection.reflect.handle.invocation.primitive.argument.null",
|
||||
requiredType.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,7 +389,7 @@ final class JavaLangReflectHandleInvocationChecker {
|
||||
|
||||
LOG.assertTrue(arguments.length == argumentOffset + 1);
|
||||
final ReflectiveType requiredType = getReflectiveType(typeExpression);
|
||||
checkArgumentType(arguments[argumentOffset], requiredType, argumentList, isExact, holder);
|
||||
checkArgumentType(arguments[argumentOffset], requiredType, argumentList, isExact, false, holder);
|
||||
|
||||
final PsiElement invokeParent = invokeCall.getParent();
|
||||
if (!(invokeParent instanceof PsiStatement)) {
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ final class JavaLangReflectVarHandleInvocationChecker {
|
||||
|
||||
LOG.assertTrue(accessArguments.length == requiredArgumentCount);
|
||||
for (int i = coordinateArguments; i < requiredArgumentCount; i++) {
|
||||
checkArgumentType(accessArguments[i], valueType, accessArgumentList, false, holder);
|
||||
checkArgumentType(accessArguments[i], valueType, accessArgumentList, false, false, holder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static java.lang.invoke.MethodHandles.publicLookup;
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
|
||||
public class VarArgMethodHandle {
|
||||
public static void main(String... args) throws Throwable {
|
||||
MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
|
||||
"asList", methodType(List.class, Object[].class));
|
||||
System.out.println(MH_asList.invoke("one", "two").toString());
|
||||
System.out.println(MH_asList.invokeExact<warning descr="One argument is expected">("one", "two")</warning>.toString());
|
||||
System.out.println(MH_asList.invokeExact(new Object[] {"one", "two"}).toString());
|
||||
System.out.println(MH_asList.invoke(new Object[] {"one", "two"}).toString());
|
||||
MethodHandle MH_main = publicLookup().findStatic(VarArgMethodHandle.class,
|
||||
"main", methodType(void.class, String[].class));
|
||||
System.out.println(MH_main.invoke("one", "two").toString());
|
||||
System.out.println(MH_main.invoke(new String[] {"one", "two"}).toString());
|
||||
System.out.println(MH_main.invoke(new Object[] {"one", "two"}).toString());
|
||||
System.out.println(MH_main.invoke(<warning descr="Argument is not assignable to 'java.lang.String'">1</warning>, <warning descr="Argument is not assignable to 'java.lang.String'">2</warning>).toString());
|
||||
System.out.println(MH_main.invokeExact<warning descr="One argument is expected">("one", "two")</warning>.toString());
|
||||
System.out.println(MH_main.invokeExact<warning descr="One argument is expected">(1, 2)</warning>.toString());
|
||||
System.out.println(MH_main.invokeExact(new String[] {"one", "two"}).toString());
|
||||
System.out.println(MH_main.invokeExact(<warning descr="Argument type should be exactly 'java.lang.String[]'">new Object[] {"one", "two"}</warning>).toString());
|
||||
}
|
||||
}
|
||||
+2
@@ -52,6 +52,8 @@ class JavaLangInvokeHandleSignatureTest : LightJavaCodeInsightFixtureTestCase()
|
||||
|
||||
fun testSpecial() = doTest()
|
||||
|
||||
fun testVarArgMethodHandle() = doTest()
|
||||
|
||||
private fun doTest() {
|
||||
myFixture.testHighlighting("${getTestName(false)}.java")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user