mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java: Inspection to verify parameters of VarHandle.get(), VarHandle.set(), and similar methods (IDEA-172358)
This commit is contained in:
+261
-248
@@ -34,6 +34,7 @@ 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.*;
|
||||
|
||||
@@ -48,7 +49,7 @@ public class JavaLangReflectHandleInvocationInspection extends BaseJavaBatchLoca
|
||||
private static final String INVOKE_WITH_ARGUMENTS = "invokeWithArguments";
|
||||
private static final String JAVA_LANG_INVOKE_METHOD_HANDLE = "java.lang.invoke.MethodHandle";
|
||||
|
||||
private static final Set<String> INVOKE_NAMES = ContainerUtil.set(INVOKE, INVOKE_EXACT, INVOKE_WITH_ARGUMENTS);
|
||||
private static final Set<String> METHOD_HANDLE_INVOKE_NAMES = ContainerUtil.set(INVOKE, INVOKE_EXACT, INVOKE_WITH_ARGUMENTS);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -59,7 +60,7 @@ public class JavaLangReflectHandleInvocationInspection extends BaseJavaBatchLoca
|
||||
super.visitMethodCallExpression(methodCall);
|
||||
|
||||
final String referenceName = methodCall.getMethodExpression().getReferenceName();
|
||||
if (referenceName != null && INVOKE_NAMES.contains(referenceName)) {
|
||||
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)) {
|
||||
@@ -67,15 +68,17 @@ public class JavaLangReflectHandleInvocationInspection extends BaseJavaBatchLoca
|
||||
}
|
||||
final PsiExpression qualifierDefinition = findDefinition(methodCall.getMethodExpression().getQualifierExpression());
|
||||
if (qualifierDefinition instanceof PsiMethodCallExpression) {
|
||||
checkMethodHandleInvocation((PsiMethodCallExpression)qualifierDefinition, methodCall, INVOKE_EXACT.equals(referenceName));
|
||||
checkMethodHandleInvocation((PsiMethodCallExpression)qualifierDefinition, methodCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
checkVarHandleAccess(methodCall, holder);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMethodHandleInvocation(@NotNull PsiMethodCallExpression handleFactoryCall,
|
||||
@NotNull PsiMethodCallExpression invokeCall,
|
||||
boolean isExact) {
|
||||
@NotNull PsiMethodCallExpression invokeCall) {
|
||||
final String factoryMethodName = handleFactoryCall.getMethodExpression().getReferenceName();
|
||||
if (factoryMethodName != null && JavaLangInvokeHandleSignatureInspection.KNOWN_METHOD_NAMES.contains(factoryMethodName)) {
|
||||
|
||||
@@ -87,10 +90,12 @@ public class JavaLangReflectHandleInvocationInspection extends BaseJavaBatchLoca
|
||||
|
||||
final PsiMethod factoryMethod = handleFactoryCall.resolveMethod();
|
||||
if (factoryMethod != null && isClassWithName(factoryMethod.getContainingClass(), JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP)) {
|
||||
final PsiClass psiClass = getReflectiveClass(handleFactoryArguments[0]);
|
||||
final ReflectiveType receiverType = getReflectiveType(handleFactoryArguments[0]);
|
||||
final boolean isExact = INVOKE_EXACT.equals(invokeCall.getMethodExpression().getReferenceName());
|
||||
|
||||
if (isFindConstructor) {
|
||||
if (psiClass != null) checkArgumentTypes(invokeCall, handleFactoryArguments[1], isExact, 0, psiClass);
|
||||
if (!checkMethodSignature(invokeCall, handleFactoryArguments[1], isExact, true, 0, holder)) return;
|
||||
checkReturnType(invokeCall, receiverType, isExact, holder);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -98,30 +103,30 @@ public class JavaLangReflectHandleInvocationInspection extends BaseJavaBatchLoca
|
||||
switch (factoryMethodName) {
|
||||
case FIND_VIRTUAL:
|
||||
case FIND_SPECIAL:
|
||||
if (!checkArgumentTypes(invokeCall, typeExpression, isExact, 1, null)) return;
|
||||
checkCallReceiver(invokeCall, psiClass);
|
||||
if (!checkMethodSignature(invokeCall, typeExpression, isExact, false, 1, holder)) return;
|
||||
checkCallReceiver(invokeCall, receiverType, holder);
|
||||
break;
|
||||
|
||||
case FIND_STATIC:
|
||||
checkArgumentTypes(invokeCall, typeExpression, isExact, 0, null);
|
||||
checkMethodSignature(invokeCall, typeExpression, isExact, false, 0, holder);
|
||||
break;
|
||||
|
||||
case FIND_GETTER:
|
||||
if (!checkGetter(invokeCall, typeExpression, isExact, 1)) return;
|
||||
checkCallReceiver(invokeCall, psiClass);
|
||||
if (!checkGetter(invokeCall, typeExpression, isExact, 1, holder)) return;
|
||||
checkCallReceiver(invokeCall, receiverType, holder);
|
||||
break;
|
||||
|
||||
case FIND_SETTER:
|
||||
if (!checkSetter(invokeCall, typeExpression, isExact, 1)) return;
|
||||
checkCallReceiver(invokeCall, psiClass);
|
||||
if (!checkSetter(invokeCall, typeExpression, isExact, 1, holder)) return;
|
||||
checkCallReceiver(invokeCall, receiverType, holder);
|
||||
break;
|
||||
|
||||
case FIND_STATIC_GETTER:
|
||||
checkGetter(invokeCall, typeExpression, isExact, 0);
|
||||
checkGetter(invokeCall, typeExpression, isExact, 0, holder);
|
||||
break;
|
||||
|
||||
case FIND_STATIC_SETTER:
|
||||
checkSetter(invokeCall, typeExpression, isExact, 0);
|
||||
checkSetter(invokeCall, typeExpression, isExact, 0, holder);
|
||||
break;
|
||||
|
||||
case FIND_VAR_HANDLE:
|
||||
@@ -134,238 +139,246 @@ public class JavaLangReflectHandleInvocationInspection extends BaseJavaBatchLoca
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCallReceiver(@NotNull PsiMethodCallExpression invokeCall, @Nullable PsiClass psiClass) {
|
||||
final PsiExpressionList argumentList = invokeCall.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
if (arguments.length == 0) {
|
||||
holder.registerProblem(argumentList, InspectionsBundle.message("inspection.reflect.handle.invocation.receiver.missing"));
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiExpression receiver = arguments[0];
|
||||
LOG.assertTrue(receiver != null);
|
||||
final PsiExpression receiverDefinition = findDefinition(receiver);
|
||||
if (ExpressionUtils.isNullLiteral(receiverDefinition)) {
|
||||
holder.registerProblem(receiver, InspectionsBundle.message("inspection.reflect.handle.invocation.receiver.null"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (psiClass != null) {
|
||||
final PsiClassType expectedType = JavaPsiFacade.getElementFactory(holder.getProject()).createType(psiClass);
|
||||
if (!isCompatible(expectedType, receiver.getType())) {
|
||||
holder.registerProblem(receiver,
|
||||
InspectionsBundle.message("inspection.reflect.handle.invocation.receiver.incompatible",
|
||||
psiClass.getQualifiedName()));
|
||||
}
|
||||
else if (receiver != receiverDefinition && receiverDefinition != null) {
|
||||
if (!isCompatible(expectedType, receiverDefinition.getType())) {
|
||||
holder.registerProblem(receiver, InspectionsBundle.message("inspection.reflect.handle.invocation.receiver.incompatible",
|
||||
psiClass.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkArgumentTypes(@NotNull PsiMethodCallExpression invokeCall,
|
||||
@NotNull PsiExpression signatureExpression,
|
||||
boolean isExact,
|
||||
int argumentOffset,
|
||||
@Nullable PsiClass resultClass) {
|
||||
final List<Supplier<ReflectiveType>> lazyRequiredTypes = getMethodType(signatureExpression);
|
||||
if (lazyRequiredTypes == null) return true;
|
||||
|
||||
final PsiExpressionList argumentList = invokeCall.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
JavaReflectionInvocationInspection.Arguments actualArguments =
|
||||
JavaReflectionInvocationInspection.getActualMethodArguments(arguments, argumentOffset, false);
|
||||
if (actualArguments == null) return true;
|
||||
|
||||
final int requiredArgumentCount = lazyRequiredTypes.size() - 1; // - 1 stands for return type
|
||||
if (!checkArgumentCount(actualArguments.expressions, requiredArgumentCount, argumentOffset, argumentList)) return false;
|
||||
final ReflectiveType returnType = resultClass != null ? ReflectiveType.create(resultClass) : lazyRequiredTypes.get(0).get();
|
||||
checkReturnType(invokeCall, returnType, isExact);
|
||||
|
||||
LOG.assertTrue(actualArguments.expressions.length == requiredArgumentCount);
|
||||
for (int i = 0; i < requiredArgumentCount; i++) {
|
||||
final ReflectiveType requiredType = lazyRequiredTypes.get(i + 1).get();
|
||||
checkArgumentType(actualArguments.expressions[i], requiredType, argumentList, isExact);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkArgumentType(@NotNull PsiExpression argument,
|
||||
@Nullable ReflectiveType requiredType,
|
||||
@NotNull PsiExpressionList argumentList,
|
||||
boolean isExact) {
|
||||
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,
|
||||
InspectionsBundle.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,
|
||||
InspectionsBundle.message("inspection.reflect.handle.invocation.primitive.argument.null",
|
||||
requiredType.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkReturnType(@NotNull PsiMethodCallExpression invokeCall,
|
||||
@Nullable ReflectiveType requiredType,
|
||||
boolean isExact) {
|
||||
if (requiredType == null) return;
|
||||
final PsiElement invokeParent = invokeCall.getParent();
|
||||
PsiType actualType = null;
|
||||
PsiElement problemElement = null;
|
||||
if (invokeParent instanceof PsiTypeCastExpression) {
|
||||
final PsiTypeElement castTypeElement = ((PsiTypeCastExpression)invokeParent).getCastType();
|
||||
if (castTypeElement != null) {
|
||||
actualType = castTypeElement.getType();
|
||||
problemElement = castTypeElement;
|
||||
}
|
||||
}
|
||||
else if (invokeParent instanceof PsiAssignmentExpression) {
|
||||
actualType = ((PsiAssignmentExpression)invokeParent).getLExpression().getType();
|
||||
}
|
||||
else if (invokeParent instanceof PsiVariable) {
|
||||
actualType = ((PsiVariable)invokeParent).getType();
|
||||
}
|
||||
|
||||
if (actualType != null && !isCompatible(requiredType, actualType, isExact)) {
|
||||
if (problemElement == null) {
|
||||
problemElement = invokeCall.getMethodExpression();
|
||||
}
|
||||
holder.registerProblem(problemElement, InspectionsBundle.message(isExact || requiredType.isPrimitive()
|
||||
? "inspection.reflect.handle.invocation.result.not.exact"
|
||||
: "inspection.reflect.handle.invocation.result.not.assignable",
|
||||
requiredType.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<Supplier<ReflectiveType>> getMethodType(@Nullable PsiExpression methodTypeExpression) {
|
||||
final PsiExpression typeDefinition = findDefinition(methodTypeExpression);
|
||||
if (typeDefinition instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression typeDefinitionCall = (PsiMethodCallExpression)typeDefinition;
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
else if (isCallToMethod(typeDefinitionCall, JAVA_LANG_INVOKE_METHOD_TYPE, GENERIC_METHOD_TYPE)) {
|
||||
final PsiExpression[] arguments = typeDefinitionCall.getArgumentList().getExpressions();
|
||||
final Pair.NonNull<Integer, Boolean> signature = JavaLangInvokeHandleSignatureInspection.getGenericSignature(arguments);
|
||||
if (signature != null) {
|
||||
final int objectArgCount = signature.getFirst();
|
||||
final boolean finalArray = signature.getSecond();
|
||||
if (objectArgCount == 0 && !finalArray) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(holder.getProject());
|
||||
final PsiClass objectClass = facade.findClass(CommonClassNames.JAVA_LANG_OBJECT, methodTypeExpression.getResolveScope());
|
||||
if (objectClass != null) {
|
||||
final List<ReflectiveType> argumentTypes = new ArrayList<>();
|
||||
final ReflectiveType objectType = ReflectiveType.create(objectClass);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
private boolean checkGetter(@NotNull PsiMethodCallExpression invokeCall,
|
||||
@NotNull PsiExpression typeExpression,
|
||||
boolean isExact,
|
||||
int argumentOffset) {
|
||||
final PsiExpressionList argumentList = invokeCall.getArgumentList();
|
||||
if (!checkArgumentCount(argumentList.getExpressions(), argumentOffset, 0, argumentList)) return false;
|
||||
|
||||
final ReflectiveType resultType = getReflectiveType(typeExpression);
|
||||
if (resultType != null) {
|
||||
checkReturnType(invokeCall, resultType, isExact);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkSetter(@NotNull PsiMethodCallExpression invokeCall,
|
||||
@NotNull PsiExpression typeExpression,
|
||||
boolean isExact,
|
||||
int argumentOffset) {
|
||||
final PsiExpressionList argumentList = invokeCall.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
if (!checkArgumentCount(arguments, argumentOffset + 1, 0, argumentList)) return false;
|
||||
|
||||
LOG.assertTrue(arguments.length == argumentOffset + 1);
|
||||
final ReflectiveType requiredType = getReflectiveType(typeExpression);
|
||||
checkArgumentType(arguments[argumentOffset], requiredType, argumentList, isExact);
|
||||
|
||||
final PsiElement invokeParent = invokeCall.getParent();
|
||||
if (!(invokeParent instanceof PsiStatement)) {
|
||||
holder.registerProblem(invokeCall.getMethodExpression(),
|
||||
InspectionsBundle.message(isExact
|
||||
? "inspection.reflect.handle.invocation.result.void"
|
||||
: "inspection.reflect.handle.invocation.result.null"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkArgumentCount(@NotNull PsiExpression[] arguments, int requiredArgumentCount, int argumentOffset,
|
||||
PsiElement problemElement) {
|
||||
if (arguments.length != requiredArgumentCount) {
|
||||
holder.registerProblem(problemElement, InspectionsBundle.message(
|
||||
"inspection.reflection.invocation.argument.count", requiredArgumentCount + argumentOffset));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isCompatible(@NotNull ReflectiveType requiredType, @NotNull PsiType actualType, boolean isExact) {
|
||||
if (isExact) {
|
||||
return requiredType.isEqualTo(actualType);
|
||||
}
|
||||
return requiredType.isAssignableFrom(actualType) || actualType.isAssignableFrom(requiredType.getType());
|
||||
}
|
||||
|
||||
|
||||
private boolean isCompatible(@NotNull PsiClassType expectedType, @Nullable PsiType actualType) {
|
||||
return actualType != null && (expectedType.isAssignableFrom(actualType) || actualType.isAssignableFrom(expectedType));
|
||||
}
|
||||
|
||||
private boolean isWithDynamicArguments(@NotNull PsiMethodCallExpression invokeCall) {
|
||||
if (INVOKE_WITH_ARGUMENTS.equals(invokeCall.getMethodExpression().getReferenceName())) {
|
||||
final PsiExpression[] arguments = invokeCall.getArgumentList().getExpressions();
|
||||
if (arguments.length == 1) {
|
||||
return JavaReflectionInvocationInspection.isVarargAsArray(arguments[0]) ||
|
||||
InheritanceUtil.isInheritor(arguments[0].getType(), JAVA_UTIL_LIST);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static void checkCallReceiver(@NotNull PsiMethodCallExpression invokeCall,
|
||||
@Nullable ReflectiveType expectedType,
|
||||
ProblemsHolder holder) {
|
||||
final PsiExpressionList argumentList = invokeCall.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
if (arguments.length == 0) return;
|
||||
|
||||
final PsiExpression receiverArgument = arguments[0];
|
||||
LOG.assertTrue(receiverArgument != null);
|
||||
final PsiExpression receiverDefinition = findDefinition(receiverArgument);
|
||||
if (ExpressionUtils.isNullLiteral(receiverDefinition)) {
|
||||
holder.registerProblem(receiverArgument, InspectionsBundle.message("inspection.reflect.handle.invocation.receiver.null"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (expectedType != null) {
|
||||
if (!isCompatible(expectedType.getType(), receiverArgument.getType())) {
|
||||
holder.registerProblem(receiverArgument,
|
||||
InspectionsBundle.message("inspection.reflect.handle.invocation.receiver.incompatible",
|
||||
expectedType.getQualifiedName()));
|
||||
}
|
||||
else if (receiverArgument != receiverDefinition && receiverDefinition != null) {
|
||||
if (!isCompatible(expectedType.getType(), receiverDefinition.getType())) {
|
||||
holder.registerProblem(receiverArgument, InspectionsBundle.message("inspection.reflect.handle.invocation.receiver.incompatible",
|
||||
expectedType.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkMethodSignature(@NotNull PsiMethodCallExpression invokeCall,
|
||||
@NotNull PsiExpression signatureExpression,
|
||||
boolean isExact,
|
||||
boolean isConstructor,
|
||||
int argumentOffset,
|
||||
@NotNull ProblemsHolder holder) {
|
||||
final List<Supplier<ReflectiveType>> lazyMethodSignature = getLazyMethodSignature(signatureExpression);
|
||||
if (lazyMethodSignature == null) return true;
|
||||
|
||||
if (!isConstructor && lazyMethodSignature.size() != 0) {
|
||||
final ReflectiveType returnType = lazyMethodSignature.get(0).get();
|
||||
checkReturnType(invokeCall, returnType, isExact, holder);
|
||||
}
|
||||
|
||||
final PsiExpressionList argumentList = invokeCall.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
final JavaReflectionInvocationInspection.Arguments actualArguments =
|
||||
JavaReflectionInvocationInspection.getActualMethodArguments(arguments, argumentOffset, false);
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void checkArgumentType(@NotNull PsiExpression argument,
|
||||
@Nullable ReflectiveType requiredType,
|
||||
@NotNull PsiExpressionList argumentList,
|
||||
boolean isExact,
|
||||
@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,
|
||||
InspectionsBundle.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,
|
||||
InspectionsBundle.message("inspection.reflect.handle.invocation.primitive.argument.null",
|
||||
requiredType.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void checkReturnType(@NotNull PsiMethodCallExpression invokeCall,
|
||||
@Nullable ReflectiveType requiredType,
|
||||
boolean isExact,
|
||||
@NotNull ProblemsHolder holder) {
|
||||
if (requiredType == null) return;
|
||||
final PsiElement invokeParent = invokeCall.getParent();
|
||||
PsiType actualType = null;
|
||||
PsiElement problemElement = null;
|
||||
if (invokeParent instanceof PsiTypeCastExpression) {
|
||||
final PsiTypeElement castTypeElement = ((PsiTypeCastExpression)invokeParent).getCastType();
|
||||
if (castTypeElement != null) {
|
||||
actualType = castTypeElement.getType();
|
||||
problemElement = castTypeElement;
|
||||
}
|
||||
}
|
||||
else if (invokeParent instanceof PsiAssignmentExpression) {
|
||||
actualType = ((PsiAssignmentExpression)invokeParent).getLExpression().getType();
|
||||
}
|
||||
else if (invokeParent instanceof PsiVariable) {
|
||||
actualType = ((PsiVariable)invokeParent).getType();
|
||||
}
|
||||
|
||||
if (actualType != null && !isCompatible(requiredType, actualType, isExact)) {
|
||||
if (problemElement == null) {
|
||||
problemElement = invokeCall.getMethodExpression();
|
||||
}
|
||||
holder.registerProblem(problemElement, InspectionsBundle.message(isExact || requiredType.isPrimitive()
|
||||
? "inspection.reflect.handle.invocation.result.not.exact"
|
||||
: "inspection.reflect.handle.invocation.result.not.assignable",
|
||||
requiredType.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<Supplier<ReflectiveType>> getLazyMethodSignature(@Nullable PsiExpression methodTypeExpression) {
|
||||
final PsiExpression typeDefinition = findDefinition(methodTypeExpression);
|
||||
if (typeDefinition instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression typeDefinitionCall = (PsiMethodCallExpression)typeDefinition;
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
else if (isCallToMethod(typeDefinitionCall, JAVA_LANG_INVOKE_METHOD_TYPE, GENERIC_METHOD_TYPE)) {
|
||||
final PsiExpression[] arguments = typeDefinitionCall.getArgumentList().getExpressions();
|
||||
final Pair.NonNull<Integer, Boolean> signature = JavaLangInvokeHandleSignatureInspection.getGenericSignature(arguments);
|
||||
if (signature != null) {
|
||||
final int objectArgCount = signature.getFirst();
|
||||
final boolean finalArray = signature.getSecond();
|
||||
if (objectArgCount == 0 && !finalArray) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(methodTypeExpression.getProject());
|
||||
final PsiClass objectClass = facade.findClass(CommonClassNames.JAVA_LANG_OBJECT, methodTypeExpression.getResolveScope());
|
||||
if (objectClass != null) {
|
||||
final List<ReflectiveType> argumentTypes = new ArrayList<>();
|
||||
final ReflectiveType objectType = ReflectiveType.create(objectClass);
|
||||
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;
|
||||
}
|
||||
|
||||
private static boolean checkGetter(@NotNull PsiMethodCallExpression invokeCall,
|
||||
@NotNull PsiExpression typeExpression,
|
||||
boolean isExact,
|
||||
int argumentOffset, ProblemsHolder holder) {
|
||||
final PsiExpressionList argumentList = invokeCall.getArgumentList();
|
||||
if (!checkArgumentCount(argumentList.getExpressions(), argumentOffset, 0, argumentList, holder)) return false;
|
||||
|
||||
final ReflectiveType resultType = getReflectiveType(typeExpression);
|
||||
if (resultType != null) {
|
||||
checkReturnType(invokeCall, resultType, isExact, holder);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean checkSetter(@NotNull PsiMethodCallExpression invokeCall,
|
||||
@NotNull PsiExpression typeExpression,
|
||||
boolean isExact,
|
||||
int argumentOffset, ProblemsHolder holder) {
|
||||
final PsiExpressionList argumentList = invokeCall.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
if (!checkArgumentCount(arguments, argumentOffset + 1, 0, argumentList, holder)) return false;
|
||||
|
||||
LOG.assertTrue(arguments.length == argumentOffset + 1);
|
||||
final ReflectiveType requiredType = getReflectiveType(typeExpression);
|
||||
checkArgumentType(arguments[argumentOffset], requiredType, argumentList, isExact, holder);
|
||||
|
||||
final PsiElement invokeParent = invokeCall.getParent();
|
||||
if (!(invokeParent instanceof PsiStatement)) {
|
||||
holder.registerProblem(invokeCall.getMethodExpression(),
|
||||
InspectionsBundle.message(isExact
|
||||
? "inspection.reflect.handle.invocation.result.void"
|
||||
: "inspection.reflect.handle.invocation.result.null"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean checkArgumentCount(@NotNull PsiExpression[] arguments,
|
||||
int requiredArgumentCount,
|
||||
int argumentOffset,
|
||||
@NotNull PsiElement problemElement,
|
||||
@NotNull ProblemsHolder holder) {
|
||||
if (requiredArgumentCount < 0) return false;
|
||||
if (arguments.length != requiredArgumentCount) {
|
||||
holder.registerProblem(problemElement, InspectionsBundle.message(
|
||||
"inspection.reflection.invocation.argument.count", requiredArgumentCount + argumentOffset));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isCompatible(@NotNull ReflectiveType requiredType, @NotNull PsiType actualType, boolean isExact) {
|
||||
if (isExact) {
|
||||
return requiredType.isEqualTo(actualType);
|
||||
}
|
||||
return requiredType.isAssignableFrom(actualType) || actualType.isAssignableFrom(requiredType.getType());
|
||||
}
|
||||
|
||||
|
||||
private static boolean isCompatible(@NotNull PsiType expectedType, @Nullable PsiType actualType) {
|
||||
return actualType != null && (expectedType.isAssignableFrom(actualType) || actualType.isAssignableFrom(expectedType));
|
||||
}
|
||||
|
||||
private static boolean isWithDynamicArguments(@NotNull PsiMethodCallExpression invokeCall) {
|
||||
if (INVOKE_WITH_ARGUMENTS.equals(invokeCall.getMethodExpression().getReferenceName())) {
|
||||
final PsiExpression[] arguments = invokeCall.getArgumentList().getExpressions();
|
||||
if (arguments.length == 1) {
|
||||
return JavaReflectionInvocationInspection.isVarargAsArray(arguments[0]) ||
|
||||
InheritanceUtil.isInheritor(arguments[0].getType(), JAVA_UTIL_LIST);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.reflectiveAccess;
|
||||
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.ObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.intellij.codeInspection.reflectiveAccess.JavaLangReflectHandleInvocationInspection.*;
|
||||
import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceUtil.*;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public 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";
|
||||
|
||||
private static final String GET = "get";
|
||||
private static final String GET_VOLATILE = "getVolatile";
|
||||
private static final String GET_OPAQUE = "getOpaque";
|
||||
private static final String GET_ACQUIRE = "getAcquire";
|
||||
|
||||
private static final String SET = "set";
|
||||
private static final String SET_VOLATILE = "setVolatile";
|
||||
private static final String SET_OPAQUE = "setOpaque";
|
||||
private static final String SET_RELEASE = "setRelease";
|
||||
|
||||
private static final String GET_AND_SET = "getAndSet";
|
||||
private static final String GET_AND_SET_ACQUIRE = "getAndSetAcquire";
|
||||
private static final String GET_AND_SET_RELEASE = "getAndSetRelease";
|
||||
|
||||
private static final String GET_AND_ADD = "getAndAdd";
|
||||
private static final String GET_AND_ADD_ACQUIRE = "getAndAddAcquire";
|
||||
private static final String GET_AND_ADD_RELEASE = "getAndAddRelease";
|
||||
|
||||
private static final String GET_AND_BITWISE_OR = "getAndBitwiseOr";
|
||||
private static final String GET_AND_BITWISE_OR_ACQUIRE = "getAndBitwiseOrAcquire";
|
||||
private static final String GET_AND_BITWISE_OR_RELEASE = "getAndBitwiseOrRelease";
|
||||
|
||||
private static final String GET_AND_BITWISE_AND = "getAndBitwiseAnd";
|
||||
private static final String GET_AND_BITWISE_AND_ACQUIRE = "getAndBitwiseAndAcquire";
|
||||
private static final String GET_AND_BITWISE_AND_RELEASE = "getAndBitwiseAndRelease";
|
||||
|
||||
private static final String GET_AND_BITWISE_XOR = "getAndBitwiseXor";
|
||||
private static final String GET_AND_BITWISE_XOR_ACQUIRE = "getAndBitwiseXorAcquire";
|
||||
private static final String GET_AND_BITWISE_XOR_RELEASE = "getAndBitwiseXorRelease";
|
||||
|
||||
private static final String COMPARE_AND_SET = "compareAndSet";
|
||||
private static final String COMPARE_AND_EXCHANGE = "compareAndExchange";
|
||||
private static final String COMPARE_AND_EXCHANGE_ACQUIRE = "compareAndExchangeAcquire";
|
||||
private static final String COMPARE_AND_EXCHANGE_RELEASE = "compareAndExchangeRelease";
|
||||
|
||||
private static final String WEAK_COMPARE_AND_SET = "weakCompareAndSet";
|
||||
private static final String WEAK_COMPARE_AND_SET_ACQUIRE = "weakCompareAndSetAcquire";
|
||||
private static final String WEAK_COMPARE_AND_SET_PLAIN = "weakCompareAndSetPlain";
|
||||
private static final String WEAK_COMPARE_AND_SET_RELEASE = "weakCompareAndSetRelease";
|
||||
|
||||
private static final ObjectIntHashMap<String> VAR_HANDLE_ARGUMENT_COUNTS = new ObjectIntHashMap<>();
|
||||
|
||||
static {
|
||||
for (String name : Arrays.asList(GET, GET_VOLATILE, GET_OPAQUE, GET_ACQUIRE)) {
|
||||
VAR_HANDLE_ARGUMENT_COUNTS.put(name, 0);
|
||||
}
|
||||
for (String name : Arrays.asList(SET, SET_VOLATILE, SET_OPAQUE, SET_RELEASE,
|
||||
GET_AND_SET, GET_AND_SET_ACQUIRE, GET_AND_SET_RELEASE,
|
||||
GET_AND_ADD, GET_AND_ADD_ACQUIRE, GET_AND_ADD_RELEASE,
|
||||
GET_AND_BITWISE_OR, GET_AND_BITWISE_OR_ACQUIRE, GET_AND_BITWISE_OR_RELEASE,
|
||||
GET_AND_BITWISE_AND, GET_AND_BITWISE_AND_ACQUIRE, GET_AND_BITWISE_AND_RELEASE,
|
||||
GET_AND_BITWISE_XOR, GET_AND_BITWISE_XOR_ACQUIRE, GET_AND_BITWISE_XOR_RELEASE)) {
|
||||
VAR_HANDLE_ARGUMENT_COUNTS.put(name, 1);
|
||||
}
|
||||
for (String name : Arrays.asList(COMPARE_AND_SET, COMPARE_AND_EXCHANGE, COMPARE_AND_EXCHANGE_ACQUIRE, COMPARE_AND_EXCHANGE_RELEASE,
|
||||
WEAK_COMPARE_AND_SET, WEAK_COMPARE_AND_SET_ACQUIRE, WEAK_COMPARE_AND_SET_PLAIN,
|
||||
WEAK_COMPARE_AND_SET_RELEASE)) {
|
||||
VAR_HANDLE_ARGUMENT_COUNTS.put(name, 2);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Set<String> WITH_RETURN_VALUE_NAMES =
|
||||
ContainerUtil.set(GET, GET_VOLATILE, GET_OPAQUE, GET_ACQUIRE,
|
||||
GET_AND_SET, GET_AND_SET_ACQUIRE, GET_AND_SET_RELEASE,
|
||||
GET_AND_ADD, GET_AND_ADD_ACQUIRE, GET_AND_ADD_RELEASE,
|
||||
GET_AND_BITWISE_OR, GET_AND_BITWISE_OR_ACQUIRE, GET_AND_BITWISE_OR_RELEASE,
|
||||
GET_AND_BITWISE_AND, GET_AND_BITWISE_AND_ACQUIRE, GET_AND_BITWISE_AND_RELEASE,
|
||||
GET_AND_BITWISE_XOR, GET_AND_BITWISE_XOR_ACQUIRE, GET_AND_BITWISE_XOR_RELEASE,
|
||||
COMPARE_AND_EXCHANGE, COMPARE_AND_EXCHANGE_ACQUIRE, COMPARE_AND_EXCHANGE_RELEASE);
|
||||
|
||||
|
||||
static void checkVarHandleAccess(PsiMethodCallExpression methodCall, @NotNull ProblemsHolder holder) {
|
||||
if (isVarHandleAccessMethod(methodCall)) {
|
||||
final PsiExpression qualifierDefinition = findDefinition(methodCall.getMethodExpression().getQualifierExpression());
|
||||
if (qualifierDefinition instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression handleFactoryCall = (PsiMethodCallExpression)qualifierDefinition;
|
||||
final PsiExpression[] factoryArguments = handleFactoryCall.getArgumentList().getExpressions();
|
||||
|
||||
if (isCallToMethod(handleFactoryCall, JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, FIND_VAR_HANDLE)) {
|
||||
if (factoryArguments.length == 3) {
|
||||
checkCallReceiver(methodCall, getReflectiveType(factoryArguments[0]), holder);
|
||||
|
||||
checkVarHandleAccessSignature(methodCall, getReflectiveType(factoryArguments[2]), 1, holder);
|
||||
}
|
||||
}
|
||||
else if (isCallToMethod(handleFactoryCall, JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, FIND_STATIC_VAR_HANDLE)) {
|
||||
if (factoryArguments.length == 3) {
|
||||
checkVarHandleAccessSignature(methodCall, getReflectiveType(factoryArguments[2]), 0, holder);
|
||||
}
|
||||
}
|
||||
else if (isCallToMethod(handleFactoryCall, JAVA_LANG_INVOKE_METHOD_HANDLES, ARRAY_ELEMENT_VAR_HANDLE)) {
|
||||
if (factoryArguments.length == 1) {
|
||||
final ReflectiveType arrayType = getReflectiveType(factoryArguments[0]);
|
||||
if (arrayType != null) {
|
||||
checkCallReceiver(methodCall, arrayType, holder);
|
||||
|
||||
final PsiType rawArrayType = arrayType.getType();
|
||||
if (rawArrayType instanceof PsiArrayType) {
|
||||
final ReflectiveType valueType = ReflectiveType.create(((PsiArrayType)rawArrayType).getComponentType());
|
||||
checkVarHandleAccessSignature(methodCall, valueType, 2, holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkVarHandleAccessSignature(@NotNull PsiMethodCallExpression accessCall,
|
||||
@Nullable ReflectiveType valueType,
|
||||
int coordinateArguments,
|
||||
@NotNull ProblemsHolder holder) {
|
||||
if (valueType == null) return;
|
||||
|
||||
if (isWithReturnValue(accessCall)) {
|
||||
checkReturnType(accessCall, valueType, false, holder);
|
||||
}
|
||||
|
||||
final PsiExpressionList accessArgumentList = accessCall.getArgumentList();
|
||||
final PsiExpression[] accessArguments = accessArgumentList.getExpressions();
|
||||
|
||||
final int requiredArgumentCount = getVarHandleArgumentCount(accessCall, coordinateArguments);
|
||||
if (!checkArgumentCount(accessArguments, requiredArgumentCount, 0, accessArgumentList, holder)) return;
|
||||
|
||||
LOG.assertTrue(accessArguments.length == requiredArgumentCount);
|
||||
for (int i = coordinateArguments; i < requiredArgumentCount; i++) {
|
||||
checkArgumentType(accessArguments[i], valueType, accessArgumentList, false, holder);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isVarHandleAccessMethod(PsiMethodCallExpression methodCall) {
|
||||
final String methodName = methodCall.getMethodExpression().getReferenceName();
|
||||
if (VAR_HANDLE_ARGUMENT_COUNTS.containsKey(methodName)) {
|
||||
final PsiMethod method = methodCall.resolveMethod();
|
||||
return method != null && isClassWithName(method.getContainingClass(), JAVA_LANG_INVOKE_VAR_HANDLE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int getVarHandleArgumentCount(@NotNull PsiMethodCallExpression accessCall, int coordinateArguments) {
|
||||
final String name = accessCall.getMethodExpression().getReferenceName();
|
||||
final int count = VAR_HANDLE_ARGUMENT_COUNTS.get(name);
|
||||
return count >= 0 ? count + coordinateArguments : -1;
|
||||
}
|
||||
|
||||
private static boolean isWithReturnValue(@NotNull PsiMethodCallExpression accessCall) {
|
||||
final String name = accessCall.getMethodExpression().getReferenceName();
|
||||
return WITH_RETURN_VALUE_NAMES.contains(name);
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
|
||||
public class ArrayVarHandle {
|
||||
void array() {
|
||||
VarHandle handle = MethodHandles.arrayElementVarHandle(Test[].class);
|
||||
Test[] array = new Test[]{new Test(), new Test(), new SubTest()};
|
||||
Test instance = new Test();
|
||||
|
||||
Test exactGet = (Test)handle.get(array, 0);
|
||||
Super superGet = (Super) handle.get(array, 1);
|
||||
Object objectGet = handle.get(array, 2);
|
||||
|
||||
Object missingIndexGet = handle.get<warning descr="2 arguments are expected">(array)</warning>;
|
||||
Object incompatibleReceiverGet = handle.get(<warning descr="Call receiver type is incompatible: 'Test[]' is expected">instance</warning>, 1);
|
||||
Object incompatibleIndexGet = handle.get(array, "abc");
|
||||
String incompatibleResultGet = (<warning descr="Should be cast to 'Test' or its superclass">String</warning>)handle.get(<warning descr="Call receiver type is incompatible: 'Test[]' is expected">instance</warning>, 1);
|
||||
|
||||
handle.set(array, 0, instance);
|
||||
handle.set(array, 1, new SubTest());
|
||||
Super superItemSet = new Test();
|
||||
handle.set(array, 1, superItemSet);
|
||||
Object objectItemSet = new Test();
|
||||
handle.set(array, 2, objectItemSet);
|
||||
|
||||
handle.set(array, instance, <warning descr="Argument is not assignable to 'Test'">0</warning>);
|
||||
handle.set<warning descr="3 arguments are expected">(array, instance)</warning>;
|
||||
handle.set(<warning descr="Call receiver type is incompatible: 'Test[]' is expected">instance</warning>, array, <warning descr="Argument is not assignable to 'Test'">0</warning>);
|
||||
handle.set<warning descr="3 arguments are expected">(array, 0)</warning>;
|
||||
handle.set(array, 0, <warning descr="Argument is not assignable to 'Test'">"abc"</warning>);
|
||||
handle.set<warning descr="3 arguments are expected">(<warning descr="Call receiver type is incompatible: 'Test[]' is expected">"abc"</warning>)</warning>;
|
||||
|
||||
Test exactGAS = (Test)handle.getAndSet(array, 0, instance);
|
||||
SubTest subGAS = (SubTest)handle.getAndSet(array, 1, instance);
|
||||
Super superGAS = (Super)handle.getAndSet(array, 2, instance);
|
||||
Object objectGAS = handle.getAndSet(array, 0, instance);
|
||||
|
||||
Object tooManyArgumentsGAS = handle.getAndSet<warning descr="3 arguments are expected">(array, 0, instance, 1)</warning>;
|
||||
Object wrongArgumentGAS = handle.getAndSet(array, instance, <warning descr="Argument is not assignable to 'Test'">0</warning>);
|
||||
Test tooFewArgumentsGAS = (Test)handle.getAndSet<warning descr="3 arguments are expected">(array, instance)</warning>;
|
||||
|
||||
boolean exactCAS = handle.compareAndSet(array, 0, instance, new Test());
|
||||
boolean subCAS = handle.compareAndSet(array, 0, new SubTest(), instance);
|
||||
|
||||
boolean tooManyArgumentsCAS = handle.compareAndSet<warning descr="4 arguments are expected">(array, 0, instance, new Test(), new Test())</warning>;
|
||||
boolean wrongArgumentCAS = handle.compareAndSet(array, instance, new Test(), <warning descr="Argument is not assignable to 'Test'">2</warning>);
|
||||
boolean tooFewArgumentsCAS = handle.compareAndSet<warning descr="4 arguments are expected">(array, 0, instance)</warning>;
|
||||
|
||||
Test exactCAE = (Test)handle.compareAndExchange(array, 0, instance, new Test());
|
||||
Super superCAE = (Super)handle.compareAndExchange(array, 0, new SubTest(), instance);
|
||||
|
||||
Test tooManyArgumentsCAE = (Test)handle.compareAndExchange<warning descr="4 arguments are expected">(array, 0, instance, new Test(), new Test())</warning>;
|
||||
Test wrongArgumentCAE = (Test)handle.compareAndExchange(array, instance, new Test(), <warning descr="Argument is not assignable to 'Test'">2</warning>);
|
||||
Test tooFewArgumentsCAE = (Test)handle.compareAndExchange<warning descr="4 arguments are expected">(array, 0, instance)</warning>;
|
||||
}
|
||||
|
||||
void array2() {
|
||||
VarHandle handle = MethodHandles.arrayElementVarHandle(Test[][].class);
|
||||
Test[] array0 = new Test[1];
|
||||
Test[][] array = new Test[][]{new Test[1]};
|
||||
Test instance = new Test();
|
||||
|
||||
Test[] exactGet = (Test[])handle.get(array, 0);
|
||||
Object incompatibleReceiverGet = handle.get(<warning descr="Call receiver type is incompatible: 'Test[][]' is expected">array0</warning>, 1);
|
||||
Test incompatibleResultGet = (<warning descr="Should be cast to 'Test[]' or its superclass">Test</warning>)handle.get(array, 1);
|
||||
|
||||
handle.set(array, 0, array0);
|
||||
handle.set(array, 0, <warning descr="Argument is not assignable to 'Test[]'">instance</warning>);
|
||||
|
||||
Test[] exactGAS = (Test[])handle.getAndSet(array, 0, array0);
|
||||
Object wrongArgumentGAS = handle.getAndSet(array, 0, <warning descr="Argument is not assignable to 'Test[]'">instance</warning>);
|
||||
|
||||
boolean exactCAS = handle.compareAndSet(array, 0, array0, new Test[0]);
|
||||
boolean wrongArgumentCAS = handle.compareAndSet(array, 0, array0, <warning descr="Argument is not assignable to 'Test[]'">instance</warning>);
|
||||
|
||||
Object exactCAE = (Object)handle.compareAndExchange(array, 0, new Test[0], array0);
|
||||
Test[] wrongArgumentCAE = (Test[])handle.compareAndExchange(array, 0, <warning descr="Argument is not assignable to 'Test[]'">instance</warning>, array0);
|
||||
Test wrongResultCAE = (<warning descr="Should be cast to 'Test[]' or its superclass">Test</warning>)handle.compareAndExchange(array, 0, array0, new Test[0]);
|
||||
}
|
||||
}
|
||||
|
||||
class Super {}
|
||||
|
||||
class Test extends Super {}
|
||||
|
||||
class SubTest extends Test {}
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
|
||||
class Main {
|
||||
void getInt() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
VarHandle handle = lookup.findStaticVarHandle(Test.class, "n", int.class);
|
||||
Test instance = new Test();
|
||||
|
||||
int exact = (int) handle.get();
|
||||
Integer boxed = (Integer) handle.get();
|
||||
Object object = (Object) handle.get();
|
||||
String incompatible = (<warning descr="Should be cast to 'int'">String</warning>) handle.get();
|
||||
handle.get<warning descr="No arguments are expected">(instance)</warning>;
|
||||
|
||||
int exactV = (int) handle.getVolatile();
|
||||
Integer boxedV = (Integer) handle.getVolatile();
|
||||
Object objectV = (Object) handle.getVolatile();
|
||||
String incompatibleV = (<warning descr="Should be cast to 'int'">String</warning>) handle.getVolatile();
|
||||
handle.getVolatile<warning descr="No arguments are expected">(instance)</warning>;
|
||||
|
||||
int exactO = (int) handle.getOpaque();
|
||||
Integer boxedO = (Integer) handle.getOpaque();
|
||||
Object objectO = (Object) handle.getOpaque();
|
||||
String incompatibleO = (<warning descr="Should be cast to 'int'">String</warning>) handle.getOpaque();
|
||||
handle.getOpaque<warning descr="No arguments are expected">(instance)</warning>;
|
||||
|
||||
int exactA = (int) handle.getAcquire();
|
||||
Integer boxedA = (Integer) handle.getAcquire();
|
||||
Object objectA = (Object) handle.getAcquire();
|
||||
String incompatibleA = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAcquire();
|
||||
handle.getAcquire<warning descr="No arguments are expected">(instance)</warning>;
|
||||
}
|
||||
|
||||
void setInt() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
VarHandle handle = lookup.findStaticVarHandle(Test.class, "n", int.class);
|
||||
Test instance = new Test();
|
||||
Object nullArg = null;
|
||||
Object textArg = "abc";
|
||||
Object numberArg = 123;
|
||||
|
||||
handle.set(1);
|
||||
handle.set(Integer.valueOf(2));
|
||||
handle.set(numberArg);
|
||||
handle.set(textArg);
|
||||
handle.set<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.set(<warning descr="Argument of type 'int' cannot be 'null'">nullArg</warning>);
|
||||
handle.set<warning descr="One argument is expected">()</warning>;
|
||||
|
||||
handle.setVolatile(1);
|
||||
handle.setVolatile(Integer.valueOf(2));
|
||||
handle.setVolatile(numberArg);
|
||||
handle.setVolatile(textArg);
|
||||
handle.setVolatile<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.setVolatile(<warning descr="Argument of type 'int' cannot be 'null'">nullArg</warning>);
|
||||
handle.setVolatile<warning descr="One argument is expected">()</warning>;
|
||||
|
||||
handle.setOpaque(1);
|
||||
handle.setOpaque(Integer.valueOf(2));
|
||||
handle.setOpaque(numberArg);
|
||||
handle.setOpaque(textArg);
|
||||
handle.setOpaque<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.setOpaque(<warning descr="Argument of type 'int' cannot be 'null'">nullArg</warning>);
|
||||
handle.setOpaque<warning descr="One argument is expected">()</warning>;
|
||||
|
||||
handle.setRelease(1);
|
||||
handle.setRelease(Integer.valueOf(2));
|
||||
handle.setRelease(numberArg);
|
||||
handle.setRelease(textArg);
|
||||
handle.setRelease<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.setRelease(<warning descr="Argument of type 'int' cannot be 'null'">nullArg</warning>);
|
||||
handle.setRelease<warning descr="One argument is expected">()</warning>;
|
||||
}
|
||||
|
||||
void getStr() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findStaticVarHandle(Test.class, "s", String.class);
|
||||
final Test instance = new Test();
|
||||
|
||||
String exact = (String) handle.get();
|
||||
CharSequence parent = (CharSequence) handle.get();
|
||||
Object object = (Object) handle.get();
|
||||
Integer incompatible = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.get();
|
||||
handle.get<warning descr="No arguments are expected">(instance)</warning>;
|
||||
|
||||
String exactV = (String) handle.getVolatile();
|
||||
CharSequence parentV = (CharSequence) handle.getVolatile();
|
||||
Object objectV = (Object) handle.getVolatile();
|
||||
Integer incompatibleV = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getVolatile();
|
||||
handle.getVolatile<warning descr="No arguments are expected">(instance)</warning>;
|
||||
|
||||
String exactO = (String) handle.getOpaque();
|
||||
CharSequence parentO = (CharSequence) handle.getOpaque();
|
||||
Object objectO = (Object) handle.getOpaque();
|
||||
Integer incompatibleO = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getOpaque();
|
||||
handle.getOpaque<warning descr="No arguments are expected">(instance)</warning>;
|
||||
|
||||
String exactA = (String) handle.getAcquire();
|
||||
CharSequence parentA = (CharSequence) handle.getAcquire();
|
||||
Object objectA = (Object) handle.getAcquire();
|
||||
Integer incompatibleA = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getAcquire();
|
||||
handle.getAcquire<warning descr="No arguments are expected">(instance)</warning>;
|
||||
}
|
||||
|
||||
void setStr() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findStaticVarHandle(Test.class, "s", String.class);
|
||||
final Test instance = new Test();
|
||||
final Object nullArg = null;
|
||||
final Object textArg = "abc";
|
||||
final Object numberArg = 3;
|
||||
|
||||
handle.set("a");
|
||||
handle.set(charSequence());
|
||||
handle.set(textArg);
|
||||
handle.set(nullArg);
|
||||
handle.set(numberArg);
|
||||
handle.set<warning descr="One argument is expected">(instance, "abc")</warning>;
|
||||
handle.set<warning descr="One argument is expected">()</warning>;
|
||||
|
||||
handle.setVolatile("a");
|
||||
handle.setVolatile(charSequence());
|
||||
handle.setVolatile(textArg);
|
||||
handle.setVolatile(nullArg);
|
||||
handle.setVolatile(numberArg);
|
||||
handle.setVolatile<warning descr="One argument is expected">(instance, "abc")</warning>;
|
||||
handle.setVolatile<warning descr="One argument is expected">()</warning>;
|
||||
|
||||
handle.setOpaque("a");
|
||||
handle.setOpaque(charSequence());
|
||||
handle.setOpaque(textArg);
|
||||
handle.setOpaque(nullArg);
|
||||
handle.setOpaque(numberArg);
|
||||
handle.setOpaque<warning descr="One argument is expected">(instance, "abc")</warning>;
|
||||
handle.setOpaque<warning descr="One argument is expected">()</warning>;
|
||||
|
||||
handle.setRelease("a");
|
||||
handle.setRelease(charSequence());
|
||||
handle.setRelease(textArg);
|
||||
handle.setRelease(nullArg);
|
||||
handle.setRelease(numberArg);
|
||||
handle.setRelease<warning descr="One argument is expected">(instance, "abc")</warning>;
|
||||
handle.setRelease<warning descr="One argument is expected">()</warning>;
|
||||
}
|
||||
|
||||
|
||||
private void getAndAddInt() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
VarHandle handle = lookup.findStaticVarHandle(Test.class, "n", int.class);
|
||||
Test instance = new Test();
|
||||
Object nullArg = null;
|
||||
|
||||
int exact = (int) handle.getAndAdd(1);
|
||||
Integer boxed = (Integer) handle.getAndAdd(2);
|
||||
Object object = (Object) handle.getAndAdd(3);
|
||||
handle.getAndAdd(4);
|
||||
String incompatible = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndAdd(0);
|
||||
int incompatibleArg = (int) handle.getAndSet(<warning descr="Argument is not assignable to 'int'">"abc"</warning>);
|
||||
handle.getAndAdd<warning descr="One argument is expected">(1, 2)</warning>;
|
||||
handle.getAndAdd<warning descr="One argument is expected">()</warning>;
|
||||
|
||||
int exactA = (int) handle.getAndAddAcquire(1); ;
|
||||
Integer boxedA = (Integer) handle.getAndAddAcquire(2);
|
||||
Object objectA = (Object) handle.getAndAddAcquire(3);
|
||||
handle.getAndAddAcquire(4);
|
||||
String incompatibleA = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndAddAcquire<warning descr="One argument is expected">(instance, 0)</warning>;
|
||||
int incompatibleArgA = (int) handle.getAndSetAcquire(<warning descr="Argument is not assignable to 'int'">"abc"</warning>);
|
||||
handle.getAndAddAcquire<warning descr="One argument is expected">(1, 2)</warning>;
|
||||
handle.getAndAddAcquire<warning descr="One argument is expected">()</warning>;
|
||||
|
||||
int exactR = (int) handle.getAndAddRelease(1); ;
|
||||
Integer boxedR = (Integer) handle.getAndAddRelease(2);
|
||||
Object objectR = (Object) handle.getAndAddRelease(3);
|
||||
handle.getAndAddRelease(4);
|
||||
String incompatibleR = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndAdd(0);
|
||||
int incompatibleArgR = (int) handle.getAndSetRelease(<warning descr="Argument is not assignable to 'int'">"abc"</warning>);
|
||||
handle.getAndAddRelease<warning descr="One argument is expected">(1, 2)</warning>;
|
||||
handle.getAndAddRelease<warning descr="One argument is expected">()</warning>;
|
||||
}
|
||||
|
||||
private void getAndSetStr() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findStaticVarHandle(Test.class, "s", String.class);
|
||||
final Test instance = new Test();
|
||||
final Object nullArg = null;
|
||||
|
||||
String exact = (String) handle.getAndSet("a");
|
||||
CharSequence parent = (CharSequence) handle.getAndSet("b");
|
||||
Object object = (Object) handle.getAndSet("c");
|
||||
String subclassArg = (String) handle.getAndSet(charSequence());
|
||||
String withNullArg = (String) handle.getAndSet(nullArg);
|
||||
handle.getAndSet("d");
|
||||
Integer incompatible = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getAndSet("e");
|
||||
String incompatibleArg = (String) handle.getAndSet(<warning descr="Argument is not assignable to 'java.lang.String'">123</warning>);
|
||||
handle.getAndSet<warning descr="One argument is expected">("a", "b")</warning>;
|
||||
handle.getAndSet<warning descr="One argument is expected">()</warning>;
|
||||
|
||||
String exactA = (String) handle.getAndSetAcquire("a");
|
||||
CharSequence parentA = (CharSequence) handle.getAndSetAcquire("b");
|
||||
Object objectA = (Object) handle.getAndSetAcquire("c");;
|
||||
String subclassArgA = (String) handle.getAndSetAcquire(charSequence());
|
||||
String withNullArgA = (String) handle.getAndSetAcquire(nullArg);
|
||||
handle.getAndSetAcquire("d");
|
||||
Integer incompatibleA = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getAndSetAcquire("e");
|
||||
String incompatibleArgA = (String) handle.getAndSetAcquire(<warning descr="Argument is not assignable to 'java.lang.String'">123</warning>);
|
||||
handle.getAndSetAcquire<warning descr="One argument is expected">("a", "b")</warning>;
|
||||
handle.getAndSetAcquire<warning descr="One argument is expected">()</warning>;
|
||||
|
||||
String exactR = (String) handle.getAndSetRelease("a");
|
||||
CharSequence parentR = (CharSequence) handle.getAndSetRelease("b");
|
||||
Object objectR = (Object) handle.getAndSetRelease("c");;
|
||||
String subclassArgR = (String) handle.getAndSetRelease(charSequence());
|
||||
String withNullArgR = (String) handle.getAndSetRelease(nullArg);
|
||||
handle.getAndSetRelease("d");
|
||||
Integer incompatibleR = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getAndSetRelease("e");
|
||||
String incompatibleArgR = (String) handle.getAndSetRelease(<warning descr="Argument is not assignable to 'java.lang.String'">123</warning>);
|
||||
handle.getAndSetRelease<warning descr="One argument is expected">("a", "b")</warning>;
|
||||
handle.getAndSetRelease<warning descr="One argument is expected">()</warning>;
|
||||
}
|
||||
|
||||
void getAndBitwise() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
VarHandle handle = lookup.findStaticVarHandle(Test.class, "n", int.class);
|
||||
Test instance = new Test();
|
||||
|
||||
int exactBitwiseAnd = (int) handle.getAndBitwiseAnd(1);
|
||||
int exactBitwiseAndA = (int) handle.getAndBitwiseAndAcquire(2);
|
||||
int exactBitwiseAndR = (int) handle.getAndBitwiseAndRelease(3);
|
||||
|
||||
int wrongArgBitwiseAnd = (int) handle.getAndBitwiseAnd(<warning descr="Argument is not assignable to 'int'">"a"</warning>);
|
||||
int wrongArgBitwiseAndA = (int) handle.getAndBitwiseAndAcquire(<warning descr="Argument is not assignable to 'int'">"b"</warning>);
|
||||
int wrongArgBitwiseAndR = (int) handle.getAndBitwiseAndRelease(<warning descr="Argument is not assignable to 'int'">"c"</warning>);
|
||||
|
||||
String wrongResultBitwiseAnd = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseAnd(1);
|
||||
String wrongResultBitwiseAndA = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseAndAcquire(2);
|
||||
String wrongResultBitwiseAndR = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseAndRelease(3);
|
||||
|
||||
int exactBitwiseOr = (int) handle.getAndBitwiseOr(1);
|
||||
int exactBitwiseOrA = (int) handle.getAndBitwiseOrAcquire(2);
|
||||
int exactBitwiseOrR = (int) handle.getAndBitwiseOrRelease(3);
|
||||
|
||||
int wrongArgBitwiseOr = (int) handle.getAndBitwiseOr(<warning descr="Argument is not assignable to 'int'">"a"</warning>);
|
||||
int wrongArgBitwiseOrA = (int) handle.getAndBitwiseOrAcquire(<warning descr="Argument is not assignable to 'int'">"b"</warning>);
|
||||
int wrongArgBitwiseOrR = (int) handle.getAndBitwiseOrRelease(<warning descr="Argument is not assignable to 'int'">"c"</warning>);
|
||||
|
||||
String wrongResultBitwiseOr = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseOr(1);
|
||||
String wrongResultBitwiseOrA = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseOrAcquire(2);
|
||||
String wrongResultBitwiseOrR = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseOrRelease(3);
|
||||
|
||||
int exactBitwiseXor = (int) handle.getAndBitwiseXor(1);
|
||||
int exactBitwiseXorA = (int) handle.getAndBitwiseXorAcquire(2);
|
||||
int exactBitwiseXorR = (int) handle.getAndBitwiseXorRelease(3);
|
||||
|
||||
int wrongArgBitwiseXor = (int) handle.getAndBitwiseXor(<warning descr="Argument is not assignable to 'int'">"a"</warning>);
|
||||
int wrongArgBitwiseXorA = (int) handle.getAndBitwiseXorAcquire(<warning descr="Argument is not assignable to 'int'">"b"</warning>);
|
||||
int wrongArgBitwiseXorR = (int) handle.getAndBitwiseXorRelease(<warning descr="Argument is not assignable to 'int'">"c"</warning>);
|
||||
|
||||
String wrongResultBitwiseXor = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseXor(1);
|
||||
String wrongResultBitwiseXorA = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseXorAcquire(2);
|
||||
String wrongResultBitwiseXorR = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseXorRelease(3);
|
||||
}
|
||||
|
||||
|
||||
void compare() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findStaticVarHandle(Test.class, "myS", String.class);
|
||||
final Test instance = new Test();
|
||||
|
||||
boolean exactCAS = handle.compareAndSet("a", "b");
|
||||
String exactCAE = (String)handle.compareAndExchange("a", "b");
|
||||
String exactCAEA = (String)handle.compareAndExchangeAcquire("a", "b");
|
||||
String exactCAER = (String)handle.compareAndExchangeRelease("a", "b");
|
||||
|
||||
boolean badArg1CAS = handle.compareAndSet(<warning descr="Argument is not assignable to 'java.lang.String'">1</warning>, "b");
|
||||
String badArg1CAE = (String)handle.compareAndExchange(<warning descr="Argument is not assignable to 'java.lang.String'">2</warning>, "b");
|
||||
String badArg1CAEa = (String)handle.compareAndExchangeAcquire(<warning descr="Argument is not assignable to 'java.lang.String'">3</warning>, "b");
|
||||
String badArg1CAEr = (String)handle.compareAndExchangeRelease(<warning descr="Argument is not assignable to 'java.lang.String'">4</warning>, "b");
|
||||
|
||||
boolean badArg2CAS = handle.compareAndSet("a", <warning descr="Argument is not assignable to 'java.lang.String'">1</warning>);
|
||||
String badArg2CAE = (String)handle.compareAndExchange("a", <warning descr="Argument is not assignable to 'java.lang.String'">2</warning>);
|
||||
String badArg2CAEa = (String)handle.compareAndExchangeAcquire("a", <warning descr="Argument is not assignable to 'java.lang.String'">3</warning>);
|
||||
String badArg2CAEr = (String)handle.compareAndExchangeRelease("a", <warning descr="Argument is not assignable to 'java.lang.String'">4</warning>);
|
||||
|
||||
Integer badResultCAE = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>)handle.compareAndExchange("a", "b");
|
||||
Integer badResultCAEa = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>)handle.compareAndExchangeAcquire("a", "b");
|
||||
Integer badResultCAEr = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>)handle.compareAndExchangeRelease("a", "b");
|
||||
}
|
||||
|
||||
void weakCompare() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findStaticVarHandle(Test.class, "myS", String.class);
|
||||
final Test instance = new Test();
|
||||
|
||||
boolean exactCAS = handle.weakCompareAndSet("a", "b");
|
||||
boolean exactCASp = handle.weakCompareAndSetPlain("a", "b");
|
||||
boolean exactCASa = handle.weakCompareAndSetAcquire("a", "b");
|
||||
boolean exactCASr = handle.weakCompareAndSetRelease("a", "b");
|
||||
|
||||
boolean badArg1CAS = handle.weakCompareAndSet(<warning descr="Argument is not assignable to 'java.lang.String'">1</warning>, "b");
|
||||
boolean badArg1CASp = handle.weakCompareAndSetPlain(<warning descr="Argument is not assignable to 'java.lang.String'">2</warning>, "b");
|
||||
boolean badArg1CASa = handle.weakCompareAndSetAcquire(<warning descr="Argument is not assignable to 'java.lang.String'">3</warning>, "b");
|
||||
boolean badArg1CASr = handle.weakCompareAndSetRelease(<warning descr="Argument is not assignable to 'java.lang.String'">4</warning>, "b");
|
||||
|
||||
boolean badArg2CAS = handle.weakCompareAndSet("a", <warning descr="Argument is not assignable to 'java.lang.String'">1</warning>);
|
||||
boolean badArg2CASp = handle.weakCompareAndSetPlain("a", <warning descr="Argument is not assignable to 'java.lang.String'">2</warning>);
|
||||
boolean badArg2CASa = handle.weakCompareAndSetAcquire("a", <warning descr="Argument is not assignable to 'java.lang.String'">3</warning>);
|
||||
boolean badArg2CASr = handle.weakCompareAndSetRelease("a", <warning descr="Argument is not assignable to 'java.lang.String'">4</warning>);
|
||||
}
|
||||
|
||||
private static CharSequence charSequence() { return "abc"; }
|
||||
}
|
||||
|
||||
class Test {
|
||||
public static int n;
|
||||
public static String s;
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
|
||||
class Main {
|
||||
void getInt() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
VarHandle handle = lookup.findVarHandle(Test.class, "n", int.class);
|
||||
Test instance = new Test();
|
||||
Object nullArg = null;
|
||||
|
||||
int exact = (int) handle.get(instance);
|
||||
Integer boxed = (Integer) handle.get(instance);
|
||||
Object object = (Object) handle.get(instance);
|
||||
String incompatible = (<warning descr="Should be cast to 'int'">String</warning>) handle.get(instance);
|
||||
handle.get<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.get<warning descr="One argument is expected">()</warning>;
|
||||
handle.get(<warning descr="Call receiver is 'null'">nullArg</warning>);
|
||||
handle.get(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>);
|
||||
|
||||
int exactV = (int) handle.getVolatile(instance);
|
||||
Integer boxedV = (Integer) handle.getVolatile(instance);
|
||||
Object objectV = (Object) handle.getVolatile(instance);
|
||||
String incompatibleV = (<warning descr="Should be cast to 'int'">String</warning>) handle.getVolatile(instance);
|
||||
handle.getVolatile<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.getVolatile<warning descr="One argument is expected">()</warning>;
|
||||
handle.getVolatile(<warning descr="Call receiver is 'null'">nullArg</warning>);
|
||||
handle.getVolatile(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>);
|
||||
|
||||
int exactO = (int) handle.getOpaque(instance);
|
||||
Integer boxedO = (Integer) handle.getOpaque(instance);
|
||||
Object objectO = (Object) handle.getOpaque(instance);
|
||||
String incompatibleO = (<warning descr="Should be cast to 'int'">String</warning>) handle.getOpaque(instance);
|
||||
handle.getOpaque<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.getOpaque<warning descr="One argument is expected">()</warning>;
|
||||
handle.getOpaque(<warning descr="Call receiver is 'null'">nullArg</warning>);
|
||||
handle.getOpaque(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>);
|
||||
|
||||
int exactA = (int) handle.getAcquire(instance);
|
||||
Integer boxedA = (Integer) handle.getAcquire(instance);
|
||||
Object objectA = (Object) handle.getAcquire(instance);
|
||||
String incompatibleA = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAcquire(instance);
|
||||
handle.getAcquire<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.getAcquire<warning descr="One argument is expected">()</warning>;
|
||||
handle.getAcquire(<warning descr="Call receiver is 'null'">nullArg</warning>);
|
||||
handle.getAcquire(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>);
|
||||
}
|
||||
|
||||
void setInt() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
VarHandle handle = lookup.findVarHandle(Test.class, "n", int.class);
|
||||
Test instance = new Test();
|
||||
Object nullArg = null;
|
||||
Object textArg = "abc";
|
||||
Object numberArg = 123;
|
||||
|
||||
handle.set(instance, 1);
|
||||
handle.set(instance, Integer.valueOf(2));
|
||||
handle.set(instance, numberArg);
|
||||
handle.set(instance, textArg);
|
||||
handle.set<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.set<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.set(<warning descr="Call receiver is 'null'">nullArg</warning>, 123);
|
||||
handle.set(instance, <warning descr="Argument of type 'int' cannot be 'null'">nullArg</warning>);
|
||||
handle.set(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>, 42);
|
||||
|
||||
handle.setVolatile(instance, 1);
|
||||
handle.setVolatile(instance, Integer.valueOf(2));
|
||||
handle.setVolatile(instance, numberArg);
|
||||
handle.setVolatile(instance, textArg);
|
||||
handle.setVolatile<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.setVolatile<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.setVolatile(<warning descr="Call receiver is 'null'">nullArg</warning>, 123);
|
||||
handle.setVolatile(instance, <warning descr="Argument of type 'int' cannot be 'null'">nullArg</warning>);
|
||||
handle.setVolatile(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>, 42);
|
||||
|
||||
handle.setOpaque(instance, 1);
|
||||
handle.setOpaque(instance, Integer.valueOf(2));
|
||||
handle.setOpaque(instance, numberArg);
|
||||
handle.setOpaque(instance, textArg);
|
||||
handle.setOpaque<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.setOpaque<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.setOpaque(<warning descr="Call receiver is 'null'">nullArg</warning>, 123);
|
||||
handle.setOpaque(instance, <warning descr="Argument of type 'int' cannot be 'null'">nullArg</warning>);
|
||||
handle.setOpaque(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>, 42);
|
||||
|
||||
handle.setRelease(instance, 1);
|
||||
handle.setRelease(instance, Integer.valueOf(2));
|
||||
handle.setRelease(instance, numberArg);
|
||||
handle.setRelease(instance, textArg);
|
||||
handle.setRelease<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.setRelease<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.setRelease(<warning descr="Call receiver is 'null'">nullArg</warning>, 123);
|
||||
handle.setRelease(instance, <warning descr="Argument of type 'int' cannot be 'null'">nullArg</warning>);
|
||||
handle.setRelease(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>, 42);
|
||||
}
|
||||
|
||||
void getStr() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findVarHandle(Test.class, "s", String.class);
|
||||
final Test instance = new Test();
|
||||
final Object nullArg = null;
|
||||
|
||||
String exact = (String) handle.get(instance);
|
||||
CharSequence parent = (CharSequence) handle.get(instance);
|
||||
Object object = (Object) handle.get(instance);
|
||||
Integer incompatible = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.get(instance);
|
||||
handle.get<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.get<warning descr="One argument is expected">()</warning>;
|
||||
handle.get(<warning descr="Call receiver is 'null'">nullArg</warning>);
|
||||
handle.get(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>);
|
||||
|
||||
String exactV = (String) handle.getVolatile(instance);
|
||||
CharSequence parentV = (CharSequence) handle.getVolatile(instance);
|
||||
Object objectV = (Object) handle.getVolatile(instance);
|
||||
Integer incompatibleV = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getVolatile(instance);
|
||||
handle.getVolatile<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.getVolatile<warning descr="One argument is expected">()</warning>;
|
||||
handle.getVolatile(<warning descr="Call receiver is 'null'">nullArg</warning>);
|
||||
handle.getVolatile(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>);
|
||||
|
||||
String exactO = (String) handle.getOpaque(instance);
|
||||
CharSequence parentO = (CharSequence) handle.getOpaque(instance);
|
||||
Object objectO = (Object) handle.getOpaque(instance);
|
||||
Integer incompatibleO = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getOpaque(instance);
|
||||
handle.getOpaque<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.getOpaque<warning descr="One argument is expected">()</warning>;
|
||||
handle.getOpaque(<warning descr="Call receiver is 'null'">nullArg</warning>);
|
||||
handle.getOpaque(<warning descr="Call receiver type is incompatible: 'Test' is expected">"abc"</warning>);
|
||||
|
||||
String exactA = (String) handle.getAcquire(instance);
|
||||
CharSequence parentA = (CharSequence) handle.getAcquire(instance);
|
||||
Object objectA = (Object) handle.getAcquire(instance);
|
||||
Integer incompatibleA = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getAcquire(instance);
|
||||
handle.getAcquire<warning descr="One argument is expected">(instance, 1)</warning>;
|
||||
handle.getAcquire<warning descr="One argument is expected">()</warning>;
|
||||
handle.getAcquire(<warning descr="Call receiver is 'null'">nullArg</warning>);
|
||||
handle.getAcquire(<warning descr="Call receiver type is incompatible: 'Test' is expected">"abc"</warning>);
|
||||
}
|
||||
|
||||
void setStr() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findVarHandle(Test.class, "s", String.class);
|
||||
final Test instance = new Test();
|
||||
final Object nullArg = null;
|
||||
final Object textArg = "abc";
|
||||
final Object numberArg = 3;
|
||||
|
||||
handle.set(instance, "a");
|
||||
handle.set(instance, charSequence());
|
||||
handle.set(instance, textArg);
|
||||
handle.set(instance, nullArg);
|
||||
handle.set(instance, numberArg);
|
||||
handle.set<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.set<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.set<warning descr="2 arguments are expected">(<warning descr="Call receiver is 'null'">nullArg</warning>)</warning>;
|
||||
handle.set(<warning descr="Call receiver type is incompatible: 'Test' is expected">"abc"</warning>, "d");
|
||||
|
||||
handle.setVolatile(instance, "a");
|
||||
handle.setVolatile(instance, charSequence());
|
||||
handle.setVolatile(instance, textArg);
|
||||
handle.setVolatile(instance, nullArg);
|
||||
handle.setVolatile(instance, numberArg);
|
||||
handle.setVolatile<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.setVolatile<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.setVolatile<warning descr="2 arguments are expected">(<warning descr="Call receiver is 'null'">nullArg</warning>)</warning>;
|
||||
handle.setVolatile(<warning descr="Call receiver type is incompatible: 'Test' is expected">"abc"</warning>, "d");
|
||||
|
||||
handle.setOpaque(instance, "a");
|
||||
handle.setOpaque(instance, charSequence());
|
||||
handle.setOpaque(instance, textArg);
|
||||
handle.setOpaque(instance, nullArg);
|
||||
handle.setOpaque(instance, numberArg);
|
||||
handle.setOpaque<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.setOpaque<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.setOpaque<warning descr="2 arguments are expected">(<warning descr="Call receiver is 'null'">nullArg</warning>)</warning>;
|
||||
handle.setOpaque(<warning descr="Call receiver type is incompatible: 'Test' is expected">"abc"</warning>, "d");
|
||||
|
||||
handle.setRelease(instance, "a");
|
||||
handle.setRelease(instance, charSequence());
|
||||
handle.setRelease(instance, textArg);
|
||||
handle.setRelease(instance, nullArg);
|
||||
handle.setRelease(instance, numberArg);
|
||||
handle.setRelease<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.setRelease<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.setRelease<warning descr="2 arguments are expected">(<warning descr="Call receiver is 'null'">nullArg</warning>)</warning>;
|
||||
handle.setRelease(<warning descr="Call receiver type is incompatible: 'Test' is expected">"abc"</warning>, "d");
|
||||
}
|
||||
|
||||
|
||||
private void getAndAddInt() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
VarHandle handle = lookup.findVarHandle(Test.class, "n", int.class);
|
||||
Test instance = new Test();
|
||||
Object nullArg = null;
|
||||
|
||||
int exact = (int) handle.getAndAdd(instance, 1);
|
||||
Integer boxed = (Integer) handle.getAndAdd(instance, 2);
|
||||
Object object = (Object) handle.getAndAdd(instance, 3);
|
||||
handle.getAndAdd(instance, 4);
|
||||
String incompatible = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndAdd(instance, 0);
|
||||
int incompatibleArg = (int) handle.getAndSet(instance, <warning descr="Argument is not assignable to 'int'">"abc"</warning>);
|
||||
handle.getAndAdd<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.getAndAdd<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.getAndAdd(<warning descr="Call receiver is 'null'">nullArg</warning>, 0);
|
||||
int wrongReceiver = (int)handle.getAndAdd(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>, 42);
|
||||
|
||||
int exactA = (int) handle.getAndAddAcquire(instance, 1); ;
|
||||
Integer boxedA = (Integer) handle.getAndAddAcquire(instance, 2);
|
||||
Object objectA = (Object) handle.getAndAddAcquire(instance, 3);
|
||||
handle.getAndAddAcquire(instance, 4);
|
||||
String incompatibleA = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndAddAcquire(instance, 0);
|
||||
int incompatibleArgA = (int) handle.getAndSetAcquire(instance, <warning descr="Argument is not assignable to 'int'">"abc"</warning>);
|
||||
handle.getAndAddAcquire<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.getAndAddAcquire<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.getAndAddAcquire(<warning descr="Call receiver is 'null'">nullArg</warning>, 0);
|
||||
int <error descr="Variable 'wrongReceiver' is already defined in the scope">wrongReceiver</error> = (int)handle.getAndAddAcquire(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>, 42);
|
||||
|
||||
int exactR = (int) handle.getAndAddRelease(instance, 1); ;
|
||||
Integer boxedR = (Integer) handle.getAndAddRelease(instance, 2);
|
||||
Object objectR = (Object) handle.getAndAddRelease(instance, 3);
|
||||
handle.getAndAddRelease(instance, 4);
|
||||
String incompatibleR = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndAdd(instance, 0);
|
||||
int incompatibleArgR = (int) handle.getAndSetRelease(instance, <warning descr="Argument is not assignable to 'int'">"abc"</warning>);
|
||||
handle.getAndAddRelease<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.getAndAddRelease<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.getAndAddRelease(<warning descr="Call receiver is 'null'">nullArg</warning>, 0);
|
||||
int wrongReceiverR = (int)handle.getAndAddRelease(<warning descr="Call receiver type is incompatible: 'Test' is expected">123</warning>, 42);
|
||||
}
|
||||
|
||||
private void getAndSetStr() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findVarHandle(Test.class, "s", String.class);
|
||||
final Test instance = new Test();
|
||||
final Object nullArg = null;
|
||||
|
||||
String exact = (String) handle.getAndSet(instance, "a");
|
||||
CharSequence parent = (CharSequence) handle.getAndSet(instance, "b");
|
||||
Object object = (Object) handle.getAndSet(instance, "c");
|
||||
String subclassArg = (String) handle.getAndSet(instance, charSequence());
|
||||
String withNullArg = (String) handle.getAndSet(instance, nullArg);
|
||||
handle.getAndSet(instance, "d");
|
||||
Integer incompatible = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getAndSet(instance, "e");
|
||||
String incompatibleArg = (String) handle.getAndSet(instance, <warning descr="Argument is not assignable to 'java.lang.String'">123</warning>);
|
||||
handle.getAndSet<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.getAndSet<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.getAndSet(<warning descr="Call receiver is 'null'">nullArg</warning>, "abc");
|
||||
int wrongReceiver = (<warning descr="Should be cast to 'java.lang.String' or its superclass">int</warning>)handle.getAndSet(<warning descr="Call receiver type is incompatible: 'Test' is expected">"abc"</warning>, "e");
|
||||
|
||||
String exactA = (String) handle.getAndSetAcquire(instance, "a");
|
||||
CharSequence parentA = (CharSequence) handle.getAndSetAcquire(instance, "b");
|
||||
Object objectA = (Object) handle.getAndSetAcquire(instance, "c");;
|
||||
String subclassArgA = (String) handle.getAndSetAcquire(instance, charSequence());
|
||||
String withNullArgA = (String) handle.getAndSetAcquire(instance, nullArg);
|
||||
handle.getAndSetAcquire(instance, "d");
|
||||
Integer incompatibleA = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getAndSetAcquire(instance, "e");
|
||||
String incompatibleArgA = (String) handle.getAndSetAcquire(instance, <warning descr="Argument is not assignable to 'java.lang.String'">123</warning>);
|
||||
handle.getAndSetAcquire<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.getAndSetAcquire<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.getAndSetAcquire(<warning descr="Call receiver is 'null'">nullArg</warning>, "abc");
|
||||
int wrongReceiverA = (<warning descr="Should be cast to 'java.lang.String' or its superclass">int</warning>)handle.getAndSetAcquire(<warning descr="Call receiver type is incompatible: 'Test' is expected">"abc"</warning>, "e");
|
||||
|
||||
String exactR = (String) handle.getAndSetRelease(instance, "a");
|
||||
CharSequence parentR = (CharSequence) handle.getAndSetRelease(instance, "b");
|
||||
Object objectR = (Object) handle.getAndSetRelease(instance, "c");;
|
||||
String subclassArgR = (String) handle.getAndSetRelease(instance, charSequence());
|
||||
String withNullArgR = (String) handle.getAndSetRelease(instance, nullArg);
|
||||
handle.getAndSetRelease(instance, "d");
|
||||
Integer incompatibleR = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>) handle.getAndSetRelease(instance, "e");
|
||||
String incompatibleArgR = (String) handle.getAndSetRelease(instance, <warning descr="Argument is not assignable to 'java.lang.String'">123</warning>);
|
||||
handle.getAndSetRelease<warning descr="2 arguments are expected">(instance)</warning>;
|
||||
handle.getAndSetRelease<warning descr="2 arguments are expected">()</warning>;
|
||||
handle.getAndSetRelease(<warning descr="Call receiver is 'null'">nullArg</warning>, "abc");
|
||||
int wrongReceiverR = (<warning descr="Should be cast to 'java.lang.String' or its superclass">int</warning>)handle.getAndSetRelease(<warning descr="Call receiver type is incompatible: 'Test' is expected">"abc"</warning>, "e");
|
||||
}
|
||||
|
||||
void getAndBitwise() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
VarHandle handle = lookup.findVarHandle(Test.class, "n", int.class);
|
||||
Test instance = new Test();
|
||||
|
||||
int exactBitwiseAnd = (int) handle.getAndBitwiseAnd(instance, 1);
|
||||
int exactBitwiseAndA = (int) handle.getAndBitwiseAndAcquire(instance, 2);
|
||||
int exactBitwiseAndR = (int) handle.getAndBitwiseAndRelease(instance, 3);
|
||||
|
||||
int wrongArgBitwiseAnd = (int) handle.getAndBitwiseAnd(instance, <warning descr="Argument is not assignable to 'int'">"a"</warning>);
|
||||
int wrongArgBitwiseAndA = (int) handle.getAndBitwiseAndAcquire(instance, <warning descr="Argument is not assignable to 'int'">"b"</warning>);
|
||||
int wrongArgBitwiseAndR = (int) handle.getAndBitwiseAndRelease(instance, <warning descr="Argument is not assignable to 'int'">"c"</warning>);
|
||||
|
||||
String wrongResultBitwiseAnd = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseAnd(instance, 1);
|
||||
String wrongResultBitwiseAndA = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseAndAcquire(instance, 2);
|
||||
String wrongResultBitwiseAndR = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseAndRelease(instance, 3);
|
||||
|
||||
int exactBitwiseOr = (int) handle.getAndBitwiseOr(instance, 1);
|
||||
int exactBitwiseOrA = (int) handle.getAndBitwiseOrAcquire(instance, 2);
|
||||
int exactBitwiseOrR = (int) handle.getAndBitwiseOrRelease(instance, 3);
|
||||
|
||||
int wrongArgBitwiseOr = (int) handle.getAndBitwiseOr(instance, <warning descr="Argument is not assignable to 'int'">"a"</warning>);
|
||||
int wrongArgBitwiseOrA = (int) handle.getAndBitwiseOrAcquire(instance, <warning descr="Argument is not assignable to 'int'">"b"</warning>);
|
||||
int wrongArgBitwiseOrR = (int) handle.getAndBitwiseOrRelease(instance, <warning descr="Argument is not assignable to 'int'">"c"</warning>);
|
||||
|
||||
String wrongResultBitwiseOr = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseOr(instance, 1);
|
||||
String wrongResultBitwiseOrA = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseOrAcquire(instance, 2);
|
||||
String wrongResultBitwiseOrR = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseOrRelease(instance, 3);
|
||||
|
||||
int exactBitwiseXor = (int) handle.getAndBitwiseXor(instance, 1);
|
||||
int exactBitwiseXorA = (int) handle.getAndBitwiseXorAcquire(instance, 2);
|
||||
int exactBitwiseXorR = (int) handle.getAndBitwiseXorRelease(instance, 3);
|
||||
|
||||
int wrongArgBitwiseXor = (int) handle.getAndBitwiseXor(instance, <warning descr="Argument is not assignable to 'int'">"a"</warning>);
|
||||
int wrongArgBitwiseXorA = (int) handle.getAndBitwiseXorAcquire(instance, <warning descr="Argument is not assignable to 'int'">"b"</warning>);
|
||||
int wrongArgBitwiseXorR = (int) handle.getAndBitwiseXorRelease(instance, <warning descr="Argument is not assignable to 'int'">"c"</warning>);
|
||||
|
||||
String wrongResultBitwiseXor = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseXor(instance, 1);
|
||||
String wrongResultBitwiseXorA = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseXorAcquire(instance, 2);
|
||||
String wrongResultBitwiseXorR = (<warning descr="Should be cast to 'int'">String</warning>) handle.getAndBitwiseXorRelease(instance, 3);
|
||||
}
|
||||
|
||||
|
||||
void compare() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findVarHandle(Test.class, "myS", String.class);
|
||||
final Test instance = new Test();
|
||||
|
||||
boolean exactCAS = handle.compareAndSet(instance, "a", "b");
|
||||
String exactCAE = (String)handle.compareAndExchange(instance, "a", "b");
|
||||
String exactCAEA = (String)handle.compareAndExchangeAcquire(instance, "a", "b");
|
||||
String exactCAER = (String)handle.compareAndExchangeRelease(instance, "a", "b");
|
||||
|
||||
boolean badArg2CAS = handle.compareAndSet(instance, <warning descr="Argument is not assignable to 'java.lang.String'">1</warning>, "b");
|
||||
String badArg2CAE = (String)handle.compareAndExchange(instance, <warning descr="Argument is not assignable to 'java.lang.String'">2</warning>, "b");
|
||||
String badArg2CAEa = (String)handle.compareAndExchangeAcquire(instance, <warning descr="Argument is not assignable to 'java.lang.String'">3</warning>, "b");
|
||||
String badArg2CAEr = (String)handle.compareAndExchangeRelease(instance, <warning descr="Argument is not assignable to 'java.lang.String'">4</warning>, "b");
|
||||
|
||||
boolean badArg3CAS = handle.compareAndSet(instance, "a", <warning descr="Argument is not assignable to 'java.lang.String'">1</warning>);
|
||||
String badArg3CAE = (String)handle.compareAndExchange(instance, "a", <warning descr="Argument is not assignable to 'java.lang.String'">2</warning>);
|
||||
String badArg3CAEa = (String)handle.compareAndExchangeAcquire(instance, "a", <warning descr="Argument is not assignable to 'java.lang.String'">3</warning>);
|
||||
String badArg3CAEr = (String)handle.compareAndExchangeRelease(instance, "a", <warning descr="Argument is not assignable to 'java.lang.String'">4</warning>);
|
||||
|
||||
Integer badResultCAE = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>)handle.compareAndExchange(instance, "a", "b");
|
||||
Integer badResultCAEa = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>)handle.compareAndExchangeAcquire(instance, "a", "b");
|
||||
Integer badResultCAEr = (<warning descr="Should be cast to 'java.lang.String' or its superclass">Integer</warning>)handle.compareAndExchangeRelease(instance, "a", "b");
|
||||
}
|
||||
|
||||
void weakCompare() throws Throwable {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final VarHandle handle = lookup.findVarHandle(Test.class, "myS", String.class);
|
||||
final Test instance = new Test();
|
||||
|
||||
boolean exactCAS = handle.weakCompareAndSet(instance, "a", "b");
|
||||
boolean exactCASp = handle.weakCompareAndSetPlain(instance, "a", "b");
|
||||
boolean exactCASa = handle.weakCompareAndSetAcquire(instance, "a", "b");
|
||||
boolean exactCASr = handle.weakCompareAndSetRelease(instance, "a", "b");
|
||||
|
||||
boolean badArg2CAS = handle.weakCompareAndSet(instance, <warning descr="Argument is not assignable to 'java.lang.String'">1</warning>, "b");
|
||||
boolean badArg2CASp = handle.weakCompareAndSetPlain(instance, <warning descr="Argument is not assignable to 'java.lang.String'">2</warning>, "b");
|
||||
boolean badArg2CASa = handle.weakCompareAndSetAcquire(instance, <warning descr="Argument is not assignable to 'java.lang.String'">3</warning>, "b");
|
||||
boolean badArg2CASr = handle.weakCompareAndSetRelease(instance, <warning descr="Argument is not assignable to 'java.lang.String'">4</warning>, "b");
|
||||
|
||||
boolean badArg3CAS = handle.weakCompareAndSet(instance, "a", <warning descr="Argument is not assignable to 'java.lang.String'">1</warning>);
|
||||
boolean badArg3CASp = handle.weakCompareAndSetPlain(instance, "a", <warning descr="Argument is not assignable to 'java.lang.String'">2</warning>);
|
||||
boolean badArg3CASa = handle.weakCompareAndSetAcquire(instance, "a", <warning descr="Argument is not assignable to 'java.lang.String'">3</warning>);
|
||||
boolean badArg3CASr = handle.weakCompareAndSetRelease(instance, "a", <warning descr="Argument is not assignable to 'java.lang.String'">4</warning>);
|
||||
}
|
||||
|
||||
private static CharSequence charSequence() { return "abc"; }
|
||||
}
|
||||
|
||||
class Test {
|
||||
public int n;
|
||||
public String s;
|
||||
}
|
||||
+23
-11
@@ -25,17 +25,9 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
class JavaLangReflectHandleInvocationTest : LightCodeInsightFixtureTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
LanguageLevelProjectExtension.getInstance(project).languageLevel = LanguageLevel.JDK_1_7
|
||||
myFixture.enableInspections(JavaLangReflectHandleInvocationInspection())
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = LightCodeInsightFixtureTestCase.JAVA_8
|
||||
|
||||
override fun getBasePath() = JavaTestUtil.getRelativeJavaTestDataPath() + "/inspection/javaLangReflectHandleInvocation"
|
||||
|
||||
class JavaLangReflectHandleInvocationTest : JavaLangReflectHandleInvocationTestBase(LanguageLevel.JDK_1_7,
|
||||
LightCodeInsightFixtureTestCase.JAVA_8) {
|
||||
fun testVirtual() = doTest()
|
||||
fun testStatic() = doTest()
|
||||
fun testConstructor() = doTest()
|
||||
@@ -45,8 +37,28 @@ class JavaLangReflectHandleInvocationTest : LightCodeInsightFixtureTestCase() {
|
||||
|
||||
fun testStaticGetter() = doTest()
|
||||
fun testStaticSetter() = doTest()
|
||||
}
|
||||
|
||||
private fun doTest() {
|
||||
class Java9LangReflectHandleInvocationTest : JavaLangReflectHandleInvocationTestBase(LanguageLevel.JDK_1_9,
|
||||
LightCodeInsightFixtureTestCase.JAVA_9) {
|
||||
fun testVarHandle() = doTest()
|
||||
fun testStaticVarHandle() = doTest()
|
||||
fun testArrayVarHandle() = doTest()
|
||||
}
|
||||
|
||||
abstract class JavaLangReflectHandleInvocationTestBase(val languageLevel: LanguageLevel,
|
||||
val descriptor: LightProjectDescriptor) : LightCodeInsightFixtureTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
LanguageLevelProjectExtension.getInstance(project).languageLevel = languageLevel
|
||||
myFixture.enableInspections(JavaLangReflectHandleInvocationInspection())
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = descriptor
|
||||
|
||||
override fun getBasePath() = JavaTestUtil.getRelativeJavaTestDataPath() + "/inspection/javaLangReflectHandleInvocation"
|
||||
|
||||
protected fun doTest() {
|
||||
myFixture.testHighlighting("${getTestName(false)}.java")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user