public static PsiType[] getErasedParameterTypes(MethodSignature signature) {
    PsiType[] parameterTypes = signature.getParameterTypes();
    if (parameterTypes.length == 0) return PsiType.EMPTY_ARRAY;

    PsiSubstitutor substitutor = signature.getSubstitutor();
    PsiType[] erasedTypes = new PsiType[parameterTypes.length];
    for (int i = 0; i < parameterTypes.length; i++) {
      erasedTypes[i] =
          TypeConversionUtil.erasure(substitutor.substitute(parameterTypes[i]), substitutor);
    }
    return erasedTypes;
  }
        @Override
        public int computeHashCode(final MethodSignature signature) {
          int result = signature.isConstructor() ? 0 : signature.getName().hashCode();

          PsiType[] parameterTypes = signature.getParameterTypes();
          result += 37 * parameterTypes.length;
          PsiType firstParamType = parameterTypes.length == 0 ? null : parameterTypes[0];
          if (firstParamType != null) {
            firstParamType = TypeConversionUtil.erasure(firstParamType, signature.getSubstitutor());
            assert firstParamType != null : parameterTypes[0];
            result = 31 * result + firstParamType.hashCode();
          }
          return result;
        }
  public static boolean isSubsignature(
      @NotNull MethodSignature superSignature, @NotNull MethodSignature subSignature) {
    if (subSignature == superSignature) return true;
    if (!areSignaturesEqualLightweight(superSignature, subSignature)) return false;
    PsiSubstitutor unifyingSubstitutor =
        getSuperMethodSignatureSubstitutor(subSignature, superSignature);
    if (checkSignaturesEqualInner(superSignature, subSignature, unifyingSubstitutor)) return true;

    if (subSignature.getTypeParameters().length > 0) return false;
    final PsiType[] subParameterTypes = subSignature.getParameterTypes();
    final PsiType[] superParameterTypes = superSignature.getParameterTypes();
    for (int i = 0; i < subParameterTypes.length; i++) {
      PsiType type1 = subParameterTypes[i];
      PsiType type2 =
          TypeConversionUtil.erasure(superParameterTypes[i], superSignature.getSubstitutor());
      if (!Comparing.equal(type1, type2)) return false;
    }
    return true;
  }
  @Nullable
  private static PsiSubstitutor getSuperMethodSignatureSubstitutorImpl(
      @NotNull MethodSignature methodSignature, @NotNull MethodSignature superSignature) {
    // normalize generic method declarations: correlate type parameters
    // todo: correlate type params by name?
    PsiTypeParameter[] methodTypeParameters = methodSignature.getTypeParameters();
    PsiTypeParameter[] superTypeParameters = superSignature.getTypeParameters();

    // both methods are parameterized and number of parameters mismatch
    if (methodTypeParameters.length != superTypeParameters.length) return null;

    PsiSubstitutor result = superSignature.getSubstitutor();
    for (int i = 0; i < methodTypeParameters.length; i++) {
      PsiTypeParameter methodTypeParameter = methodTypeParameters[i];
      PsiElementFactory factory =
          JavaPsiFacade.getInstance(methodTypeParameter.getProject()).getElementFactory();
      result = result.put(superTypeParameters[i], factory.createType(methodTypeParameter));
    }

    return result;
  }
  /**
   * @param methodSignature method signature
   * @param superMethodSignature super method signature
   * @return null if signatures do not match
   */
  @Nullable
  public static PsiSubstitutor getSuperMethodSignatureSubstitutor(
      @NotNull MethodSignature methodSignature, @NotNull MethodSignature superMethodSignature) {
    PsiSubstitutor result =
        getSuperMethodSignatureSubstitutorImpl(methodSignature, superMethodSignature);
    if (result == null) return null;

    PsiTypeParameter[] methodTypeParameters = methodSignature.getTypeParameters();
    PsiTypeParameter[] superTypeParameters = superMethodSignature.getTypeParameters();
    PsiSubstitutor methodSubstitutor = methodSignature.getSubstitutor();

    // check bounds
    for (int i = 0; i < methodTypeParameters.length; i++) {
      PsiTypeParameter methodTypeParameter = methodTypeParameters[i];
      PsiTypeParameter superTypeParameter = superTypeParameters[i];
      final Set<PsiType> methodSupers = new HashSet<PsiType>();
      for (PsiClassType methodSuper : methodTypeParameter.getSuperTypes()) {
        methodSupers.add(methodSubstitutor.substitute(methodSuper));
      }

      final Set<PsiType> superSupers = new HashSet<PsiType>();
      for (PsiClassType superSuper : superTypeParameter.getSuperTypes()) {
        superSupers.add(
            methodSubstitutor.substitute(
                PsiUtil.captureToplevelWildcards(
                    result.substitute(superSuper), methodTypeParameter)));
      }
      methodSupers.remove(
          PsiType.getJavaLangObject(
              methodTypeParameter.getManager(), methodTypeParameter.getResolveScope()));
      superSupers.remove(
          PsiType.getJavaLangObject(
              superTypeParameter.getManager(), superTypeParameter.getResolveScope()));
      if (!methodSupers.equals(superSupers)) return null;
    }

    return result;
  }
