diff --git a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangInvokeHandleSignatureInspection.java b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangInvokeHandleSignatureInspection.java index 57273c8c1c74..7158fa96c3bb 100644 --- a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangInvokeHandleSignatureInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangInvokeHandleSignatureInspection.java @@ -100,7 +100,7 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI @NotNull ProblemsHolder holder) { if (arguments.length == 2) { if (FIND_CONSTRUCTOR.equals(factoryMethodName)) { - final PsiClass ownerClass = getReflectiveClass(arguments[0]); + final ReflectiveClass ownerClass = getReflectiveClass(arguments[0]); if (ownerClass != null) { final PsiExpression typeExpression = ParenthesesUtils.stripParentheses(arguments[1]); checkConstructor(ownerClass, typeExpression, holder); @@ -108,7 +108,7 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI } } else if (arguments.length >= 3) { - final PsiClass ownerClass = getReflectiveClass(arguments[0]); + final ReflectiveClass ownerClass = getReflectiveClass(arguments[0]); if (ownerClass != null) { final PsiExpression nameExpression = ParenthesesUtils.stripParentheses(arguments[1]); final PsiExpression nameDefinition = findDefinition(nameExpression); @@ -146,12 +146,13 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI } } - private static void checkConstructor(@NotNull PsiClass ownerClass, + private static void checkConstructor(@NotNull ReflectiveClass ownerClass, @NotNull PsiExpression constructorTypeExpression, @NotNull ProblemsHolder holder) { + if (!ownerClass.isExact()) return; final ReflectiveSignature constructorSignature = composeMethodSignature(constructorTypeExpression); if (constructorSignature != null) { - final List constructors = ContainerUtil.filter(ownerClass.getMethods(), PsiMethod::isConstructor); + final List constructors = ContainerUtil.filter(ownerClass.getPsiClass().getMethods(), PsiMethod::isConstructor); List validSignatures = null; if (constructors.isEmpty()) { if (!constructorSignature.equals(ReflectiveSignature.NO_ARGUMENT_CONSTRUCTOR_SIGNATURE)) { @@ -168,7 +169,7 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI final String declarationText = getConstructorDeclarationText(ownerClass, constructorSignature); if (declarationText != null) { LocalQuickFix fix = null; - final String ownerClassName = ownerClass.getName(); + final String ownerClassName = ownerClass.getPsiClass().getName(); if (ownerClassName != null) { fix = ReplaceSignatureQuickFix .createFix(constructorTypeExpression, ownerClassName, validSignatures, true, holder.isOnTheFly()); @@ -179,14 +180,15 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI } } - private static void checkField(@NotNull PsiClass ownerClass, + private static void checkField(@NotNull ReflectiveClass ownerClass, @NotNull String fieldName, @NotNull PsiExpression fieldNameExpression, @NotNull PsiExpression fieldTypeExpression, boolean isStaticExpected, @NotNull PsiReferenceExpression factoryMethodExpression, @NotNull ProblemsHolder holder) { - final PsiField field = ownerClass.findFieldByName(fieldName, true); + if (!ownerClass.isExact()) return; + final PsiField field = ownerClass.getPsiClass().findFieldByName(fieldName, true); if (field == null) { holder.registerProblem(fieldNameExpression, InspectionsBundle.message("inspection.handle.signature.field.cannot.resolve", fieldName)); return; @@ -212,15 +214,15 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI } } - private static void checkMethod(@NotNull PsiClass ownerClass, + private static void checkMethod(@NotNull ReflectiveClass ownerClass, @NotNull String methodName, @NotNull PsiExpression methodNameExpression, @NotNull PsiExpression methodTypeExpression, boolean isStaticExpected, @NotNull PsiReferenceExpression factoryMethodExpression, @NotNull ProblemsHolder holder) { - - final PsiMethod[] methods = ownerClass.findMethodsByName(methodName, true); + if (!ownerClass.isExact()) return; + final PsiMethod[] methods = ownerClass.getPsiClass().findMethodsByName(methodName, true); if (methods.length == 0) { holder.registerProblem(methodNameExpression, JavaErrorMessages.message("cannot.resolve.method", methodName)); return; @@ -264,7 +266,7 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI if (argumentType == null || argumentType.getType() instanceof PsiArrayType) { return; } - if (!argumentType.isPrimitive()) { + if (!argumentType.isPrimitive() && !argumentType.isExact()) { final String name = argumentType.getQualifiedName(); if (JAVA_LANG_OBJECT.equals(name) || "java.io.Serializable".equals(name) || "java.lang.Cloneable".equals(name)) { return; @@ -280,8 +282,8 @@ public class JavaLangInvokeHandleSignatureInspection extends BaseJavaBatchLocalI } @Nullable - private static String getConstructorDeclarationText(@NotNull PsiClass ownerClass, @NotNull ReflectiveSignature methodSignature) { - final String className = ownerClass.getName(); + private static String getConstructorDeclarationText(@NotNull ReflectiveClass ownerClass, @NotNull ReflectiveSignature methodSignature) { + final String className = ownerClass.getPsiClass().getName(); if (className != null) { return getConstructorDeclarationText(className, methodSignature); } diff --git a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangReflectHandleInvocationChecker.java b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangReflectHandleInvocationChecker.java index 8d4714f0e00c..e15dbc02089d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangReflectHandleInvocationChecker.java +++ b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangReflectHandleInvocationChecker.java @@ -280,7 +280,7 @@ class JavaLangReflectHandleInvocationChecker { } final PsiClassType javaLangObject = PsiType.getJavaLangObject(methodTypeExpression.getManager(), methodTypeExpression.getResolveScope()); - final ReflectiveType objectType = ReflectiveType.create(javaLangObject); + final ReflectiveType objectType = ReflectiveType.create(javaLangObject, false); final List argumentTypes = new ArrayList<>(); argumentTypes.add(objectType); // return type for (int i = 0; i < objectArgCount; i++) { diff --git a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangReflectVarHandleInvocationChecker.java b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangReflectVarHandleInvocationChecker.java index 2c4da4e6beb9..c5610dad1ee3 100644 --- a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangReflectVarHandleInvocationChecker.java +++ b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaLangReflectVarHandleInvocationChecker.java @@ -135,9 +135,8 @@ class JavaLangReflectVarHandleInvocationChecker { if (arrayType != null) { checkCallReceiver(methodCall, arrayType, holder); - final PsiType rawArrayType = arrayType.getType(); - if (rawArrayType instanceof PsiArrayType) { - final ReflectiveType valueType = ReflectiveType.create(((PsiArrayType)rawArrayType).getComponentType()); + final ReflectiveType valueType = arrayType.getArrayComponentType(); + if (valueType != null) { checkVarHandleAccessSignature(methodCall, valueType, 2, holder); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionMemberAccessInspection.java b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionMemberAccessInspection.java index 019e593c442a..a4acce092452 100644 --- a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionMemberAccessInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionMemberAccessInspection.java @@ -163,19 +163,19 @@ public class JavaReflectionMemberAccessInspection extends BaseJavaBatchLocalInsp final PsiExpression nameExpression = arguments[0]; final String fieldName = getMemberName(nameExpression); if (fieldName != null) { - final PsiClass psiClass = getPsiClass(callExpression); - if (psiClass != null) { - final PsiField field = psiClass.findFieldByName(fieldName, true); + final ReflectiveClass ownerClass = getOwnerClass(callExpression); + if (ownerClass != null && ownerClass.isExact()) { + final PsiField field = ownerClass.getPsiClass().findFieldByName(fieldName, true); if (field == null) { - if (reportUnresolvedMembersOf(psiClass)) { + if (reportUnresolvedMembersOf(ownerClass)) { holder.registerProblem(nameExpression, InspectionsBundle.message( "inspection.reflection.member.access.cannot.resolve.field", fieldName)); } return; } - if (isDeclared && field.getContainingClass() != psiClass) { + if (isDeclared && field.getContainingClass() != ownerClass.getPsiClass()) { holder.registerProblem(nameExpression, InspectionsBundle.message( - "inspection.reflection.member.access.field.not.in.class", fieldName, psiClass.getQualifiedName())); + "inspection.reflection.member.access.field.not.in.class", fieldName, ownerClass.getPsiClass().getQualifiedName())); return; } if (!isDeclared && !field.hasModifierProperty(PsiModifier.PUBLIC)) { @@ -193,11 +193,11 @@ public class JavaReflectionMemberAccessInspection extends BaseJavaBatchLocalInsp final PsiExpression nameExpression = arguments[0]; final String methodName = getMemberName(nameExpression); if (methodName != null) { - final PsiClass psiClass = getPsiClass(callExpression); - if (psiClass != null) { - final PsiMethod[] methods = psiClass.findMethodsByName(methodName, true); + final ReflectiveClass ownerClass = getOwnerClass(callExpression); + if (ownerClass != null && ownerClass.isExact()) { + final PsiMethod[] methods = ownerClass.getPsiClass().findMethodsByName(methodName, true); if (methods.length == 0) { - if (reportUnresolvedMembersOf(psiClass)) { + if (reportUnresolvedMembersOf(ownerClass)) { holder.registerProblem(nameExpression, InspectionsBundle.message( "inspection.reflection.member.access.cannot.resolve.method", methodName)); } @@ -205,15 +205,15 @@ public class JavaReflectionMemberAccessInspection extends BaseJavaBatchLocalInsp } final PsiMethod matchingMethod = matchMethod(methods, arguments, 1); if (matchingMethod == null) { - if (reportUnresolvedMembersOf(psiClass)) { + if (reportUnresolvedMembersOf(ownerClass)) { holder.registerProblem(nameExpression, InspectionsBundle.message( "inspection.reflection.member.access.cannot.resolve.method.arguments", methodName)); } return; } - if (isDeclared && matchingMethod.getContainingClass() != psiClass) { + if (isDeclared && matchingMethod.getContainingClass() != ownerClass.getPsiClass()) { holder.registerProblem(nameExpression, InspectionsBundle.message( - "inspection.reflection.member.access.method.not.in.class", methodName, psiClass.getQualifiedName())); + "inspection.reflection.member.access.method.not.in.class", methodName, ownerClass.getPsiClass().getQualifiedName())); return; } if (!isDeclared && !matchingMethod.hasModifierProperty(PsiModifier.PUBLIC)) { @@ -228,9 +228,9 @@ public class JavaReflectionMemberAccessInspection extends BaseJavaBatchLocalInsp private void checkConstructor(@NotNull PsiMethodCallExpression callExpression, boolean isDeclared, @NotNull ProblemsHolder holder) { - final PsiClass psiClass = getPsiClass(callExpression); - if (psiClass != null) { - final PsiMethod[] methods = psiClass.getConstructors(); + final ReflectiveClass ownerClass = getOwnerClass(callExpression); + if (ownerClass != null && ownerClass.isExact()) { + final PsiMethod[] methods = ownerClass.getPsiClass().getConstructors(); final PsiExpression[] arguments = callExpression.getArgumentList().getExpressions(); final PsiModifierListOwner constructorOrClass; if (methods.length != 0) { @@ -238,10 +238,10 @@ public class JavaReflectionMemberAccessInspection extends BaseJavaBatchLocalInsp } else { // implicit constructor - constructorOrClass = arguments.length == 0 ? psiClass : null; + constructorOrClass = arguments.length == 0 ? ownerClass.getPsiClass() : null; } if (constructorOrClass == null) { - if (reportUnresolvedMembersOf(psiClass)) { + if (reportUnresolvedMembersOf(ownerClass)) { holder.registerProblem(callExpression.getArgumentList(), InspectionsBundle.message( "inspection.reflection.member.access.cannot.resolve.constructor.arguments")); } @@ -254,9 +254,9 @@ public class JavaReflectionMemberAccessInspection extends BaseJavaBatchLocalInsp } } - private boolean reportUnresolvedMembersOf(@NotNull PsiClass psiClass) { - return (checkMemberExistsInNonFinalClasses || psiClass.hasModifierProperty(PsiModifier.FINAL)) && - !ignoredClassNames.contains(psiClass.getQualifiedName()); + private boolean reportUnresolvedMembersOf(@NotNull ReflectiveClass ownerClass) { + return (checkMemberExistsInNonFinalClasses || ownerClass.getPsiClass().hasModifierProperty(PsiModifier.FINAL)) && + !ignoredClassNames.contains(ownerClass.getPsiClass().getQualifiedName()); } @Contract("null->null") @@ -266,7 +266,7 @@ public class JavaReflectionMemberAccessInspection extends BaseJavaBatchLocalInsp } @Nullable - private static PsiClass getPsiClass(@NotNull PsiMethodCallExpression callExpression) { + private static ReflectiveClass getOwnerClass(@NotNull PsiMethodCallExpression callExpression) { return getReflectiveClass(callExpression.getMethodExpression().getQualifierExpression()); } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java index 4e45bdf5b3c8..400f3b7d1b85 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java @@ -56,21 +56,21 @@ public class JavaLangClassMemberReference extends PsiReferenceBase 1) { methods = ContainerUtil.filter(methods, method -> isRegularMethod(method) && isPublic(method)) @@ -83,10 +83,10 @@ public class JavaLangClassMemberReference extends PsiReferenceBase 1) { methods = - ContainerUtil.filter(methods, method -> isRegularMethod(method) && isPotentiallyAccessible(method, psiClass)) + ContainerUtil.filter(methods, method -> isRegularMethod(method) && isPotentiallyAccessible(method, ownerClass)) .toArray(PsiMethod.EMPTY_ARRAY); if (methods.length > 1) { return findOverloadedMethod(methods); @@ -102,7 +102,7 @@ public class JavaLangClassMemberReference extends PsiReferenceBase field.getName() != null) .sorted(Comparator.comparing(PsiField::getName)) .map(field -> lookupField(field)) @@ -124,15 +124,15 @@ public class JavaLangClassMemberReference extends PsiReferenceBase uniqueNames = new THashSet<>(); - return Arrays.stream(psiClass.getAllFields()) - .filter(field -> isPotentiallyAccessible(field, psiClass) && field.getName() != null && uniqueNames.add(field.getName())) + return Arrays.stream(ownerClass.getPsiClass().getAllFields()) + .filter(field -> isPotentiallyAccessible(field, ownerClass) && field.getName() != null && uniqueNames.add(field.getName())) .sorted(Comparator.comparingInt((PsiField field) -> isPublic(field) ? 0 : 1).thenComparing(PsiField::getName)) .map(field -> withPriority(lookupField(field), isPublic(field))) .toArray(); } case GET_DECLARED_METHOD: - return Arrays.stream(psiClass.getMethods()) + return Arrays.stream(ownerClass.getPsiClass().getMethods()) .filter(method -> isRegularMethod(method)) .sorted(Comparator.comparing(PsiMethod::getName)) .map(method -> lookupMethod(method, this)) @@ -140,10 +140,10 @@ public class JavaLangClassMemberReference extends PsiReferenceBase isRegularMethod(method) && isPotentiallyAccessible(method, psiClass)) + .filter(method -> isRegularMethod(method) && isPotentiallyAccessible(method, ownerClass)) .sorted(Comparator.comparingInt((PsiMethod method) -> getMethodSortOrder(method)).thenComparing(PsiMethod::getName)) .map(method -> withPriority(lookupMethod(method, this), -getMethodSortOrder(method))) .filter(Objects::nonNull) @@ -160,8 +160,8 @@ public class JavaLangClassMemberReference extends PsiReferenceBase false") - private static boolean isPotentiallyAccessible(PsiMember member, PsiClass psiClass) { - return member != null && (member.getContainingClass() == psiClass || isPublic(member)); + private static boolean isPotentiallyAccessible(PsiMember member, ReflectiveClass psiClass) { + return member != null && (member.getContainingClass() == psiClass.getPsiClass() || isPublic(member)); } @Nullable diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangInvokeHandleReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangInvokeHandleReference.java index ed949cfc0e5b..202e3b7dfbef 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangInvokeHandleReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangInvokeHandleReference.java @@ -63,27 +63,27 @@ public class JavaLangInvokeHandleReference extends PsiReferenceBase filter) { - final PsiField field = psiClass.findFieldByName(name, true); + private static PsiElement resolveField(@NotNull String name, @NotNull ReflectiveClass ownerClass, Condition filter) { + final PsiField field = ownerClass.getPsiClass().findFieldByName(name, true); return field != null && filter.value(field) ? field : null; } - private PsiElement resolveMethod(@NotNull String name, @NotNull PsiClass psiClass, Condition filter) { - PsiMethod[] methods = psiClass.findMethodsByName(name, true); + private PsiElement resolveMethod(@NotNull String name, @NotNull ReflectiveClass ownerClass, Condition filter) { + PsiMethod[] methods = ownerClass.getPsiClass().findMethodsByName(name, true); if (methods.length != 0) { methods = ContainerUtil.filter(methods, filter).toArray(PsiMethod.EMPTY_ARRAY); if (methods.length > 1) { @@ -125,25 +125,25 @@ public class JavaLangInvokeHandleReference extends PsiReferenceBase filter) { - return psiClass.getVisibleSignatures() + private Object[] lookupMethods(@NotNull ReflectiveClass ownerClass, Predicate filter) { + return ownerClass.getPsiClass().getVisibleSignatures() .stream() .map(MethodSignatureBackedByPsiMethod::getMethod) .filter(filter) @@ -163,11 +163,11 @@ public class JavaLangInvokeHandleReference extends PsiReferenceBase filter) { + private Object[] lookupFields(@NotNull ReflectiveClass ownerClass, Predicate filter) { final Set uniqueNames = new THashSet<>(); - return Arrays.stream(psiClass.getAllFields()) + return Arrays.stream(ownerClass.getPsiClass().getAllFields()) .filter(field -> field != null && - (field.getContainingClass() == psiClass || !field.hasModifierProperty(PsiModifier.PRIVATE)) && + (field.getContainingClass() == ownerClass.getPsiClass() || !field.hasModifierProperty(PsiModifier.PRIVATE)) && field.getName() != null && uniqueNames.add(field.getName())) .filter(filter) .sorted(Comparator.comparing((PsiField field) -> isPublic(field) ? 0 : 1).thenComparing(PsiField::getName)) diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaMethodHandleCompletionContributor.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaMethodHandleCompletionContributor.java index e0b671bb6de6..cf99c02820dd 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaMethodHandleCompletionContributor.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaMethodHandleCompletionContributor.java @@ -91,12 +91,12 @@ public class JavaMethodHandleCompletionContributor extends CompletionContributor final String methodName = methodCall.getMethodExpression().getReferenceName(); if (methodName != null && METHOD_HANDLE_FACTORY_NAMES.contains(methodName)) { final PsiExpression[] arguments = methodCall.getArgumentList().getExpressions(); - final PsiClass psiClass = arguments.length != 0 ? getReflectiveClass(arguments[0]) : null; - if (psiClass != null) { + final ReflectiveClass ownerClass = arguments.length != 0 ? getReflectiveClass(arguments[0]) : null; + if (ownerClass != null) { switch (methodName) { case FIND_CONSTRUCTOR: - addConstructorSignatures(psiClass, position, result); + addConstructorSignatures(ownerClass, position, result); break; case FIND_VIRTUAL: @@ -104,7 +104,7 @@ public class JavaMethodHandleCompletionContributor extends CompletionContributor case FIND_SPECIAL: final String name = arguments.length > 1 ? computeConstantExpression(arguments[1], String.class) : null; if (!StringUtil.isEmpty(name)) { - addMethodSignatures(psiClass, name, FIND_STATIC.equals(methodName), position, result); + addMethodSignatures(ownerClass, name, FIND_STATIC.equals(methodName), position, result); } break; } @@ -113,27 +113,24 @@ public class JavaMethodHandleCompletionContributor extends CompletionContributor } } - private static void addConstructorSignatures(@NotNull PsiClass psiClass, + private static void addConstructorSignatures(@NotNull ReflectiveClass ownerClass, @NotNull PsiElement context, @NotNull Consumer result) { - final String className = psiClass.getName(); - if (className != null) { - final PsiMethod[] constructors = psiClass.getConstructors(); - if (constructors.length != 0) { - lookupMethodTypes(Arrays.stream(constructors), context, result); - } - else { - result.consume(lookupSignature(ReflectiveSignature.NO_ARGUMENT_CONSTRUCTOR_SIGNATURE, context)); - } + final PsiMethod[] constructors = ownerClass.getPsiClass().getConstructors(); + if (constructors.length != 0) { + lookupMethodTypes(Arrays.stream(constructors), context, result); + } + else { + result.consume(lookupSignature(ReflectiveSignature.NO_ARGUMENT_CONSTRUCTOR_SIGNATURE, context)); } } - private static void addMethodSignatures(@NotNull PsiClass psiClass, + private static void addMethodSignatures(@NotNull ReflectiveClass psiClass, @NotNull String methodName, boolean isStaticExpected, @NotNull PsiElement context, @NotNull Consumer result) { - final PsiMethod[] methods = psiClass.findMethodsByName(methodName, false); + final PsiMethod[] methods = psiClass.getPsiClass().findMethodsByName(methodName, false); if (methods.length != 0) { final Stream methodStream = Arrays.stream(methods) .filter(method -> method.hasModifierProperty(PsiModifier.STATIC) == isStaticExpected); @@ -174,9 +171,9 @@ public class JavaMethodHandleCompletionContributor extends CompletionContributor if (arguments.length > 2) { final String fieldName = computeConstantExpression(arguments[1], String.class); if (!StringUtil.isEmpty(fieldName)) { - final PsiClass psiClass = getReflectiveClass(arguments[0]); - if (psiClass != null) { - addFieldType(psiClass, fieldName, position, result); + final ReflectiveClass ownerClass = getReflectiveClass(arguments[0]); + if (ownerClass != null) { + addFieldType(ownerClass, fieldName, position, result); } } } @@ -184,14 +181,14 @@ public class JavaMethodHandleCompletionContributor extends CompletionContributor } } - private static void addFieldType(@NotNull PsiClass psiClass, + private static void addFieldType(@NotNull ReflectiveClass ownerClass, @NotNull String fieldName, @NotNull PsiElement context, @NotNull Consumer result) { - final PsiField field = psiClass.findFieldByName(fieldName, false); + final PsiField field = ownerClass.getPsiClass().findFieldByName(fieldName, false); if (field != null) { final String typeText = getTypeText(field.getType()); - final PsiElementFactory factory = JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory(); + final PsiElementFactory factory = JavaPsiFacade.getInstance(ownerClass.getPsiClass().getProject()).getElementFactory(); final PsiExpression expression = factory.createExpressionFromText(typeText + ".class", context); final String shortType = PsiNameHelper.getShortClassName(typeText); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionCompletionContributor.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionCompletionContributor.java index fd3ec2982562..369c295c4a07 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionCompletionContributor.java @@ -99,11 +99,11 @@ public class JavaReflectionCompletionContributor extends CompletionContributor { private static void addVariants(PsiElement position, BiConsumer variantAdder) { PsiMethodCallExpression methodCall = PsiTreeUtil.getParentOfType(position, PsiMethodCallExpression.class); if (methodCall != null) { - PsiClass psiClass = getReflectiveClass(methodCall.getMethodExpression().getQualifierExpression()); - if (psiClass != null) { + ReflectiveClass ownerClass = getReflectiveClass(methodCall.getMethodExpression().getQualifierExpression()); + if (ownerClass != null) { String methodName = methodCall.getMethodExpression().getReferenceName(); if (methodName != null) { - variantAdder.accept(psiClass, DECLARED_NAMES.contains(methodName)); + variantAdder.accept(ownerClass.getPsiClass(), DECLARED_NAMES.contains(methodName)); } } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java index 7969d19b400c..c4bd4c3ab5e5 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java @@ -102,9 +102,9 @@ public class JavaReflectionReferenceUtil { if (context == null) { return null; } - if (context instanceof PsiClassObjectAccessExpression) { // special case for JDK 1.4 + if (context instanceof PsiClassObjectAccessExpression) { final PsiTypeElement operand = ((PsiClassObjectAccessExpression)context).getOperand(); - return ReflectiveType.create(operand.getType()); + return ReflectiveType.create(operand.getType(), true); } if (context instanceof PsiMethodCallExpression) { @@ -118,7 +118,7 @@ public class JavaReflectionReferenceUtil { final PsiExpression argument = findDefinition(ParenthesesUtils.stripParentheses(expressions[0])); final String className = computeConstantExpression(argument, String.class); if (className != null) { - return ReflectiveType.create(findClass(className, context)); + return ReflectiveType.create(findClass(className, context), true); } } } @@ -154,7 +154,7 @@ public class JavaReflectionReferenceUtil { if (field.hasModifierProperty(PsiModifier.FINAL) && field.hasModifierProperty(PsiModifier.STATIC)) { final PsiPrimitiveType unboxedType = tryUnbox(field.getContainingClass(), (PsiClassType)type); if (unboxedType != null) { - return ReflectiveType.create(unboxedType); + return ReflectiveType.create(unboxedType, true); } } } @@ -165,7 +165,7 @@ public class JavaReflectionReferenceUtil { final PsiType erasure = TypeConversionUtil.erasure(typeArgument); final PsiClass argumentClass = PsiTypesUtil.getPsiClass(erasure); if (argumentClass != null && !isJavaLangObject(argumentClass)) { - return ReflectiveType.create(argumentClass); + return ReflectiveType.create(argumentClass, false); } } } @@ -212,7 +212,7 @@ public class JavaReflectionReferenceUtil { } } } - return ReflectiveType.create(expression.getType()); + return ReflectiveType.create(expression.getType(), false); } @Contract("null,_->null") @@ -224,9 +224,9 @@ public class JavaReflectionReferenceUtil { } @Nullable - public static PsiClass getReflectiveClass(PsiExpression context) { + public static ReflectiveClass getReflectiveClass(PsiExpression context) { final ReflectiveType reflectiveType = getReflectiveType(context); - return reflectiveType != null ? reflectiveType.getPsiClass() : null; + return reflectiveType != null ? reflectiveType.getReflectiveClass() : null; } @Nullable @@ -405,7 +405,7 @@ public class JavaReflectionReferenceUtil { @NotNull public static String getTypeText(@NotNull PsiType type) { - final ReflectiveType reflectiveType = ReflectiveType.create(type); + final ReflectiveType reflectiveType = ReflectiveType.create(type, false); return reflectiveType.getQualifiedName(); } @@ -557,9 +557,11 @@ public class JavaReflectionReferenceUtil { public static class ReflectiveType { final PsiType myType; + final boolean myIsExact; - private ReflectiveType(@NotNull PsiType erasedType) { + private ReflectiveType(@NotNull PsiType erasedType, boolean isExact) { myType = erasedType; + myIsExact = isExact; } @NotNull @@ -589,26 +591,48 @@ public class JavaReflectionReferenceUtil { return myType; } + public boolean isExact() { + return myIsExact; + } + + @Nullable + public ReflectiveClass getReflectiveClass() { + PsiClass psiClass = getPsiClass(); + if (psiClass != null) { + return new ReflectiveClass(psiClass, myIsExact); + } + return null; + } + + @Nullable + public ReflectiveType getArrayComponentType() { + if (myType instanceof PsiArrayType) { + PsiType componentType = ((PsiArrayType)myType).getComponentType(); + return new ReflectiveType(componentType, myIsExact); + } + return null; + } + @Nullable public PsiClass getPsiClass() { return PsiTypesUtil.getPsiClass(myType); } - @Contract("!null -> !null; null -> null") + @Contract("!null,_ -> !null; null,_ -> null") @Nullable - public static ReflectiveType create(@Nullable PsiType originalType) { + public static ReflectiveType create(@Nullable PsiType originalType, boolean isExact) { if (originalType != null) { - return new ReflectiveType(erasure(originalType)); + return new ReflectiveType(erasure(originalType), isExact); } return null; } - @Contract("!null -> !null; null -> null") + @Contract("!null,_ -> !null; null,_ -> null") @Nullable - public static ReflectiveType create(@Nullable PsiClass psiClass) { + public static ReflectiveType create(@Nullable PsiClass psiClass, boolean isExact) { if (psiClass != null) { final PsiElementFactory factory = JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory(); - return new ReflectiveType(factory.createType(psiClass)); + return new ReflectiveType(factory.createType(psiClass), isExact); } return null; } @@ -617,7 +641,7 @@ public class JavaReflectionReferenceUtil { @Nullable public static ReflectiveType arrayOf(@Nullable ReflectiveType itemType) { if (itemType != null) { - return new ReflectiveType(itemType.myType.createArrayType()); + return new ReflectiveType(itemType.myType.createArrayType(), itemType.myIsExact); } return null; } @@ -632,6 +656,25 @@ public class JavaReflectionReferenceUtil { } } + public static class ReflectiveClass { + final PsiClass myPsiClass; + final boolean myIsExact; + + public ReflectiveClass(@NotNull PsiClass psiClass, boolean isExact) { + myPsiClass = psiClass; + myIsExact = isExact; + } + + @NotNull + public PsiClass getPsiClass() { + return myPsiClass; + } + + public boolean isExact() { + return myIsExact || myPsiClass.hasModifierProperty(PsiModifier.FINAL); + } + } + public static class ReflectiveSignature implements Comparable { public static final ReflectiveSignature NO_ARGUMENT_CONSTRUCTOR_SIGNATURE = new ReflectiveSignature(null, PsiKeyword.VOID, ArrayUtil.EMPTY_STRING_ARRAY); diff --git a/java/java-tests/testData/inspection/javaReflectionMemberAccess/Bugs.java b/java/java-tests/testData/inspection/javaReflectionMemberAccess/Bugs.java new file mode 100644 index 000000000000..2ad9f7bc6a3d --- /dev/null +++ b/java/java-tests/testData/inspection/javaReflectionMemberAccess/Bugs.java @@ -0,0 +1,38 @@ +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +class Bugs { + static class EnumMethod { + public static > boolean isEnum(final Class enumClass, final String candidate) { + try { + final Method method = enumClass.getMethod("valueOf", String.class); + Object o = method.invoke(null, candidate); + System.out.println(o.getClass() + "." + o); + return true; + } + catch (final IllegalArgumentException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { + return false; + } + } + } + + static class ConstructorInSubclass { + static abstract class X { + } + + public static class Y extends X { + public Y(int i) { + System.out.println("ok"); + } + } + + static X test(Class clazz) throws Exception { + return clazz.getConstructor(int.class) + .newInstance(1); + } + + public static void main(String[] args) throws Exception { + test(Y.class); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/javaReflectionMemberAccess/NewInstance.java b/java/java-tests/testData/inspection/javaReflectionMemberAccess/NewInstance.java index 4e193dbadb5e..e5e29696f6d5 100644 --- a/java/java-tests/testData/inspection/javaReflectionMemberAccess/NewInstance.java +++ b/java/java-tests/testData/inspection/javaReflectionMemberAccess/NewInstance.java @@ -53,7 +53,7 @@ class Vararg { myB1 = B.class; } - void foo1() { + void foo1() throws Exception { ourA.getMethod("bar", myB1); ourA.getMethod("bar", myB1, String.class); } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/JavaReflectionMemberAccessTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInspection/JavaReflectionMemberAccessTest.kt index 380e5353bdbc..2e8ed733da23 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/JavaReflectionMemberAccessTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/JavaReflectionMemberAccessTest.kt @@ -17,8 +17,6 @@ package com.intellij.java.codeInspection import com.intellij.JavaTestUtil import com.intellij.codeInspection.reflectiveAccess.JavaReflectionMemberAccessInspection -import com.intellij.openapi.roots.LanguageLevelProjectExtension -import com.intellij.pom.java.LanguageLevel import com.intellij.testFramework.LightProjectDescriptor import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase @@ -31,11 +29,11 @@ class JavaReflectionMemberAccessTest : LightCodeInsightFixtureTestCase() { override fun setUp() { super.setUp() - LanguageLevelProjectExtension.getInstance(project).languageLevel = LanguageLevel.JDK_1_5 myFixture.enableInspections(inspection) } - override fun getProjectDescriptor(): LightProjectDescriptor = LightCodeInsightFixtureTestCase.JAVA_1_5 + override fun getProjectDescriptor(): LightProjectDescriptor = + LightCodeInsightFixtureTestCase.JAVA_8 // older mock JREs are missing some bits override fun getBasePath() = JavaTestUtil.getRelativeJavaTestDataPath() + "/inspection/javaReflectionMemberAccess" @@ -48,6 +46,7 @@ class JavaReflectionMemberAccessTest : LightCodeInsightFixtureTestCase() { fun testConstructorExists() = doTest(true) fun testNewInstance() = doTest(true) + fun testBugs() = doTest(true) private fun doTest(checkExists: Boolean = false) {