mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-inspections] IDEA-281190 MethodHandle inspections do not consider MethodType overloads
PR#1798 Committed-by: tagir.valeev@jetbrains.com GitOrigin-RevId: e0c59271f5345b45291f177de610bd5f1fb9f6c6
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2bd4aebd1f
commit
3b277a36bf
+163
-18
@@ -21,6 +21,8 @@ import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.callMatcher.CallMapper;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
import com.siyeh.ig.psiutils.DeclarationSearchUtils;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import com.siyeh.ig.psiutils.MethodCallUtils;
|
||||
@@ -29,9 +31,14 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.intellij.psi.CommonClassNames.*;
|
||||
import static com.siyeh.ig.callMatcher.CallMatcher.anyOf;
|
||||
import static com.siyeh.ig.callMatcher.CallMatcher.staticCall;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
@@ -43,6 +50,34 @@ public final class JavaReflectionReferenceUtil {
|
||||
|
||||
public static final String METHOD_TYPE = "methodType";
|
||||
public static final String GENERIC_METHOD_TYPE = "genericMethodType";
|
||||
private static final CallMatcher LIST_FACTORY = anyOf(
|
||||
staticCall(JAVA_UTIL_LIST, "of"),
|
||||
staticCall(JAVA_UTIL_ARRAYS, "asList")
|
||||
);
|
||||
private static final CallMatcher.Simple METHOD_TYPE_MATCHER = staticCall(JAVA_LANG_INVOKE_METHOD_TYPE, METHOD_TYPE);
|
||||
public static final CallMatcher METHOD_TYPE_WITH_METHOD_TYPE_MATCHER =
|
||||
METHOD_TYPE_MATCHER.parameterTypes(JAVA_LANG_CLASS, JAVA_LANG_INVOKE_METHOD_TYPE);
|
||||
public static final CallMatcher METHOD_TYPE_WITH_LIST_MATCHER =
|
||||
METHOD_TYPE_MATCHER.parameterTypes(JAVA_LANG_CLASS, JAVA_UTIL_LIST);
|
||||
public static final CallMatcher METHOD_TYPE_WITH_CLASSES_MATCHER = anyOf(
|
||||
METHOD_TYPE_MATCHER.parameterCount(3),
|
||||
METHOD_TYPE_MATCHER.parameterCount(1),
|
||||
METHOD_TYPE_MATCHER.parameterTypes(JAVA_LANG_CLASS, JAVA_LANG_CLASS)
|
||||
);
|
||||
public static final CallMatcher METHOD_TYPE_WITH_ARRAY_MATCHER =
|
||||
METHOD_TYPE_MATCHER.parameterTypes(JAVA_LANG_CLASS, JAVA_LANG_CLASS + "<?>[]");
|
||||
public static final CallMatcher GENERIC_METHOD_TYPE_MATCHER = staticCall(JAVA_LANG_INVOKE_METHOD_TYPE, GENERIC_METHOD_TYPE);
|
||||
private static final CallMapper<ReflectiveSignature> SIGNATURE_MAPPER = new CallMapper<ReflectiveSignature>()
|
||||
.register(METHOD_TYPE_WITH_CLASSES_MATCHER,
|
||||
call -> composeMethodSignatureFromTypes(call.getArgumentList().getExpressions()))
|
||||
.register(METHOD_TYPE_WITH_LIST_MATCHER,
|
||||
call -> composeMethodSignatureFromReturnTypeAndList(call.getArgumentList().getExpressions()))
|
||||
.register(METHOD_TYPE_WITH_ARRAY_MATCHER,
|
||||
call -> composeMethodSignatureFromReturnTypeAndArray(call.getArgumentList().getExpressions()))
|
||||
.register(METHOD_TYPE_WITH_METHOD_TYPE_MATCHER,
|
||||
call -> composeMethodSignatureFromReturnTypeAndMethodType(call.getArgumentList().getExpressions()))
|
||||
.register(GENERIC_METHOD_TYPE_MATCHER,
|
||||
call -> composeGenericMethodSignature(call.getArgumentList().getExpressions()));
|
||||
|
||||
public static final String FIND_VIRTUAL = "findVirtual";
|
||||
public static final String FIND_STATIC = "findStatic";
|
||||
@@ -468,6 +503,31 @@ public final class JavaReflectionReferenceUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static List<PsiExpression> getListComponents(@Nullable PsiExpression maybeList) {
|
||||
maybeList = PsiUtil.skipParenthesizedExprDown(maybeList);
|
||||
if (LIST_FACTORY.matches(maybeList) && maybeList instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression callExpression = (PsiMethodCallExpression)maybeList;
|
||||
final PsiExpression[] expressions = callExpression.getArgumentList().getExpressions();
|
||||
if (expressions.length == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final PsiExpression firstArgument = PsiUtil.skipParenthesizedExprDown(expressions[0]);
|
||||
if (MethodCallUtils.isVarArgCall(callExpression)) {
|
||||
final List<PsiExpression> varargs = getVarargs(firstArgument);
|
||||
if (varargs != null) {
|
||||
return varargs;
|
||||
}
|
||||
}
|
||||
// Skip calls with explicit arrays, for example: List.of(new Class<?>[0])
|
||||
if (isVarargAsArray(firstArgument)) {
|
||||
return null;
|
||||
}
|
||||
return Arrays.asList(expressions);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Contract("null -> false")
|
||||
public static boolean isVarargAsArray(@Nullable PsiExpression maybeArray) {
|
||||
final PsiType type = maybeArray != null ? maybeArray.getType() : null;
|
||||
@@ -482,26 +542,33 @@ public final class JavaReflectionReferenceUtil {
|
||||
*/
|
||||
@Nullable
|
||||
public static ReflectiveSignature composeMethodSignature(@Nullable PsiExpression methodTypeExpression) {
|
||||
final PsiExpression typeDefinition = findDefinition(methodTypeExpression);
|
||||
return composeMethodSignature(methodTypeExpression, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ReflectiveSignature composeMethodSignature(@Nullable PsiExpression methodTypeExpression, boolean allowRecursion) {
|
||||
final PsiExpression typeDefinition = findDefinition(PsiUtil.skipParenthesizedExprDown(methodTypeExpression));
|
||||
if (METHOD_TYPE_WITH_METHOD_TYPE_MATCHER.matches(typeDefinition) && !allowRecursion) {
|
||||
return null;
|
||||
}
|
||||
if (typeDefinition instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)typeDefinition;
|
||||
final String referenceName = methodCallExpression.getMethodExpression().getReferenceName();
|
||||
return SIGNATURE_MAPPER.mapFirst((PsiMethodCallExpression)typeDefinition);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Function<PsiExpression[], ReflectiveSignature> composer = null;
|
||||
if (METHOD_TYPE.equals(referenceName)) {
|
||||
composer = JavaReflectionReferenceUtil::composeMethodSignatureFromTypes;
|
||||
}
|
||||
else if (GENERIC_METHOD_TYPE.equals(referenceName)) {
|
||||
composer = JavaReflectionReferenceUtil::composeGenericMethodSignature;
|
||||
}
|
||||
|
||||
if (composer != null) {
|
||||
final PsiMethod method = methodCallExpression.resolveMethod();
|
||||
if (method != null) {
|
||||
final PsiClass psiClass = method.getContainingClass();
|
||||
if (psiClass != null && JAVA_LANG_INVOKE_METHOD_TYPE.equals(psiClass.getQualifiedName())) {
|
||||
final PsiExpression[] arguments = methodCallExpression.getArgumentList().getExpressions();
|
||||
return composer.apply(arguments);
|
||||
@Nullable
|
||||
private static ReflectiveSignature composeMethodSignatureFromReturnTypeAndMethodType(
|
||||
PsiExpression @NotNull [] arguments
|
||||
) {
|
||||
if (arguments.length == 2) {
|
||||
final PsiExpression methodType = findInnermostMethodType(arguments[1]);
|
||||
if (methodType != null) {
|
||||
final ReflectiveSignature signature = composeMethodSignature(methodType, false);
|
||||
if (signature != null) {
|
||||
final String text = getTypeText(arguments[0]);
|
||||
if (text != null) {
|
||||
return signature.withReturnType(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -509,6 +576,80 @@ public final class JavaReflectionReferenceUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find innermost {@link MethodType} for a {@link MethodType#methodType(Class, MethodType)} call
|
||||
*
|
||||
* <p>
|
||||
* Examples:
|
||||
* <ol>
|
||||
* <li>
|
||||
* For {@code MethodType.methodType(void.class, MethodType.methodType(String.class)}
|
||||
* will return {@link PsiExpression} for {@code MethodType.methodType(String.class)}
|
||||
* </li>
|
||||
* <li>
|
||||
* For {@code MethodType.methodType(void.class, MethodType.methodType(String.class, MethodType.methodType(List.class))}
|
||||
* will return {@link PsiExpression} for {@code MethodType.methodType(List.class)}
|
||||
* </li>
|
||||
* </ol>
|
||||
*
|
||||
* @param methodType the origin {@link MethodType}
|
||||
* @return innermost {@link MethodType} as {@link PsiExpression} or {@code null}, if unable to resolve or there are too many nested calls
|
||||
*/
|
||||
@Nullable
|
||||
public static PsiExpression findInnermostMethodType(@Nullable PsiExpression methodType) {
|
||||
methodType = findDefinition(methodType);
|
||||
int preventEndlessLoop = 5;
|
||||
while (METHOD_TYPE_WITH_METHOD_TYPE_MATCHER.matches(methodType)) {
|
||||
if (--preventEndlessLoop == 0) {
|
||||
return null;
|
||||
}
|
||||
methodType = PsiUtil.skipParenthesizedExprDown(methodType);
|
||||
if (!(methodType instanceof PsiMethodCallExpression)) {
|
||||
return null;
|
||||
}
|
||||
final PsiMethodCallExpression call = (PsiMethodCallExpression)methodType;
|
||||
final PsiExpression[] expressions = call.getArgumentList().getExpressions();
|
||||
if (expressions.length != 2) {
|
||||
return null;
|
||||
}
|
||||
methodType = findDefinition(expressions[1]);
|
||||
}
|
||||
|
||||
return METHOD_TYPE_MATCHER.matches(methodType) ? methodType : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ReflectiveSignature composeMethodSignatureFromReturnTypeAndList(PsiExpression @NotNull [] arguments) {
|
||||
if (arguments.length == 2) {
|
||||
final PsiExpression returnType = findDefinition(arguments[0]);
|
||||
if (returnType != null) {
|
||||
final PsiExpression list = arguments[1];
|
||||
final List<PsiExpression> components = getListComponents(list);
|
||||
if (components != null) {
|
||||
final List<PsiExpression> signature = ContainerUtil.prepend(components, returnType);
|
||||
return ReflectiveSignature.create(ContainerUtil.map(signature, typeExpression -> getTypeText(typeExpression)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ReflectiveSignature composeMethodSignatureFromReturnTypeAndArray(PsiExpression @NotNull [] arguments) {
|
||||
if (arguments.length == 2) {
|
||||
final PsiExpression returnType = findDefinition(arguments[0]);
|
||||
if (returnType != null) {
|
||||
final PsiExpression array = arguments[1];
|
||||
final List<PsiExpression> components = getVarargs(array);
|
||||
if (components != null) {
|
||||
final List<PsiExpression> signature = ContainerUtil.prepend(components, returnType);
|
||||
return ReflectiveSignature.create(ContainerUtil.map(signature, typeExpression -> getTypeText(typeExpression)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ReflectiveSignature composeMethodSignatureFromTypes(PsiExpression @NotNull [] returnAndParameterTypes) {
|
||||
final List<String> typeTexts = ContainerUtil.map(returnAndParameterTypes, JavaReflectionReferenceUtil::getTypeText);
|
||||
@@ -734,6 +875,10 @@ public final class JavaReflectionReferenceUtil {
|
||||
return myIcon != null ? myIcon : PlatformIcons.METHOD_ICON;
|
||||
}
|
||||
|
||||
public ReflectiveSignature withReturnType(@NotNull String returnType) {
|
||||
return new ReflectiveSignature(this.myIcon, returnType, this.myArgumentTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull ReflectiveSignature other) {
|
||||
int c = myArgumentTypes.length - other.myArgumentTypes.length;
|
||||
|
||||
+94
-27
@@ -9,6 +9,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.callMatcher.CallMapper;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -33,6 +34,13 @@ final class JavaLangReflectHandleInvocationChecker {
|
||||
private static final String INVOKE_WITH_ARGUMENTS = "invokeWithArguments";
|
||||
private static final String JAVA_LANG_INVOKE_METHOD_HANDLE = "java.lang.invoke.MethodHandle";
|
||||
|
||||
private static final CallMapper<List<Supplier<ReflectiveType>>> LAZY_SIGNATURE_MAPPER = new CallMapper<List<Supplier<ReflectiveType>>>()
|
||||
.register(METHOD_TYPE_WITH_CLASSES_MATCHER, call -> getLazyMethodSignatureForTypes(call))
|
||||
.register(METHOD_TYPE_WITH_LIST_MATCHER, call -> getLazyMethodSignatureForReturnTypeAndList(call))
|
||||
.register(METHOD_TYPE_WITH_ARRAY_MATCHER, call -> getLazyMethodSignatureForReturnTypeAndArray(call))
|
||||
.register(METHOD_TYPE_WITH_METHOD_TYPE_MATCHER, call -> getLazyMethodSignatureForReturnTypeAndMethodType(call))
|
||||
.register(GENERIC_METHOD_TYPE_MATCHER, call -> getLazyMethodSignatureForGenericMethodType(call));
|
||||
|
||||
private static final Set<String> METHOD_HANDLE_INVOKE_NAMES = ContainerUtil.set(INVOKE, INVOKE_EXACT, INVOKE_WITH_ARGUMENTS);
|
||||
|
||||
static boolean checkMethodHandleInvocation(@NotNull PsiMethodCallExpression methodCall, @NotNull ProblemsHolder holder) {
|
||||
@@ -247,41 +255,100 @@ final class JavaLangReflectHandleInvocationChecker {
|
||||
private static List<Supplier<ReflectiveType>> getLazyMethodSignature(@Nullable PsiExpression methodTypeExpression) {
|
||||
final PsiExpression typeDefinition = findDefinition(methodTypeExpression);
|
||||
if (typeDefinition instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression typeDefinitionCall = (PsiMethodCallExpression)typeDefinition;
|
||||
return LAZY_SIGNATURE_MAPPER.mapFirst(((PsiMethodCallExpression)typeDefinition));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isCallToMethod(typeDefinitionCall, JAVA_LANG_INVOKE_METHOD_TYPE, METHOD_TYPE)) {
|
||||
final PsiExpression[] arguments = typeDefinitionCall.getArgumentList().getExpressions();
|
||||
if (arguments.length != 0) {
|
||||
return ContainerUtil.map(arguments, argument -> (() -> getReflectiveType(argument)));
|
||||
@Nullable
|
||||
private static List<Supplier<ReflectiveType>> getLazyMethodSignatureForGenericMethodType(
|
||||
@NotNull PsiMethodCallExpression methodTypeExpression
|
||||
) {
|
||||
final PsiExpression[] arguments = methodTypeExpression.getArgumentList().getExpressions();
|
||||
final Pair.NonNull<Integer, Boolean> signature = getGenericSignature(arguments);
|
||||
if (signature != null) {
|
||||
final int objectArgCount = signature.getFirst();
|
||||
final boolean finalArray = signature.getSecond();
|
||||
if (objectArgCount == 0 && !finalArray) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final PsiClassType javaLangObject =
|
||||
PsiType.getJavaLangObject(methodTypeExpression.getManager(), methodTypeExpression.getResolveScope());
|
||||
final ReflectiveType objectType = ReflectiveType.create(javaLangObject, false);
|
||||
final List<ReflectiveType> argumentTypes = new ArrayList<>();
|
||||
argumentTypes.add(objectType); // return type
|
||||
for (int i = 0; i < objectArgCount; i++) {
|
||||
argumentTypes.add(objectType);
|
||||
}
|
||||
if (finalArray) {
|
||||
argumentTypes.add(ReflectiveType.arrayOf(objectType));
|
||||
}
|
||||
return ContainerUtil.map(argumentTypes, type -> (() -> type));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<Supplier<ReflectiveType>> getLazyMethodSignatureForReturnTypeAndMethodType(
|
||||
@NotNull PsiMethodCallExpression callExpression
|
||||
) {
|
||||
final PsiExpression[] arguments = callExpression.getArgumentList().getExpressions();
|
||||
if (arguments.length == 2) {
|
||||
final PsiExpression methodType = findInnermostMethodType(arguments[1]);
|
||||
if (methodType != null) {
|
||||
final List<Supplier<ReflectiveType>> nestedSignature = getLazyMethodSignature(methodType);
|
||||
if (nestedSignature != null) {
|
||||
final List<Supplier<ReflectiveType>> signature = new ArrayList<>(nestedSignature);
|
||||
if (!signature.isEmpty()) {
|
||||
final PsiExpression returnType = arguments[0];
|
||||
signature.set(0, () -> getReflectiveType(returnType));
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
}
|
||||
else if (isCallToMethod(typeDefinitionCall, JAVA_LANG_INVOKE_METHOD_TYPE, GENERIC_METHOD_TYPE)) {
|
||||
final PsiExpression[] arguments = typeDefinitionCall.getArgumentList().getExpressions();
|
||||
final Pair.NonNull<Integer, Boolean> signature = getGenericSignature(arguments);
|
||||
if (signature != null) {
|
||||
final int objectArgCount = signature.getFirst();
|
||||
final boolean finalArray = signature.getSecond();
|
||||
if (objectArgCount == 0 && !finalArray) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final PsiClassType javaLangObject =
|
||||
PsiType.getJavaLangObject(methodTypeExpression.getManager(), methodTypeExpression.getResolveScope());
|
||||
final ReflectiveType objectType = ReflectiveType.create(javaLangObject, false);
|
||||
final List<ReflectiveType> argumentTypes = new ArrayList<>();
|
||||
argumentTypes.add(objectType); // return type
|
||||
for (int i = 0; i < objectArgCount; i++) {
|
||||
argumentTypes.add(objectType);
|
||||
}
|
||||
if (finalArray) {
|
||||
argumentTypes.add(ReflectiveType.arrayOf(objectType));
|
||||
}
|
||||
return ContainerUtil.map(argumentTypes, type -> (() -> type));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<Supplier<ReflectiveType>> getLazyMethodSignatureForReturnTypeAndArray(@NotNull PsiMethodCallExpression call) {
|
||||
final PsiExpression[] arguments = call.getArgumentList().getExpressions();
|
||||
if (arguments.length == 2) {
|
||||
final PsiExpression returnType = findDefinition(arguments[0]);
|
||||
final PsiExpression secondArgument = arguments[1];
|
||||
final List<PsiExpression> components = getVarargs(secondArgument);
|
||||
if (components != null) {
|
||||
final List<PsiExpression> signature = ContainerUtil.prepend(components, returnType);
|
||||
return ContainerUtil.map(signature, parameter -> (() -> getReflectiveType(parameter)));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<Supplier<ReflectiveType>> getLazyMethodSignatureForReturnTypeAndList(@NotNull PsiMethodCallExpression call) {
|
||||
final PsiExpression[] arguments = call.getArgumentList().getExpressions();
|
||||
if (arguments.length == 2) {
|
||||
final PsiExpression list = arguments[1];
|
||||
final List<PsiExpression> components = getListComponents(list);
|
||||
if (components != null) {
|
||||
final PsiExpression returnType = findDefinition(arguments[0]);
|
||||
final List<PsiExpression> signature = ContainerUtil.prepend(components, returnType);
|
||||
return ContainerUtil.map(signature, argument -> (() -> getReflectiveType(argument)));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<Supplier<ReflectiveType>> getLazyMethodSignatureForTypes(@NotNull PsiMethodCallExpression call) {
|
||||
final PsiExpression[] expressions = call.getArgumentList().getExpressions();
|
||||
if (expressions.length != 0) {
|
||||
return ContainerUtil.map(expressions, argument -> (() -> getReflectiveType(argument)));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean checkGetter(@NotNull PsiMethodCallExpression invokeCall,
|
||||
@NotNull PsiExpression typeExpression,
|
||||
boolean isExact,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import java.lang.invoke.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
class Main {
|
||||
void foo() throws Exception {
|
||||
@@ -25,6 +27,14 @@ class Main {
|
||||
l.findConstructor(Class.forName("NoDefault"), <warning descr="Cannot resolve constructor 'NoDefault()'">MethodType.methodType(void.class)</warning>);
|
||||
|
||||
}
|
||||
|
||||
void differentMethodTypeOverloads() throws Exception {
|
||||
MethodHandles.Lookup l = MethodHandles.lookup();
|
||||
|
||||
l.findConstructor(Test.class, <warning descr="Cannot resolve constructor 'int Test()'">MethodType.methodType(int.class)</warning>);
|
||||
l.findConstructor(Test.class, <warning descr="Cannot resolve constructor 'int Test()'">MethodType.methodType(int.class, List.of())</warning>);
|
||||
l.findConstructor(Test.class, <warning descr="Cannot resolve constructor 'int Test()'">MethodType.methodType(int.class, Arrays.asList())</warning>);
|
||||
}
|
||||
}
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import java.lang.invoke.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
class Main {
|
||||
void foo() throws Exception {
|
||||
@@ -26,6 +28,17 @@ class Main {
|
||||
l.<warning descr="Method 'method' is not static">findStatic</warning>(Test.class, "method", MethodType.methodType(void.class));
|
||||
l.findVirtual(Test.class, <warning descr="Cannot resolve method 'doesntExist'">"doesntExist"</warning>, MethodType.methodType(void.class));
|
||||
}
|
||||
|
||||
void differentMethodTypeOverloads() throws Exception {
|
||||
MethodHandles.Lookup l = MethodHandles.lookup();
|
||||
|
||||
l.findVirtual(Test.class, "method", <warning descr="Cannot resolve method 'void method(void)'">MethodType.methodType(void.class, List.of(void.class))</warning>);
|
||||
l.findVirtual(Test.class, "method", <warning descr="Cannot resolve method 'void method(void)'">MethodType.methodType(void.class, new Class<?>[]{void.class})</warning>);
|
||||
l.findVirtual(Test.class, "method", <warning descr="Cannot resolve method 'void method(void)'">MethodType.methodType(void.class, Arrays.asList(void.class))</warning>);
|
||||
l.findVirtual(Test.class, "method", <warning descr="Cannot resolve method 'void method(void)'">MethodType.methodType(void.class, MethodType.methodType(String.class, void.class))</warning>);
|
||||
MethodType methodType = MethodType.methodType(String.class, MethodType.methodType(void.class, void.class));
|
||||
l.findVirtual(Test.class, "method", <warning descr="Cannot resolve method 'void method(void)'">MethodType.methodType(void.class, methodType)</warning>);
|
||||
}
|
||||
}
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import java.lang.invoke.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
class Main {
|
||||
void foo() throws Exception {
|
||||
@@ -47,6 +49,16 @@ class Main {
|
||||
l.findSpecial(A.class, <warning descr="Cannot resolve method 'baz'">"baz"</warning>, MethodType.methodType(String.class, double.class), A.class);
|
||||
l.findSpecial(B.class, "baz", <warning descr="Cannot resolve method 'String baz(double)'">MethodType.methodType(String.class, double.class)</warning>, <warning descr="Caller class 'A' must be a subclass of 'B'">A.class</warning>);
|
||||
}
|
||||
|
||||
void differentMethodTypeOverloads() throws Exception {
|
||||
MethodHandles.Lookup l = MethodHandles.lookup();
|
||||
|
||||
l.findSpecial(B.class, "baz", <warning descr="Cannot resolve method 'String baz(double)'">MethodType.methodType(String.class, double.class)</warning>, C.class);
|
||||
l.findSpecial(B.class, "baz", <warning descr="Cannot resolve method 'String baz(double)'">MethodType.methodType(String.class, List.of(double.class))</warning>, C.class);
|
||||
l.findSpecial(B.class, "baz", <warning descr="Cannot resolve method 'String baz(double)'">MethodType.methodType(String.class, Arrays.asList(double.class))</warning>, C.class);
|
||||
l.findSpecial(B.class, "baz", <warning descr="Cannot resolve method 'String baz(double)'">MethodType.methodType(String.class, new Class<?>[]{double.class})</warning>, C.class);
|
||||
l.findSpecial(B.class, "baz", <warning descr="Cannot resolve method 'String baz(double)'">MethodType.methodType(String.class, MethodType.methodType(void.class, new Class<?>[]{double.class}))</warning>, C.class);
|
||||
}
|
||||
}
|
||||
|
||||
interface A {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import java.lang.invoke.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
class Main {
|
||||
void foo() throws Exception {
|
||||
@@ -16,6 +18,16 @@ class Main {
|
||||
l.<warning descr="Method 'method1' is static">findVirtual</warning>(Test.class, "method1", MethodType.methodType(void.class));
|
||||
l.findStatic(Test.class, <warning descr="Cannot resolve method 'doesntExist'">"doesntExist"</warning>, MethodType.methodType(String.class));
|
||||
}
|
||||
|
||||
void differentMethodTypeOverloads() throws Exception {
|
||||
MethodHandles.Lookup l = MethodHandles.lookup();
|
||||
|
||||
l.findStatic(Test.class, "method2", <warning descr="Cannot resolve method 'int method2(String)'">MethodType.methodType(int.class, String.class)</warning>);
|
||||
l.findStatic(Test.class, "method2", <warning descr="Cannot resolve method 'int method2(String)'">MethodType.methodType(int.class, List.of(String.class))</warning>);
|
||||
l.findStatic(Test.class, "method2", <warning descr="Cannot resolve method 'int method2(String)'">MethodType.methodType(int.class, Arrays.asList(String.class))</warning>);
|
||||
l.findStatic(Test.class, "method2", <warning descr="Cannot resolve method 'int method2(String)'">MethodType.methodType(int.class, new Class<?>[]{String.class})</warning>);
|
||||
l.findStatic(Test.class, "method2", <warning descr="Cannot resolve method 'int method2(String)'">MethodType.methodType(int.class, MethodType.methodType(void.class, List.of(String.class)))</warning>);
|
||||
}
|
||||
}
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
class Main {
|
||||
void fooInt() throws Throwable {
|
||||
@@ -122,10 +127,48 @@ class Main {
|
||||
CharSequence superclassResult3 = (<warning descr="Should be cast to 'java.lang.String'">CharSequence</warning>) handle.invokeExact(instance, "c");
|
||||
}
|
||||
|
||||
void fooVariousTypesVariousMethodTypes() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
Test instance = new Test();
|
||||
|
||||
MethodType methodTypeFromArraysAsList = MethodType.methodType(long.class, Arrays.asList(int.class, long.class));
|
||||
MethodHandle methodHandle0 = lookup.findVirtual(Test.class, "foo", methodTypeFromArraysAsList);
|
||||
methodHandle0.invoke<warning descr="3 arguments are expected">(instance, 1, 2, 3)</warning>;
|
||||
|
||||
MethodType methodTypeFromListOf = MethodType.methodType(long.class, (List.of(int.class, long.class)));
|
||||
MethodHandle methodHandle1 = lookup.findVirtual(Test.class, "foo", methodTypeFromListOf);
|
||||
methodHandle1.invoke<warning descr="3 arguments are expected">(instance, 1, 2, 3)</warning>;
|
||||
|
||||
MethodHandle methodHandle2 = lookup.findVirtual(Test.class, "foo", MethodType.methodType(long.class, MethodType.methodType(Object.class, int.class, long.class)));
|
||||
methodHandle2.invoke<warning descr="3 arguments are expected">(instance, 1, 2, 3)</warning>;
|
||||
|
||||
MethodHandle methodHandle3 = lookup.findVirtual(Test.class, "foo", MethodType.methodType(long.class, new Class<?>[]{int.class, long.class}));
|
||||
methodHandle3.invoke<warning descr="3 arguments are expected">(instance, 1, 2, 3)</warning>;
|
||||
|
||||
MethodHandle methodHandle4 = lookup.findVirtual(Test.class, "foo", MethodType.methodType(long.class, new Class[]{int.class, long.class}));
|
||||
methodHandle4.invoke<warning descr="3 arguments are expected">(instance, 1, 2, 3)</warning>;
|
||||
|
||||
MethodType nestedMethodType5 = MethodType.methodType(long.class, new Class[]{int.class, long.class});
|
||||
MethodHandle methodHandle5 = lookup.findVirtual(Test.class, "foo", MethodType.methodType(long.class, nestedMethodType5));
|
||||
methodHandle5.invoke<warning descr="3 arguments are expected">(instance, 1, 2, 3)</warning>;
|
||||
|
||||
List<Class<?>> noWarningsForMutableLists = Arrays.asList(int.class, String.class);
|
||||
noWarningsForMutableLists.set(1, long.class);
|
||||
MethodHandle methodHandle6 = lookup.findVirtual(Test.class, "foo", MethodType.methodType(long.class, noWarningsForMutableLists));
|
||||
methodHandle6.invoke(instance, 1, 2L);
|
||||
|
||||
MethodType noStackOverflowError = MethodType.methodType(long.class, <error descr="Variable 'noStackOverflowError' might not have been initialized">noStackOverflowError</error>);
|
||||
MethodHandle methodHandle7 = lookup.findVirtual(Test.class, "foo", noStackOverflowError);
|
||||
methodHandle7.invoke(instance, 1, 2L);
|
||||
}
|
||||
|
||||
private static CharSequence charSequence() { return "abc"; }
|
||||
}
|
||||
|
||||
class Test {
|
||||
public int foo(int n) {return n;}
|
||||
public String foo(String s) {return s;}
|
||||
public long foo(int i, long l) {
|
||||
return l + i;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-12
@@ -25,9 +25,7 @@ import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
|
||||
class JavaLangReflectHandleInvocationTest : JavaLangReflectHandleInvocationTestBase(LanguageLevel.JDK_1_7,
|
||||
LightJavaCodeInsightFixtureTestCase.JAVA_8) {
|
||||
class JavaLangReflectHandleInvocationTest : LightJavaCodeInsightFixtureTestCase() {
|
||||
fun testVirtual() = doTest()
|
||||
fun testStatic() = doTest()
|
||||
fun testConstructor() = doTest()
|
||||
@@ -37,28 +35,22 @@ class JavaLangReflectHandleInvocationTest : JavaLangReflectHandleInvocationTestB
|
||||
|
||||
fun testStaticGetter() = doTest()
|
||||
fun testStaticSetter() = doTest()
|
||||
}
|
||||
|
||||
class Java9LangReflectHandleInvocationTest : JavaLangReflectHandleInvocationTestBase(LanguageLevel.JDK_1_9,
|
||||
LightJavaCodeInsightFixtureTestCase.JAVA_9) {
|
||||
fun testVarHandle() = doTest()
|
||||
fun testStaticVarHandle() = doTest()
|
||||
fun testArrayVarHandle() = doTest()
|
||||
}
|
||||
|
||||
abstract class JavaLangReflectHandleInvocationTestBase(val languageLevel: LanguageLevel,
|
||||
val descriptor: LightProjectDescriptor) : LightJavaCodeInsightFixtureTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
LanguageLevelProjectExtension.getInstance(project).languageLevel = languageLevel
|
||||
LanguageLevelProjectExtension.getInstance(project).languageLevel = LanguageLevel.JDK_1_9
|
||||
myFixture.enableInspections(JavaLangInvokeHandleSignatureInspection())
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = descriptor
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = JAVA_9
|
||||
|
||||
override fun getBasePath() = JavaTestUtil.getRelativeJavaTestDataPath() + "/inspection/javaLangReflectHandleInvocation"
|
||||
|
||||
protected fun doTest() {
|
||||
private fun doTest() {
|
||||
myFixture.testHighlighting("${getTestName(false)}.java")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user