Пример #6
0
  public static boolean isAcceptable(
      PsiLambdaExpression lambdaExpression, final PsiType leftType, boolean checkReturnType) {
    if (leftType instanceof PsiIntersectionType) {
      for (PsiType conjunctType : ((PsiIntersectionType) leftType).getConjuncts()) {
        if (isAcceptable(lambdaExpression, conjunctType, checkReturnType)) return true;
      }
      return false;
    }
    final PsiClassType.ClassResolveResult resolveResult =
        PsiUtil.resolveGenericsClassInType(GenericsUtil.eliminateWildcards(leftType));
    final PsiClass psiClass = resolveResult.getElement();
    if (psiClass instanceof PsiAnonymousClass) {
      return isAcceptable(
          lambdaExpression, ((PsiAnonymousClass) psiClass).getBaseClassType(), checkReturnType);
    }
    final MethodSignature methodSignature = getFunction(psiClass);
    if (methodSignature == null) return false;
    final PsiParameter[] lambdaParameters = lambdaExpression.getParameterList().getParameters();
    final PsiType[] parameterTypes = methodSignature.getParameterTypes();
    if (lambdaParameters.length != parameterTypes.length) return false;
    for (int lambdaParamIdx = 0, length = lambdaParameters.length;
        lambdaParamIdx < length;
        lambdaParamIdx++) {
      PsiParameter parameter = lambdaParameters[lambdaParamIdx];
      final PsiTypeElement typeElement = parameter.getTypeElement();
      if (typeElement != null) {
        final PsiType lambdaFormalType = typeElement.getType();
        final PsiType methodParameterType = parameterTypes[lambdaParamIdx];
        if (lambdaFormalType instanceof PsiPrimitiveType) {
          if (methodParameterType instanceof PsiPrimitiveType)
            return methodParameterType.equals(lambdaFormalType);
          return false;
        }

        if (!TypeConversionUtil.erasure(lambdaFormalType)
            .isAssignableFrom(
                TypeConversionUtil.erasure(
                    GenericsUtil.eliminateWildcards(
                        resolveResult
                            .getSubstitutor()
                            .substitute(
                                methodSignature
                                    .getSubstitutor()
                                    .substitute(methodParameterType)))))) {
          return false;
        }
      }
    }
    if (checkReturnType) {
      final String uniqueVarName =
          JavaCodeStyleManager.getInstance(lambdaExpression.getProject())
              .suggestUniqueVariableName("l", lambdaExpression, true);
      String canonicalText = leftType.getCanonicalText();
      if (leftType instanceof PsiEllipsisType) {
        canonicalText = ((PsiEllipsisType) leftType).toArrayType().getCanonicalText();
      }
      final PsiStatement assignmentFromText =
          JavaPsiFacade.getElementFactory(lambdaExpression.getProject())
              .createStatementFromText(
                  canonicalText + " " + uniqueVarName + " = " + lambdaExpression.getText(),
                  lambdaExpression);
      final PsiLocalVariable localVariable =
          (PsiLocalVariable)
              ((PsiDeclarationStatement) assignmentFromText).getDeclaredElements()[0];
      LOG.assertTrue(psiClass != null);
      PsiType methodReturnType = getReturnType(psiClass, methodSignature);
      if (methodReturnType != null) {
        methodReturnType =
            resolveResult
                .getSubstitutor()
                .substitute(methodSignature.getSubstitutor().substitute(methodReturnType));
        return LambdaHighlightingUtil.checkReturnTypeCompatible(
                (PsiLambdaExpression) localVariable.getInitializer(), methodReturnType)
            == null;
      }
    }
    return true;
  }