@Nullable
  private static MethodSignature getSignatureForInheritor(
      @NotNull PsiMethod methodFromSuperClass, @NotNull GrTypeDefinition inheritor) {
    final PsiClass clazz = methodFromSuperClass.getContainingClass();
    if (clazz == null) return null;
    PsiSubstitutor superSubstitutor =
        TypeConversionUtil.getClassSubstitutor(clazz, inheritor, PsiSubstitutor.EMPTY);
    if (superSubstitutor == null) return null;

    return methodFromSuperClass.getSignature(superSubstitutor);
  }
 static boolean isInheritorOrSelf(PsiMethod inheritorCandidate, PsiMethod base) {
   PsiClass aClass = inheritorCandidate.getContainingClass();
   PsiClass bClass = base.getContainingClass();
   if (aClass == null || bClass == null) return false;
   PsiSubstitutor substitutor =
       TypeConversionUtil.getClassSubstitutor(bClass, aClass, PsiSubstitutor.EMPTY);
   return substitutor != null
       && MethodSignatureUtil.findMethodBySignature(
               bClass, inheritorCandidate.getSignature(substitutor), false)
           == base;
 }
  public static String checkReturnType(
      PsiMethodReferenceExpression expression,
      JavaResolveResult result,
      PsiType functionalInterfaceType) {
    final PsiElement resolve = result.getElement();
    if (resolve instanceof PsiMethod) {
      final PsiClass containingClass = ((PsiMethod) resolve).getContainingClass();
      LOG.assertTrue(containingClass != null);
      PsiSubstitutor subst = result.getSubstitutor();
      PsiClass qContainingClass = getQualifierResolveResult(expression).getContainingClass();
      if (qContainingClass != null
          && isReceiverType(functionalInterfaceType, containingClass, (PsiMethod) resolve)) {
        subst = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, subst);
        LOG.assertTrue(subst != null);
      }

      final PsiType interfaceReturnType =
          LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType);

      PsiType returnType =
          PsiTypesUtil.patchMethodGetClassReturnType(
              expression,
              expression,
              (PsiMethod) resolve,
              null,
              PsiUtil.getLanguageLevel(expression));
      if (returnType == null) {
        returnType = ((PsiMethod) resolve).getReturnType();
      }
      PsiType methodReturnType = subst.substitute(returnType);
      if (interfaceReturnType != null && interfaceReturnType != PsiType.VOID) {
        if (methodReturnType == null) {
          methodReturnType =
              JavaPsiFacade.getElementFactory(expression.getProject())
                  .createType(containingClass, subst);
        }
        if (!TypeConversionUtil.isAssignable(interfaceReturnType, methodReturnType, false)) {
          return "Bad return type in method reference: cannot convert "
              + methodReturnType.getCanonicalText()
              + " to "
              + interfaceReturnType.getCanonicalText();
        }
      }
    }
    return null;
  }
 @Nullable
 public static PsiMethod findMethodBySuperMethod(
     @NotNull PsiClass aClass, @NotNull PsiMethod method, final boolean checkBases) {
   List<Pair<PsiMethod, PsiSubstitutor>> pairs =
       aClass.findMethodsAndTheirSubstitutorsByName(method.getName(), checkBases);
   for (Pair<PsiMethod, PsiSubstitutor> pair : pairs) {
     PsiMethod candidate = pair.first;
     PsiSubstitutor substitutor = pair.second;
     MethodSignature candidateSignature = candidate.getSignature(substitutor);
     final PsiClass methodClass = method.getContainingClass();
     final PsiClass candidateClass = candidate.getContainingClass();
     if (methodClass == null || candidateClass == null) continue;
     PsiSubstitutor superSubstitutor =
         TypeConversionUtil.getClassSubstitutor(methodClass, candidateClass, substitutor);
     if (superSubstitutor == null) continue;
     MethodSignature superSignature = method.getSignature(superSubstitutor);
     if (isSubsignature(superSignature, candidateSignature)) return candidate;
   }
   return null;
 }
 public static boolean isReceiverType(
     PsiType receiverType, @Nullable PsiClass containingClass, PsiSubstitutor psiSubstitutor) {
   if (containingClass != null) {
     receiverType = getExpandedType(receiverType, containingClass);
   }
   final PsiClassType.ClassResolveResult resolveResult =
       PsiUtil.resolveGenericsClassInType(receiverType);
   final PsiClass receiverClass = resolveResult.getElement();
   if (receiverClass != null && isReceiverType(receiverClass, containingClass)) {
     if (emptyOrRaw(containingClass, psiSubstitutor)) {
       return true;
     }
     final PsiSubstitutor derivedSubstitutor =
         TypeConversionUtil.getClassSubstitutor(containingClass, receiverClass, psiSubstitutor);
     return derivedSubstitutor != null
         && TypeConversionUtil.isAssignable(
             JavaPsiFacade.getElementFactory(containingClass.getProject())
                 .createType(containingClass, derivedSubstitutor),
             receiverType);
   }
   return false;
 }
  @Nullable
  public static String getSuspiciousMethodCallMessage(
      @NotNull PsiMethodCallExpression methodCall,
      PsiType argType,
      boolean reportConvertibleMethodCalls,
      @NotNull List<PsiMethod> patternMethods,
      @NotNull IntArrayList indices) {
    final PsiReferenceExpression methodExpression = methodCall.getMethodExpression();
    final PsiExpression qualifier = methodExpression.getQualifierExpression();
    if (qualifier == null
        || qualifier instanceof PsiThisExpression
        || qualifier instanceof PsiSuperExpression) return null;
    if (argType instanceof PsiPrimitiveType) {
      argType = ((PsiPrimitiveType) argType).getBoxedType(methodCall);
    }

    if (!(argType instanceof PsiClassType)) return null;

    final JavaResolveResult resolveResult = methodExpression.advancedResolve(false);
    PsiMethod calleeMethod = (PsiMethod) resolveResult.getElement();
    if (calleeMethod == null) return null;
    PsiMethod contextMethod = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class);

    //noinspection SynchronizationOnLocalVariableOrMethodParameter
    synchronized (patternMethods) {
      if (patternMethods.isEmpty()) {
        setupPatternMethods(
            methodCall.getManager(), methodCall.getResolveScope(), patternMethods, indices);
      }
    }

    for (int i = 0; i < patternMethods.size(); i++) {
      PsiMethod patternMethod = patternMethods.get(i);
      if (!patternMethod.getName().equals(methodExpression.getReferenceName())) continue;
      int index = indices.get(i);

      // we are in collections method implementation
      if (contextMethod != null && isInheritorOrSelf(contextMethod, patternMethod)) return null;

      final PsiClass calleeClass = calleeMethod.getContainingClass();
      PsiSubstitutor substitutor = resolveResult.getSubstitutor();
      final PsiClass patternClass = patternMethod.getContainingClass();
      assert patternClass != null;
      assert calleeClass != null;
      substitutor = TypeConversionUtil.getClassSubstitutor(patternClass, calleeClass, substitutor);
      if (substitutor == null) continue;

      if (!patternMethod
          .getSignature(substitutor)
          .equals(calleeMethod.getSignature(PsiSubstitutor.EMPTY))) continue;

      PsiTypeParameter[] typeParameters = patternClass.getTypeParameters();
      if (typeParameters.length <= index) return null;
      final PsiTypeParameter typeParameter = typeParameters[index];
      PsiType typeParamMapping = substitutor.substitute(typeParameter);
      if (typeParamMapping == null) return null;

      PsiParameter[] parameters = patternMethod.getParameterList().getParameters();
      if (parameters.length == 1 && "removeAll".equals(patternMethod.getName())) {
        PsiType paramType = parameters[0].getType();
        if (InheritanceUtil.isInheritor(paramType, CommonClassNames.JAVA_UTIL_COLLECTION)) {
          PsiType qualifierType = qualifier.getType();
          if (qualifierType != null) {
            final PsiType itemType =
                JavaGenericsUtil.getCollectionItemType(argType, calleeMethod.getResolveScope());
            final PsiType qualifierItemType =
                JavaGenericsUtil.getCollectionItemType(
                    qualifierType, calleeMethod.getResolveScope());
            if (qualifierItemType != null
                && itemType != null
                && !qualifierItemType.isAssignableFrom(itemType)) {
              return InspectionsBundle.message(
                  "inspection.suspicious.collections.method.calls.problem.descriptor",
                  PsiFormatUtil.formatType(qualifierType, 0, PsiSubstitutor.EMPTY),
                  PsiFormatUtil.formatType(itemType, 0, PsiSubstitutor.EMPTY));
            }
          }
          return null;
        }
      }

      String message = null;
      if (typeParamMapping instanceof PsiCapturedWildcardType) {
        typeParamMapping = ((PsiCapturedWildcardType) typeParamMapping).getWildcard();
      }
      if (!typeParamMapping.isAssignableFrom(argType)) {
        if (typeParamMapping.isConvertibleFrom(argType)) {
          if (reportConvertibleMethodCalls) {
            message =
                InspectionsBundle.message(
                    "inspection.suspicious.collections.method.calls.problem.descriptor1",
                    PsiFormatUtil.formatMethod(
                        calleeMethod,
                        substitutor,
                        PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_CONTAINING_CLASS,
                        PsiFormatUtilBase.SHOW_TYPE));
          }
        } else {
          PsiType qualifierType = qualifier.getType();
          if (qualifierType != null) {
            message =
                InspectionsBundle.message(
                    "inspection.suspicious.collections.method.calls.problem.descriptor",
                    PsiFormatUtil.formatType(qualifierType, 0, PsiSubstitutor.EMPTY),
                    PsiFormatUtil.formatType(argType, 0, PsiSubstitutor.EMPTY));
          }
        }
      }
      return message;
    }
    return null;
  }