ReflectiveType (@Nullable PsiExpression context) { context = PsiUtil.skipParenthesizedExprDown(context); if (context == null) { return null; } if (context instanceof PsiClassObjectAccessExpression) { final PsiTypeElement operand = ((PsiClassObjectAccessExpression)context).getOperand(); return ReflectiveType.create(operand.getType(), true); } if (context instanceof PsiMethodCallExpression methodCall) { final String methodReferenceName = methodCall.getMethodExpression().getReferenceName(); if (FOR_NAME.equals(methodReferenceName)) { final PsiMethod method = methodCall.resolveMethod(); if (method != null && isJavaLangClass(method.getContainingClass())) { final PsiExpression[] expressions = methodCall.getArgumentList().getExpressions(); if (expressions.length == 1) { final PsiExpression argument = findDefinition(PsiUtil.skipParenthesizedExprDown(expressions[0])); final String className = computeConstantExpression(argument, String.class); if (className != null) { return ReflectiveType.create(findClass(className, context), true); } } } } else if (GET_CLASS.equals(methodReferenceName) && methodCall.getArgumentList().isEmpty()) { final PsiMethod method = methodCall.resolveMethod(); if (method != null && isJavaLangObject(method.getContainingClass())) { final PsiExpression qualifier = PsiUtil.skipParenthesizedExprDown(methodCall.getMethodExpression().getQualifierExpression()); if (qualifier instanceof PsiReferenceExpression) { final PsiExpression definition = findVariableDefinition((PsiReferenceExpression)qualifier); if (definition != null) { return getClassInstanceType(definition); } } //TODO type of the qualifier may be a supertype of the actual value - need to compute the type of the actual value // otherwise getDeclaredField and getDeclaredMethod may work not reliably if (qualifier != null) { return getClassInstanceType(qualifier); } } } } if (context instanceof PsiReferenceExpression reference && reference.resolve() instanceof PsiVariable variable && isJavaLangClass(PsiTypesUtil.getPsiClass(variable.getType()))) { final PsiExpression definition = findVariableDefinition(reference, variable); if (definition != null) { ReflectiveType result = ourGuard.doPreventingRecursion(variable, false, () -> getReflectiveType(definition)); if (result != null) { return result; } } } if (context.getType() instanceof PsiClassType type) { final PsiClassType.ClassResolveResult resolveResult = type.resolveGenerics(); final PsiClass resolvedElement = resolveResult.getElement(); if (!isJavaLangClass(resolvedElement)) return null; if (context instanceof PsiReferenceExpression ref && TYPE.equals(ref.getReferenceName()) && ref.resolve() instanceof PsiField field && field.hasModifierProperty(PsiModifier.FINAL) && field.hasModifierProperty(PsiModifier.STATIC)) { final PsiType[] classTypeArguments = type.getParameters(); final PsiPrimitiveType unboxedType = classTypeArguments.length == 1 ? PsiPrimitiveType.getUnboxedType(classTypeArguments[0]) : null; if (unboxedType != null && field.getContainingClass() == PsiUtil.resolveClassInClassTypeOnly(classTypeArguments[0])) { return ReflectiveType.create(unboxedType, true); } } final PsiTypeParameter[] parameters = resolvedElement.getTypeParameters(); if (parameters.length == 1) { final PsiType typeArgument = resolveResult.getSubstitutor().substitute(parameters[0]); final PsiType erasure = TypeConversionUtil.erasure(typeArgument); final PsiClass argumentClass = PsiTypesUtil.getPsiClass(erasure); if (argumentClass != null && !isJavaLangObject(argumentClass)) { return ReflectiveType.create(argumentClass, false); } } } return null; }