private static void checkReflectionCall(@NotNull PsiMethodCallExpression methodCall,
                                          int argumentOffset,
                                          @NotNull ProblemsHolder holder,
                                          @NotNull Predicate<? super PsiMethodCallExpression> methodPredicate) {
    final List<PsiExpression> requiredTypes =
      getRequiredMethodArguments(methodCall.getMethodExpression().getQualifierExpression(), argumentOffset, methodPredicate);
    if (requiredTypes != null) {
      final PsiExpressionList argumentList = methodCall.getArgumentList();
      final Arguments actualArguments = getActualMethodArguments(argumentList.getExpressions(), argumentOffset, 
                                                                 MethodCallUtils.isVarArgCall(methodCall));
      if (actualArguments != null) {
        if (requiredTypes.size() != actualArguments.expressions.length) {
          if (actualArguments.varargAsArray) {
            final PsiExpression[] expressions = argumentList.getExpressions();
            final PsiElement element = expressions.length == argumentOffset + 1 ? expressions[argumentOffset] : argumentList;
            holder.registerProblem(element, JavaBundle.message(
              "inspection.reflection.invocation.item.count", requiredTypes.size()));
          }
          else {
            holder.registerProblem(argumentList, JavaBundle.message(
              "inspection.reflection.invocation.argument.count", requiredTypes.size() + argumentOffset));
          }
          return;
        }

        for (int i = 0; i < requiredTypes.size(); i++) {
          final ReflectiveType requiredType = getReflectiveType(requiredTypes.get(i));
          if (requiredType != null) {
            final PsiExpression argument = actualArguments.expressions[i];
            if (argument != null) {
              PsiType actualType = argument.getType();
              if (TypeUtils.isJavaLangObject(actualType) && !requiredType.isAssignableFrom(actualType) &&
                  PsiPolyExpressionUtil.isPolyExpression(argument)) {
                // We make a copy here to avoid surrounding call affecting the inferred type,
                // as sometimes in complex expressions it causes the final type to be inferred to Object
                actualType = ((PsiExpression)argument.copy()).getType();
              }
              if (actualType != null && !requiredType.isAssignableFrom(actualType)) {
                if (PsiTreeUtil.isAncestor(argumentList, argument, false)) {
                  // either varargs or in-place arguments array
                  holder.registerProblem(argument, JavaBundle.message(actualArguments.varargAsArray
                                                                             ? "inspection.reflection.invocation.item.not.assignable"
                                                                             : "inspection.reflection.invocation.argument.not.assignable",
                                                                             requiredType.getQualifiedName()));
                }
                else {
                  // arguments array in a variable
                  final PsiExpression[] expressions = argumentList.getExpressions();
                  final PsiElement element = expressions.length == argumentOffset + 1 ? expressions[argumentOffset] : argumentList;
                  holder.registerProblem(element, JavaBundle.message(
                    "inspection.reflection.invocation.array.not.assignable", actualArguments.expressions.length));
                  break;
                }
              }
            }
          }
        }
      }
    }
  }
private static void checkReflectionCall(@NotNull PsiMethodCallExpression methodCall,
                                          int argumentOffset,
                                          @NotNull ProblemsHolder holder,
                                          @NotNull Predicate<? super PsiMethodCallExpression> methodPredicate)