mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java: Merge all MethodHandle/VarHandle checks into a single inspection (IDEA-172358, IDEA-171813, IDEA-167318)
This commit is contained in:
+60
-16
@@ -38,6 +38,9 @@ import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.intellij.codeInspection.reflectiveAccess.JavaLangReflectVarHandleInvocationChecker.ARRAY_ELEMENT_VAR_HANDLE;
|
||||
import static com.intellij.codeInspection.reflectiveAccess.JavaLangReflectVarHandleInvocationChecker.JAVA_LANG_INVOKE_METHOD_HANDLES;
|
||||
import static com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT;
|
||||
import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceUtil.*;
|
||||
|
||||
/**
|
||||
@@ -50,6 +53,16 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI
|
||||
static final Set<String> KNOWN_METHOD_NAMES = Collections.unmodifiableSet(
|
||||
ContainerUtil.union(Arrays.asList(HANDLE_FACTORY_METHOD_NAMES), Collections.singletonList(FIND_CONSTRUCTOR)));
|
||||
|
||||
private interface CallChecker {
|
||||
boolean checkCall(@NotNull PsiMethodCallExpression callExpression, @NotNull ProblemsHolder holder);
|
||||
}
|
||||
|
||||
private static final CallChecker[] CALL_CHECKERS = {
|
||||
JavaLangInvokeHandleSignatureInspection::checkHandlerFactoryCall,
|
||||
JavaLangReflectHandleInvocationChecker::checkMethodHandleInvocation,
|
||||
JavaLangReflectVarHandleInvocationChecker::checkVarHandleAccess,
|
||||
};
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
@@ -58,24 +71,35 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression callExpression) {
|
||||
super.visitMethodCallExpression(callExpression);
|
||||
|
||||
final PsiReferenceExpression methodExpression = callExpression.getMethodExpression();
|
||||
final String methodName = methodExpression.getReferenceName();
|
||||
if (methodName != null && KNOWN_METHOD_NAMES.contains(methodName)) {
|
||||
final PsiMethod method = callExpression.resolveMethod();
|
||||
final PsiClass psiClass = method != null ? method.getContainingClass() : null;
|
||||
if (psiClass != null && JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP.equals(psiClass.getQualifiedName())) {
|
||||
final PsiExpression[] arguments = callExpression.getArgumentList().getExpressions();
|
||||
checkHandlerFactory(methodName, methodExpression, arguments, holder);
|
||||
}
|
||||
for (CallChecker checker : CALL_CHECKERS) {
|
||||
if (checker.checkCall(callExpression, holder)) return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void checkHandlerFactory(@NotNull String factoryMethodName,
|
||||
@NotNull PsiReferenceExpression factoryMethodExpression,
|
||||
@NotNull PsiExpression[] arguments,
|
||||
@NotNull ProblemsHolder holder) {
|
||||
private static boolean checkHandlerFactoryCall(@NotNull PsiMethodCallExpression callExpression, @NotNull ProblemsHolder holder) {
|
||||
final PsiReferenceExpression methodExpression = callExpression.getMethodExpression();
|
||||
final String methodName = methodExpression.getReferenceName();
|
||||
if (methodName != null && KNOWN_METHOD_NAMES.contains(methodName)) {
|
||||
final PsiMethod method = callExpression.resolveMethod();
|
||||
if (method != null && isClassWithName(method.getContainingClass(), JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP)) {
|
||||
final PsiExpression[] arguments = callExpression.getArgumentList().getExpressions();
|
||||
checkHandleFactory(methodName, methodExpression, arguments, holder);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (isCallToMethod(callExpression, JAVA_LANG_INVOKE_METHOD_HANDLES, ARRAY_ELEMENT_VAR_HANDLE)) {
|
||||
checkArrayElementVarHandle(callExpression, holder);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void checkHandleFactory(@NotNull String factoryMethodName,
|
||||
@NotNull PsiReferenceExpression factoryMethodExpression,
|
||||
@NotNull PsiExpression[] arguments,
|
||||
@NotNull ProblemsHolder holder) {
|
||||
if (arguments.length == 2) {
|
||||
if (FIND_CONSTRUCTOR.equals(factoryMethodName)) {
|
||||
final PsiClass ownerClass = getReflectiveClass(arguments[0]);
|
||||
@@ -231,6 +255,26 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkArrayElementVarHandle(PsiMethodCallExpression factoryCallExpression, ProblemsHolder holder) {
|
||||
final PsiExpressionList argumentList = factoryCallExpression.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
if (arguments.length != 1) {
|
||||
holder.registerProblem(argumentList, InspectionsBundle.message("inspection.reflection.invocation.argument.count", 1));
|
||||
return;
|
||||
}
|
||||
final ReflectiveType argumentType = getReflectiveType(arguments[0]);
|
||||
if (argumentType == null || argumentType.getType() instanceof PsiArrayType) {
|
||||
return;
|
||||
}
|
||||
if (!argumentType.isPrimitive()) {
|
||||
final String name = argumentType.getQualifiedName();
|
||||
if (JAVA_LANG_OBJECT.equals(name) || "java.io.Serializable".equals(name) || "java.lang.Cloneable".equals(name)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
holder.registerProblem(arguments[0], InspectionsBundle.message("inspection.reflect.handle.invocation.argument.not.array"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getMethodDeclarationText(@NotNull String methodName, @NotNull ReflectiveSignature methodSignature) {
|
||||
final String returnType = methodSignature.getShortReturnType();
|
||||
@@ -329,13 +373,13 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI
|
||||
final boolean finalArray = signature.getSecond();
|
||||
|
||||
final List<String> typeNames = new ArrayList<>();
|
||||
typeNames.add(CommonClassNames.JAVA_LANG_OBJECT); // return type
|
||||
typeNames.add(JAVA_LANG_OBJECT); // return type
|
||||
|
||||
for (int i = 0; i < objectArgCount; i++) {
|
||||
typeNames.add(CommonClassNames.JAVA_LANG_OBJECT);
|
||||
typeNames.add(JAVA_LANG_OBJECT);
|
||||
}
|
||||
if (finalArray) {
|
||||
typeNames.add(CommonClassNames.JAVA_LANG_OBJECT + "[]");
|
||||
typeNames.add(JAVA_LANG_OBJECT + "[]");
|
||||
}
|
||||
return ReflectiveSignature.create(typeNames);
|
||||
}
|
||||
|
||||
+64
-75
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.reflectiveAccess;
|
||||
|
||||
import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool;
|
||||
import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -34,15 +33,14 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.intellij.codeInspection.reflectiveAccess.JavaLangReflectVarHandleInvocationChecker.checkVarHandleAccess;
|
||||
import static com.intellij.psi.CommonClassNames.JAVA_UTIL_LIST;
|
||||
import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceUtil.*;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class JavaLangReflectHandleInvocationInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
private static final Logger LOG = Logger.getInstance(JavaLangReflectHandleInvocationInspection.class);
|
||||
class JavaLangReflectHandleInvocationChecker {
|
||||
private static final Logger LOG = Logger.getInstance(JavaLangReflectHandleInvocationChecker.class);
|
||||
|
||||
private static final String INVOKE = "invoke";
|
||||
private static final String INVOKE_EXACT = "invokeExact";
|
||||
@@ -51,95 +49,86 @@ public class JavaLangReflectHandleInvocationInspection extends BaseJavaBatchLoca
|
||||
|
||||
private static final Set<String> METHOD_HANDLE_INVOKE_NAMES = ContainerUtil.set(INVOKE, INVOKE_EXACT, INVOKE_WITH_ARGUMENTS);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression methodCall) {
|
||||
super.visitMethodCallExpression(methodCall);
|
||||
|
||||
final String referenceName = methodCall.getMethodExpression().getReferenceName();
|
||||
if (METHOD_HANDLE_INVOKE_NAMES.contains(referenceName)) {
|
||||
final PsiMethod method = methodCall.resolveMethod();
|
||||
if (method != null && isClassWithName(method.getContainingClass(), JAVA_LANG_INVOKE_METHOD_HANDLE)) {
|
||||
if (isWithDynamicArguments(methodCall)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression qualifierDefinition = findDefinition(methodCall.getMethodExpression().getQualifierExpression());
|
||||
if (qualifierDefinition instanceof PsiMethodCallExpression) {
|
||||
checkMethodHandleInvocation((PsiMethodCallExpression)qualifierDefinition, methodCall);
|
||||
}
|
||||
}
|
||||
static boolean checkMethodHandleInvocation(@NotNull PsiMethodCallExpression methodCall, @NotNull ProblemsHolder holder) {
|
||||
final String referenceName = methodCall.getMethodExpression().getReferenceName();
|
||||
if (METHOD_HANDLE_INVOKE_NAMES.contains(referenceName)) {
|
||||
final PsiMethod method = methodCall.resolveMethod();
|
||||
if (method != null && isClassWithName(method.getContainingClass(), JAVA_LANG_INVOKE_METHOD_HANDLE)) {
|
||||
if (isWithDynamicArguments(methodCall)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
checkVarHandleAccess(methodCall, holder);
|
||||
final PsiExpression qualifierDefinition = findDefinition(methodCall.getMethodExpression().getQualifierExpression());
|
||||
if (qualifierDefinition instanceof PsiMethodCallExpression) {
|
||||
checkMethodHandleInvocation((PsiMethodCallExpression)qualifierDefinition, methodCall, holder);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkMethodHandleInvocation(@NotNull PsiMethodCallExpression handleFactoryCall,
|
||||
@NotNull PsiMethodCallExpression invokeCall) {
|
||||
final String factoryMethodName = handleFactoryCall.getMethodExpression().getReferenceName();
|
||||
if (factoryMethodName != null && JavaLangInvokeHandleSignatureInspection.KNOWN_METHOD_NAMES.contains(factoryMethodName)) {
|
||||
private static void checkMethodHandleInvocation(@NotNull PsiMethodCallExpression handleFactoryCall,
|
||||
@NotNull PsiMethodCallExpression invokeCall,
|
||||
@NotNull ProblemsHolder holder) {
|
||||
final String factoryMethodName = handleFactoryCall.getMethodExpression().getReferenceName();
|
||||
if (factoryMethodName != null && JavaLangInvokeHandleSignatureInspection.KNOWN_METHOD_NAMES.contains(factoryMethodName)) {
|
||||
|
||||
final PsiExpression[] handleFactoryArguments = handleFactoryCall.getArgumentList().getExpressions();
|
||||
final boolean isFindConstructor = FIND_CONSTRUCTOR.equals(factoryMethodName);
|
||||
if (handleFactoryArguments.length == 3 && !isFindConstructor ||
|
||||
handleFactoryArguments.length == 2 && isFindConstructor ||
|
||||
handleFactoryArguments.length == 4 && FIND_SPECIAL.equals(factoryMethodName)) {
|
||||
final PsiExpression[] handleFactoryArguments = handleFactoryCall.getArgumentList().getExpressions();
|
||||
final boolean isFindConstructor = FIND_CONSTRUCTOR.equals(factoryMethodName);
|
||||
if (handleFactoryArguments.length == 3 && !isFindConstructor ||
|
||||
handleFactoryArguments.length == 2 && isFindConstructor ||
|
||||
handleFactoryArguments.length == 4 && FIND_SPECIAL.equals(factoryMethodName)) {
|
||||
|
||||
final PsiMethod factoryMethod = handleFactoryCall.resolveMethod();
|
||||
if (factoryMethod != null && isClassWithName(factoryMethod.getContainingClass(), JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP)) {
|
||||
final ReflectiveType receiverType = getReflectiveType(handleFactoryArguments[0]);
|
||||
final boolean isExact = INVOKE_EXACT.equals(invokeCall.getMethodExpression().getReferenceName());
|
||||
final PsiMethod factoryMethod = handleFactoryCall.resolveMethod();
|
||||
if (factoryMethod != null && isClassWithName(factoryMethod.getContainingClass(), JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP)) {
|
||||
final ReflectiveType receiverType = getReflectiveType(handleFactoryArguments[0]);
|
||||
final boolean isExact = INVOKE_EXACT.equals(invokeCall.getMethodExpression().getReferenceName());
|
||||
|
||||
if (isFindConstructor) {
|
||||
if (!checkMethodSignature(invokeCall, handleFactoryArguments[1], isExact, true, 0, holder)) return;
|
||||
checkReturnType(invokeCall, receiverType, isExact, holder);
|
||||
return;
|
||||
}
|
||||
if (isFindConstructor) {
|
||||
if (!checkMethodSignature(invokeCall, handleFactoryArguments[1], isExact, true, 0, holder)) return;
|
||||
checkReturnType(invokeCall, receiverType, isExact, holder);
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiExpression typeExpression = handleFactoryArguments[2];
|
||||
switch (factoryMethodName) {
|
||||
case FIND_VIRTUAL:
|
||||
case FIND_SPECIAL:
|
||||
if (!checkMethodSignature(invokeCall, typeExpression, isExact, false, 1, holder)) return;
|
||||
checkCallReceiver(invokeCall, receiverType, holder);
|
||||
break;
|
||||
final PsiExpression typeExpression = handleFactoryArguments[2];
|
||||
switch (factoryMethodName) {
|
||||
case FIND_VIRTUAL:
|
||||
case FIND_SPECIAL:
|
||||
if (!checkMethodSignature(invokeCall, typeExpression, isExact, false, 1, holder)) return;
|
||||
checkCallReceiver(invokeCall, receiverType, holder);
|
||||
break;
|
||||
|
||||
case FIND_STATIC:
|
||||
checkMethodSignature(invokeCall, typeExpression, isExact, false, 0, holder);
|
||||
break;
|
||||
case FIND_STATIC:
|
||||
checkMethodSignature(invokeCall, typeExpression, isExact, false, 0, holder);
|
||||
break;
|
||||
|
||||
case FIND_GETTER:
|
||||
if (!checkGetter(invokeCall, typeExpression, isExact, 1, holder)) return;
|
||||
checkCallReceiver(invokeCall, receiverType, holder);
|
||||
break;
|
||||
case FIND_GETTER:
|
||||
if (!checkGetter(invokeCall, typeExpression, isExact, 1, holder)) return;
|
||||
checkCallReceiver(invokeCall, receiverType, holder);
|
||||
break;
|
||||
|
||||
case FIND_SETTER:
|
||||
if (!checkSetter(invokeCall, typeExpression, isExact, 1, holder)) return;
|
||||
checkCallReceiver(invokeCall, receiverType, holder);
|
||||
break;
|
||||
case FIND_SETTER:
|
||||
if (!checkSetter(invokeCall, typeExpression, isExact, 1, holder)) return;
|
||||
checkCallReceiver(invokeCall, receiverType, holder);
|
||||
break;
|
||||
|
||||
case FIND_STATIC_GETTER:
|
||||
checkGetter(invokeCall, typeExpression, isExact, 0, holder);
|
||||
break;
|
||||
case FIND_STATIC_GETTER:
|
||||
checkGetter(invokeCall, typeExpression, isExact, 0, holder);
|
||||
break;
|
||||
|
||||
case FIND_STATIC_SETTER:
|
||||
checkSetter(invokeCall, typeExpression, isExact, 0, holder);
|
||||
break;
|
||||
case FIND_STATIC_SETTER:
|
||||
checkSetter(invokeCall, typeExpression, isExact, 0, holder);
|
||||
break;
|
||||
|
||||
case FIND_VAR_HANDLE:
|
||||
break;
|
||||
case FIND_VAR_HANDLE:
|
||||
break;
|
||||
|
||||
case FIND_STATIC_VAR_HANDLE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
case FIND_STATIC_VAR_HANDLE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static void checkCallReceiver(@NotNull PsiMethodCallExpression invokeCall,
|
||||
+8
-6
@@ -26,18 +26,18 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.intellij.codeInspection.reflectiveAccess.JavaLangReflectHandleInvocationInspection.*;
|
||||
import static com.intellij.codeInspection.reflectiveAccess.JavaLangReflectHandleInvocationChecker.*;
|
||||
import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceUtil.*;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class JavaLangReflectVarHandleInvocationChecker {
|
||||
class JavaLangReflectVarHandleInvocationChecker {
|
||||
private static final Logger LOG = Logger.getInstance(JavaLangReflectVarHandleInvocationChecker.class);
|
||||
|
||||
private static final String ARRAY_ELEMENT_VAR_HANDLE = "arrayElementVarHandle";
|
||||
private static final String JAVA_LANG_INVOKE_VAR_HANDLE = "java.lang.invoke.VarHandle";
|
||||
private static final String JAVA_LANG_INVOKE_METHOD_HANDLES = "java.lang.invoke.MethodHandles";
|
||||
static final String ARRAY_ELEMENT_VAR_HANDLE = "arrayElementVarHandle";
|
||||
static final String JAVA_LANG_INVOKE_VAR_HANDLE = "java.lang.invoke.VarHandle";
|
||||
static final String JAVA_LANG_INVOKE_METHOD_HANDLES = "java.lang.invoke.MethodHandles";
|
||||
|
||||
private static final String GET = "get";
|
||||
private static final String GET_VOLATILE = "getVolatile";
|
||||
@@ -110,7 +110,7 @@ public class JavaLangReflectVarHandleInvocationChecker {
|
||||
COMPARE_AND_EXCHANGE, COMPARE_AND_EXCHANGE_ACQUIRE, COMPARE_AND_EXCHANGE_RELEASE);
|
||||
|
||||
|
||||
static void checkVarHandleAccess(PsiMethodCallExpression methodCall, @NotNull ProblemsHolder holder) {
|
||||
static boolean checkVarHandleAccess(PsiMethodCallExpression methodCall, @NotNull ProblemsHolder holder) {
|
||||
if (isVarHandleAccessMethod(methodCall)) {
|
||||
final PsiExpression qualifierDefinition = findDefinition(methodCall.getMethodExpression().getQualifierExpression());
|
||||
if (qualifierDefinition instanceof PsiMethodCallExpression) {
|
||||
@@ -144,7 +144,9 @@ public class JavaLangReflectVarHandleInvocationChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void checkVarHandleAccessSignature(@NotNull PsiMethodCallExpression accessCall,
|
||||
|
||||
@@ -30,7 +30,16 @@ class Main {
|
||||
|
||||
l.<warning descr="Field 'myString' is not static">findStaticVarHandle</warning>(Test.class, "myString", String.class);
|
||||
l.<warning descr="Field 'ourString' is static">findVarHandle</warning>(Test.class, "ourString", String.class);
|
||||
|
||||
MethodHandles.arrayElementVarHandle(Test[].class);
|
||||
MethodHandles.arrayElementVarHandle(int[].class);
|
||||
MethodHandles.arrayElementVarHandle(cloneable().getClass());
|
||||
|
||||
MethodHandles.arrayElementVarHandle(<warning descr="Argument is not an array type">Test.class</warning>);
|
||||
MethodHandles.arrayElementVarHandle(<warning descr="Argument is not an array type">int.class</warning>);
|
||||
}
|
||||
|
||||
static Cloneable cloneable() {return null;}
|
||||
}
|
||||
|
||||
class Test {
|
||||
|
||||
+2
-2
@@ -264,7 +264,7 @@ class Main {
|
||||
|
||||
void compare() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findStaticVarHandle(Test.class, "myS", String.class);
|
||||
final VarHandle handle = lookup.findStaticVarHandle(Test.class, "s", String.class);
|
||||
final Test instance = new Test();
|
||||
|
||||
boolean exactCAS = handle.compareAndSet("a", "b");
|
||||
@@ -289,7 +289,7 @@ class Main {
|
||||
|
||||
void weakCompare() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findStaticVarHandle(Test.class, "myS", String.class);
|
||||
final VarHandle handle = lookup.findStaticVarHandle(Test.class, "s", String.class);
|
||||
final Test instance = new Test();
|
||||
|
||||
boolean exactCAS = handle.weakCompareAndSet("a", "b");
|
||||
|
||||
@@ -318,7 +318,7 @@ class Main {
|
||||
|
||||
void compare() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findVarHandle(Test.class, "myS", String.class);
|
||||
final VarHandle handle = lookup.findVarHandle(Test.class, "s", String.class);
|
||||
final Test instance = new Test();
|
||||
|
||||
boolean exactCAS = handle.compareAndSet(instance, "a", "b");
|
||||
@@ -343,7 +343,7 @@ class Main {
|
||||
|
||||
void weakCompare() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findVarHandle(Test.class, "myS", String.class);
|
||||
final VarHandle handle = lookup.findVarHandle(Test.class, "s", String.class);
|
||||
final Test instance = new Test();
|
||||
|
||||
boolean exactCAS = handle.weakCompareAndSet(instance, "a", "b");
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@
|
||||
package com.intellij.codeInspection
|
||||
|
||||
import com.intellij.JavaTestUtil
|
||||
import com.intellij.codeInspection.reflectiveAccess.JavaLangReflectHandleInvocationInspection
|
||||
import com.intellij.codeInspection.reflectiveAccess.JavaLangInvokeHandleSignatureInspection
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
@@ -51,7 +51,7 @@ abstract class JavaLangReflectHandleInvocationTestBase(val languageLevel: Langua
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
LanguageLevelProjectExtension.getInstance(project).languageLevel = languageLevel
|
||||
myFixture.enableInspections(JavaLangReflectHandleInvocationInspection())
|
||||
myFixture.enableInspections(JavaLangInvokeHandleSignatureInspection())
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = descriptor
|
||||
|
||||
@@ -832,13 +832,12 @@ inspection.reflection.invocation.argument.not.assignable=Argument is not assigna
|
||||
inspection.reflection.invocation.item.not.assignable=Array item is not assignable to ''{0}''
|
||||
inspection.reflection.invocation.array.not.assignable=Array {0,choice,1#item has|1<items have} incompatible {0,choice,1#type|1<types}
|
||||
|
||||
inspection.reflect.handle.invocation.name=MethodHandle/VarHandle invocation arguments mismatch
|
||||
inspection.reflect.handle.invocation.receiver.missing=Call receiver is missing
|
||||
inspection.reflect.handle.invocation.receiver.null=Call receiver is 'null'
|
||||
inspection.reflect.handle.invocation.receiver.incompatible=Call receiver type is incompatible: ''{0}'' is expected
|
||||
inspection.reflect.handle.invocation.argument.not.exact=Argument type should be exactly ''{0}''
|
||||
inspection.reflect.handle.invocation.result.not.exact=Should be cast to ''{0}''
|
||||
inspection.reflect.handle.invocation.result.not.assignable=Should be cast to ''{0}'' or its superclass
|
||||
inspection.reflect.handle.invocation.argument.not.array=Argument is not an array type
|
||||
inspection.reflect.handle.invocation.primitive.argument.null=Argument of type ''{0}'' cannot be ''null''
|
||||
inspection.reflect.handle.invocation.result.void=Return type is 'void'
|
||||
inspection.reflect.handle.invocation.result.null=Returned value is always 'null'
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection detects the case where the type of a VarHandle or the signature of a MethodHandle doesn't match the actual field or method.
|
||||
<p>It also detects if a static field/method is accessed in non-static way and vice versa.
|
||||
This inspection detects the case where the signature of a MethodHandle or the type of a VarHandle doesn't match the actual method or field.
|
||||
<p>It also checks that the arguments provided to MethodHandle.invoke(), VarHandle.set(), etc match the method signature/field type.
|
||||
<!-- tooltip end -->
|
||||
|
||||
<p>Examples:</p>
|
||||
<pre><code>
|
||||
MethodHandle mh = MethodHandles.lookup().findVirtual(
|
||||
MyClass.class, "foo", MethodType.methodType(void.class, int.class));
|
||||
<i>// the argument should be an <b>int</b> value</i>
|
||||
mh.invoke(myObj, "<b>abc</b>");
|
||||
</code></pre>
|
||||
<br>
|
||||
<pre><code>
|
||||
<i>// the argument should be <b>String</b>.class</i>
|
||||
VarHandle vh = MethodHandles.lookup().findVarHandle(
|
||||
MyClass.class, "text", <b>int</b>.class);
|
||||
</code></pre>
|
||||
<br>
|
||||
<pre><code>
|
||||
VarHandle vh = MethodHandles.lookup().findVarHandle(
|
||||
MyClass.class, "text", String.class);
|
||||
<i>// the argument should be a <b>String</b> value</i>
|
||||
vh.set(myObj, <b>42</b>);
|
||||
</code></pre>
|
||||
<p>
|
||||
<small>New in 2017.2</small>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,27 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
The inspection checks that the arguments provided to MethodHandle.invoke(), VarHandle.set(), and similar methods
|
||||
match the method handle signature and var handle type.
|
||||
<!-- tooltip end -->
|
||||
<p>The signature of the method handle is specified in Lookup.findVirtual(), Lookup.findGetter(), etc.</p>
|
||||
<p>The type of the var handle is specified in Lookup.findVarHandle(), MethodHandles.arrayElementVarHandle(), etc.</p>
|
||||
|
||||
<p>Examples:</p>
|
||||
<pre><code>
|
||||
MethodHandle mh = MethodHandles.lookup().findVirtual(
|
||||
MyClass.class, "foo", MethodType.methodType(void.class, int.class));
|
||||
<i>// the argument should be an <b>int</b> value</i>
|
||||
mh.invoke(myObj, "<b>abc</b>");
|
||||
</code></pre>
|
||||
<pre><code>
|
||||
VarHandle vh = MethodHandles.lookup().findVarHandle(
|
||||
MyClass.class, "text", String.class);
|
||||
<i>// the argument should be a <b>String</b> value</i>
|
||||
vh.set(myObj, <b>42</b>);
|
||||
</code></pre>
|
||||
|
||||
<p>
|
||||
<small>New in 2017.2</small>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -955,10 +955,6 @@
|
||||
groupPath="Java" groupBundle="messages.InspectionsBundle" groupKey="group.names.reflective.access.issues"
|
||||
bundle="messages.InspectionsBundle" key="inspection.reflection.invocation.name"
|
||||
implementationClass="com.intellij.codeInspection.reflectiveAccess.JavaReflectionInvocationInspection"/>
|
||||
<localInspection language="JAVA" shortName="JavaLangReflectHandleInvocation" enabledByDefault="true" level="WARNING"
|
||||
groupPath="Java" groupBundle="messages.InspectionsBundle" groupKey="group.names.reflective.access.issues"
|
||||
bundle="messages.InspectionsBundle" key="inspection.reflect.handle.invocation.name"
|
||||
implementationClass="com.intellij.codeInspection.reflectiveAccess.JavaLangReflectHandleInvocationInspection"/>
|
||||
<localInspection language="JAVA" shortName="JavaReflectionMemberAccess" enabledByDefault="true" level="WARNING"
|
||||
groupPath="Java" groupBundle="messages.InspectionsBundle" groupKey="group.names.reflective.access.issues"
|
||||
bundle="messages.InspectionsBundle" key="inspection.reflection.member.access.name"
|
||||
|
||||
Reference in New Issue
Block a user