Exemplo n.º 1
0
  @Nullable
  private String[] suggestVariableNameFromLiterals(
      PsiExpression expr, VariableKind variableKind, boolean correctKeywords) {
    final PsiElement[] literals =
        PsiTreeUtil.collectElements(
            expr,
            new PsiElementFilter() {
              @Override
              public boolean isAccepted(PsiElement element) {
                if (isStringPsiLiteral(element)
                    && StringUtil.isJavaIdentifier(StringUtil.unquoteString(element.getText()))) {
                  final PsiElement exprList = element.getParent();
                  if (exprList instanceof PsiExpressionList) {
                    final PsiElement call = exprList.getParent();
                    if (call instanceof PsiNewExpression) {
                      return true;
                    } else if (call instanceof PsiMethodCallExpression) {
                      // TODO: exclude or not getA().getB("name").getC(); or
                      // getA(getB("name").getC()); It works fine for now in the most cases
                      return true;
                    }
                  }
                }
                return false;
              }
            });

    if (literals.length == 1) {
      final String text = StringUtil.unquoteString(literals[0].getText());
      return getSuggestionsByName(
          text, variableKind, expr.getType() instanceof PsiArrayType, correctKeywords);
    }
    return null;
  }
  protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
    final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();

    checkExistingMethods(conflicts, true);
    checkExistingMethods(conflicts, false);
    final Collection<PsiClass> classes = ClassInheritorsSearch.search(myClass).findAll();
    for (FieldDescriptor fieldDescriptor : myFieldDescriptors) {
      final Set<PsiMethod> setters = new HashSet<PsiMethod>();
      final Set<PsiMethod> getters = new HashSet<PsiMethod>();

      for (PsiClass aClass : classes) {
        final PsiMethod getterOverrider =
            myDescriptor.isToEncapsulateGet()
                ? aClass.findMethodBySignature(fieldDescriptor.getGetterPrototype(), false)
                : null;
        if (getterOverrider != null) {
          getters.add(getterOverrider);
        }
        final PsiMethod setterOverrider =
            myDescriptor.isToEncapsulateSet()
                ? aClass.findMethodBySignature(fieldDescriptor.getSetterPrototype(), false)
                : null;
        if (setterOverrider != null) {
          setters.add(setterOverrider);
        }
      }
      if (!getters.isEmpty() || !setters.isEmpty()) {
        final PsiField field = fieldDescriptor.getField();
        for (PsiReference reference : ReferencesSearch.search(field)) {
          final PsiElement place = reference.getElement();
          if (place instanceof PsiReferenceExpression) {
            final PsiExpression qualifierExpression =
                ((PsiReferenceExpression) place).getQualifierExpression();
            final PsiClass ancestor;
            if (qualifierExpression == null) {
              ancestor = PsiTreeUtil.getParentOfType(place, PsiClass.class, false);
            } else {
              ancestor = PsiUtil.resolveClassInType(qualifierExpression.getType());
            }

            final boolean isGetter = !PsiUtil.isAccessedForWriting((PsiExpression) place);
            for (PsiMethod overridden : isGetter ? getters : setters) {
              if (InheritanceUtil.isInheritorOrSelf(myClass, ancestor, true)) {
                conflicts.putValue(
                    overridden,
                    "There is already a "
                        + RefactoringUIUtil.getDescription(overridden, true)
                        + " which would hide generated "
                        + (isGetter ? "getter" : "setter")
                        + " for "
                        + place.getText());
                break;
              }
            }
          }
        }
      }
    }
    return showConflicts(conflicts, refUsages.get());
  }
 private static String createInitializerReplacementText(
     PsiType varType, PsiExpression initializer) {
   final PsiType initializerType = initializer.getType();
   final PsiClassType rawType =
       initializerType instanceof PsiClassType
           ? ((PsiClassType) initializerType).rawType()
           : null;
   final PsiClassType rawVarType =
       varType instanceof PsiClassType ? ((PsiClassType) varType).rawType() : null;
   if (rawType != null
       && rawVarType != null
       && rawType.equalsToText(CommonClassNames.JAVA_UTIL_ARRAY_LIST)
       && rawVarType.equalsToText(CommonClassNames.JAVA_UTIL_LIST)) {
     return "toList()";
   } else if (rawType != null
       && rawVarType != null
       && rawType.equalsToText(CommonClassNames.JAVA_UTIL_HASH_SET)
       && rawVarType.equalsToText(CommonClassNames.JAVA_UTIL_SET)) {
     return "toSet()";
   } else if (rawType != null) {
     return "toCollection(" + rawType.getClassName() + "::new)";
   } else {
     return "toCollection(() -> " + initializer.getText() + ")";
   }
 }
Exemplo n.º 4
0
  private NamesByExprInfo suggestVariableNameByExpression(
      PsiExpression expr, VariableKind variableKind, boolean correctKeywords) {

    final LinkedHashSet<String> names = new LinkedHashSet<String>();
    final String[] fromLiterals =
        suggestVariableNameFromLiterals(expr, variableKind, correctKeywords);
    if (fromLiterals != null) {
      ContainerUtil.addAll(names, fromLiterals);
    }

    ContainerUtil.addAll(
        names,
        suggestVariableNameByExpressionOnly(expr, variableKind, correctKeywords, false).names);
    ContainerUtil.addAll(
        names, suggestVariableNameByExpressionPlace(expr, variableKind, correctKeywords).names);

    PsiType type = expr.getType();
    if (type != null) {
      ContainerUtil.addAll(names, suggestVariableNameByType(type, variableKind, correctKeywords));
    }
    ContainerUtil.addAll(
        names,
        suggestVariableNameByExpressionOnly(expr, variableKind, correctKeywords, true).names);

    String[] namesArray = ArrayUtil.toStringArray(names);
    String propertyName =
        suggestVariableNameByExpressionOnly(expr, variableKind, correctKeywords, false).propertyName
                != null
            ? suggestVariableNameByExpressionOnly(expr, variableKind, correctKeywords, false)
                .propertyName
            : suggestVariableNameByExpressionPlace(expr, variableKind, correctKeywords)
                .propertyName;
    return new NamesByExprInfo(propertyName, namesArray);
  }
Exemplo n.º 5
0
 private static boolean checkRawAcceptable(
     PsiLambdaExpression expression, PsiType functionalInterfaceType) {
   PsiElement parent = expression.getParent();
   while (parent instanceof PsiParenthesizedExpression) {
     parent = parent.getParent();
   }
   if (parent instanceof PsiExpressionList) {
     final PsiElement gParent = parent.getParent();
     if (gParent instanceof PsiMethodCallExpression) {
       final PsiExpression qualifierExpression =
           ((PsiMethodCallExpression) gParent).getMethodExpression().getQualifierExpression();
       final PsiType type = qualifierExpression != null ? qualifierExpression.getType() : null;
       if (type instanceof PsiClassType && ((PsiClassType) type).isRaw()) {
         return true;
       }
       final PsiMethod method = ((PsiMethodCallExpression) gParent).resolveMethod();
       if (method != null) {
         int lambdaIdx = getLambdaIdx((PsiExpressionList) parent, expression);
         final PsiParameter[] parameters = method.getParameterList().getParameters();
         final PsiType normalizedType =
             getNormalizedType(parameters[adjustLambdaIdx(lambdaIdx, method, parameters)]);
         if (normalizedType instanceof PsiClassType && ((PsiClassType) normalizedType).isRaw())
           return true;
       }
     }
     if (functionalInterfaceType instanceof PsiClassType
         && ((PsiClassType) functionalInterfaceType).isRaw()) {
       return false;
     }
   }
   return true;
 }
  private static boolean isGoodExpression(
      PsiExpression expression,
      @NotNull AllowedValues allowedValues,
      @NotNull PsiElement scope,
      @NotNull PsiManager manager) {
    expression = PsiUtil.deparenthesizeExpression(expression);
    if (expression == null) return true;
    if (expression instanceof PsiConditionalExpression) {
      PsiExpression thenExpression = ((PsiConditionalExpression) expression).getThenExpression();
      boolean thenAllowed =
          thenExpression == null || isAllowed(scope, thenExpression, allowedValues, manager);
      if (!thenAllowed) return false;
      PsiExpression elseExpression = ((PsiConditionalExpression) expression).getElseExpression();
      return elseExpression == null || isAllowed(scope, elseExpression, allowedValues, manager);
    }

    if (isOneOf(expression, allowedValues, manager)) return true;

    if (allowedValues.canBeOred) {
      PsiExpression zero = getLiteralExpression(expression, manager, "0");
      if (same(expression, zero, manager)) return true;
      PsiExpression mOne = getLiteralExpression(expression, manager, "-1");
      if (same(expression, mOne, manager)) return true;
      if (expression instanceof PsiPolyadicExpression) {
        IElementType tokenType = ((PsiPolyadicExpression) expression).getOperationTokenType();
        if (JavaTokenType.OR.equals(tokenType) || JavaTokenType.AND.equals(tokenType)) {
          for (PsiExpression operand : ((PsiPolyadicExpression) expression).getOperands()) {
            if (!isAllowed(scope, operand, allowedValues, manager)) return false;
          }
          return true;
        }
      }
      if (expression instanceof PsiPrefixExpression
          && JavaTokenType.TILDE.equals(
              ((PsiPrefixExpression) expression).getOperationTokenType())) {
        PsiExpression operand = ((PsiPrefixExpression) expression).getOperand();
        return operand == null || isAllowed(scope, operand, allowedValues, manager);
      }
    }

    PsiElement resolved = null;
    if (expression instanceof PsiReference) {
      resolved = ((PsiReference) expression).resolve();
    } else if (expression instanceof PsiCallExpression) {
      resolved = ((PsiCallExpression) expression).resolveMethod();
    }

    AllowedValues allowedForRef;
    if (resolved instanceof PsiModifierListOwner
        && (allowedForRef =
                getAllowedValues(
                    (PsiModifierListOwner) resolved,
                    getType((PsiModifierListOwner) resolved),
                    null))
            != null
        && allowedForRef.isSubsetOf(allowedValues, manager)) return true;

    return PsiType.NULL.equals(expression.getType());
  }
  private static boolean isCollectCall(PsiStatement body, final PsiParameter parameter) {
    PsiIfStatement ifStatement = extractIfStatement(body);
    final PsiMethodCallExpression methodCallExpression = extractAddCall(body, ifStatement);
    if (methodCallExpression != null) {
      final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
      final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
      PsiClass qualifierClass = null;
      if (qualifierExpression instanceof PsiReferenceExpression) {
        if (ReferencesSearch.search(parameter, new LocalSearchScope(qualifierExpression))
                .findFirst()
            != null) {
          return false;
        }
        final PsiElement resolve = ((PsiReferenceExpression) qualifierExpression).resolve();
        if (resolve instanceof PsiVariable) {
          if (ReferencesSearch.search(
                      resolve, new LocalSearchScope(methodCallExpression.getArgumentList()))
                  .findFirst()
              != null) {
            return false;
          }
        }
        qualifierClass = PsiUtil.resolveClassInType(qualifierExpression.getType());
      } else if (qualifierExpression == null) {
        final PsiClass enclosingClass = PsiTreeUtil.getParentOfType(body, PsiClass.class);
        if (PsiUtil.getEnclosingStaticElement(body, enclosingClass) == null) {
          qualifierClass = enclosingClass;
        }
      }

      if (qualifierClass != null
          && InheritanceUtil.isInheritor(
              qualifierClass, false, CommonClassNames.JAVA_UTIL_COLLECTION)) {

        while (ifStatement != null && PsiTreeUtil.isAncestor(body, ifStatement, false)) {
          final PsiExpression condition = ifStatement.getCondition();
          if (condition != null
              && isConditionDependsOnUpdatedCollections(condition, qualifierExpression))
            return false;
          ifStatement = PsiTreeUtil.getParentOfType(ifStatement, PsiIfStatement.class);
        }

        final PsiElement resolve = methodExpression.resolve();
        if (resolve instanceof PsiMethod
            && "add".equals(((PsiMethod) resolve).getName())
            && ((PsiMethod) resolve).getParameterList().getParametersCount() == 1) {
          final PsiExpression[] args = methodCallExpression.getArgumentList().getExpressions();
          if (args.length == 1) {
            if (args[0] instanceof PsiCallExpression) {
              final PsiMethod method = ((PsiCallExpression) args[0]).resolveMethod();
              return method != null && !method.hasTypeParameters() && !isThrowsCompatible(method);
            }
            return true;
          }
        }
      }
    }
    return false;
  }
Exemplo n.º 8
0
  @Override
  public SuggestedNameInfo suggestVariableName(
      @NotNull final VariableKind kind,
      @Nullable final String propertyName,
      @Nullable final PsiExpression expr,
      @Nullable PsiType type,
      final boolean correctKeywords) {
    LinkedHashSet<String> names = new LinkedHashSet<String>();

    if (expr != null && type == null) {
      type = expr.getType();
    }

    if (propertyName != null) {
      String[] namesByName = getSuggestionsByName(propertyName, kind, false, correctKeywords);
      sortVariableNameSuggestions(namesByName, kind, propertyName, null);
      ContainerUtil.addAll(names, namesByName);
    }

    final NamesByExprInfo namesByExpr;
    if (expr != null) {
      namesByExpr = suggestVariableNameByExpression(expr, kind, correctKeywords);
      if (namesByExpr.propertyName != null) {
        sortVariableNameSuggestions(namesByExpr.names, kind, namesByExpr.propertyName, null);
      }
      ContainerUtil.addAll(names, namesByExpr.names);
    } else {
      namesByExpr = null;
    }

    if (type != null) {
      String[] namesByType = suggestVariableNameByType(type, kind, correctKeywords);
      sortVariableNameSuggestions(namesByType, kind, null, type);
      ContainerUtil.addAll(names, namesByType);
    }

    final String _propertyName;
    if (propertyName != null) {
      _propertyName = propertyName;
    } else {
      _propertyName = namesByExpr != null ? namesByExpr.propertyName : null;
    }

    addNamesFromStatistics(names, kind, _propertyName, type);

    String[] namesArray = ArrayUtil.toStringArray(names);
    sortVariableNameSuggestions(namesArray, kind, _propertyName, type);

    final PsiType _type = type;
    return new SuggestedNameInfo(namesArray) {
      @Override
      public void nameChosen(String name) {
        if (_propertyName != null || _type != null && _type.isValid()) {
          JavaStatisticsManager.incVariableNameUseCount(name, kind, _propertyName, _type);
        }
      }
    };
  }
 private static String createMapperFunctionalExpressionText(
     PsiParameter parameter, PsiExpression expression) {
   String iteration = "";
   if (!isIdentityMapping(parameter, expression)) {
     iteration += ".map(";
     iteration +=
         compoundLambdaOrMethodReference(
             parameter,
             expression,
             "java.util.function.Function",
             new PsiType[] {parameter.getType(), expression.getType()});
     iteration += ")";
   }
   return iteration;
 }
 @NotNull
 public static QualifierResolveResult getQualifierResolveResult(
     @NotNull PsiMethodReferenceExpression methodReferenceExpression) {
   PsiClass containingClass = null;
   PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
   final PsiExpression expression = methodReferenceExpression.getQualifierExpression();
   if (expression != null) {
     final PsiType expressionType = getExpandedType(expression.getType(), expression);
     PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(expressionType);
     containingClass = result.getElement();
     if (containingClass != null) {
       substitutor = result.getSubstitutor();
     }
     if (containingClass == null && expression instanceof PsiReferenceExpression) {
       final JavaResolveResult resolveResult =
           ((PsiReferenceExpression) expression).advancedResolve(false);
       final PsiElement resolve = resolveResult.getElement();
       if (resolve instanceof PsiClass) {
         containingClass = (PsiClass) resolve;
         substitutor = resolveResult.getSubstitutor();
         return new QualifierResolveResult(containingClass, substitutor, true);
       }
     }
   } else {
     final PsiTypeElement typeElement = methodReferenceExpression.getQualifierType();
     if (typeElement != null) {
       PsiType type = getExpandedType(typeElement.getType(), typeElement);
       PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(type);
       containingClass = result.getElement();
       if (containingClass != null) {
         return new QualifierResolveResult(containingClass, result.getSubstitutor(), true);
       }
     }
   }
   return new QualifierResolveResult(containingClass, substitutor, 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;
  }
  private void checkExistingMethods(MultiMap<PsiElement, String> conflicts, boolean isGetter) {
    if (isGetter) {
      if (!myDescriptor.isToEncapsulateGet()) return;
    } else {
      if (!myDescriptor.isToEncapsulateSet()) return;
    }

    for (FieldDescriptor descriptor : myFieldDescriptors) {
      PsiMethod prototype =
          isGetter ? descriptor.getGetterPrototype() : descriptor.getSetterPrototype();

      final PsiType prototypeReturnType = prototype.getReturnType();
      PsiMethod existing = myClass.findMethodBySignature(prototype, true);
      if (existing != null) {
        final PsiType returnType = existing.getReturnType();
        if (!RefactoringUtil.equivalentTypes(
            prototypeReturnType, returnType, myClass.getManager())) {
          final String descr =
              PsiFormatUtil.formatMethod(
                  existing,
                  PsiSubstitutor.EMPTY,
                  PsiFormatUtilBase.SHOW_NAME
                      | PsiFormatUtilBase.SHOW_PARAMETERS
                      | PsiFormatUtilBase.SHOW_TYPE,
                  PsiFormatUtilBase.SHOW_TYPE);
          String message =
              isGetter
                  ? RefactoringBundle.message(
                      "encapsulate.fields.getter.exists",
                      CommonRefactoringUtil.htmlEmphasize(descr),
                      CommonRefactoringUtil.htmlEmphasize(prototype.getName()))
                  : RefactoringBundle.message(
                      "encapsulate.fields.setter.exists",
                      CommonRefactoringUtil.htmlEmphasize(descr),
                      CommonRefactoringUtil.htmlEmphasize(prototype.getName()));
          conflicts.putValue(existing, message);
        }
      } else {
        PsiClass containingClass = myClass.getContainingClass();
        while (containingClass != null && existing == null) {
          existing = containingClass.findMethodBySignature(prototype, true);
          if (existing != null) {
            for (PsiReference reference : ReferencesSearch.search(existing)) {
              final PsiElement place = reference.getElement();
              LOG.assertTrue(place instanceof PsiReferenceExpression);
              final PsiExpression qualifierExpression =
                  ((PsiReferenceExpression) place).getQualifierExpression();
              final PsiClass inheritor;
              if (qualifierExpression == null) {
                inheritor = PsiTreeUtil.getParentOfType(place, PsiClass.class, false);
              } else {
                inheritor = PsiUtil.resolveClassInType(qualifierExpression.getType());
              }

              if (InheritanceUtil.isInheritorOrSelf(inheritor, myClass, true)) {
                conflicts.putValue(
                    existing,
                    "There is already a "
                        + RefactoringUIUtil.getDescription(existing, true)
                        + " which would be hidden by generated "
                        + (isGetter ? "getter" : "setter"));
                break;
              }
            }
          }
          containingClass = containingClass.getContainingClass();
        }
      }
    }
  }
  protected void checkSameSignatures(@NotNull List<CandidateInfo> conflicts) {
    // candidates should go in order of class hierarchy traversal
    // in order for this to work
    Map<MethodSignature, CandidateInfo> signatures =
        new THashMap<MethodSignature, CandidateInfo>(conflicts.size());
    Set<PsiMethod> superMethods = new HashSet<PsiMethod>();
    for (CandidateInfo conflict : conflicts) {
      final PsiMethod method = ((MethodCandidateInfo) conflict).getElement();
      for (HierarchicalMethodSignature methodSignature :
          method.getHierarchicalMethodSignature().getSuperSignatures()) {
        final PsiMethod superMethod = methodSignature.getMethod();
        final PsiClass aClass = superMethod.getContainingClass();
        if (aClass != null
            && !CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) {
          superMethods.add(superMethod);
        }
      }
    }
    nextConflict:
    for (int i = 0; i < conflicts.size(); i++) {
      ProgressManager.checkCanceled();
      CandidateInfo info = conflicts.get(i);
      PsiMethod method = (PsiMethod) info.getElement();

      if (!method.hasModifierProperty(PsiModifier.STATIC) && superMethods.contains(method)) {
        conflicts.remove(i);
        i--;
        continue;
      }

      PsiClass class1 = method.getContainingClass();
      PsiSubstitutor infoSubstitutor = ((MethodCandidateInfo) info).getSubstitutor(false);
      MethodSignature signature = method.getSignature(infoSubstitutor);
      CandidateInfo existing = signatures.get(signature);

      if (existing == null) {
        signatures.put(signature, info);
        continue;
      }
      PsiMethod existingMethod = (PsiMethod) existing.getElement();
      PsiClass existingClass = existingMethod.getContainingClass();
      if (class1 != null
          && existingClass != null) { // prefer interface methods to methods from Object
        if (class1.isInterface()
            && CommonClassNames.JAVA_LANG_OBJECT.equals(existingClass.getQualifiedName())) {
          signatures.put(signature, info);
          continue;
        } else if (existingClass.isInterface()
            && CommonClassNames.JAVA_LANG_OBJECT.equals(class1.getQualifiedName())) {
          conflicts.remove(info);
          i--;
          continue;
        }
      }
      if (method == existingMethod) {
        PsiElement scope1 = info.getCurrentFileResolveScope();
        PsiElement scope2 = existing.getCurrentFileResolveScope();
        if (scope1 instanceof PsiClass
            && scope2 instanceof PsiClass
            && PsiTreeUtil.isAncestor(scope1, scope2, true)
            && !existing
                .isAccessible()) { // prefer methods from outer class to inaccessible base class
                                   // methods
          signatures.put(signature, info);
          continue;
        }
      }

      // filter out methods with incorrect inferred bounds (for unrelated methods only)
      boolean existingTypeParamAgree = areTypeParametersAgree(existing);
      boolean infoTypeParamAgree = areTypeParametersAgree(info);
      if (existingTypeParamAgree
          && !infoTypeParamAgree
          && !PsiSuperMethodImplUtil.isSuperMethodSmart(method, existingMethod)) {
        conflicts.remove(i);
        i--;
        continue;
      }
      if (!existingTypeParamAgree
          && infoTypeParamAgree
          && !PsiSuperMethodImplUtil.isSuperMethodSmart(existingMethod, method)) {
        signatures.put(signature, info);
        int index = conflicts.indexOf(existing);
        conflicts.remove(index);
        i--;
        continue;
      }

      if (InheritanceUtil.isInheritorOrSelf(class1, existingClass, true)
          || InheritanceUtil.isInheritorOrSelf(existingClass, class1, true)) {
        PsiParameter[] parameters = method.getParameterList().getParameters();
        final PsiParameter[] existingParameters = existingMethod.getParameterList().getParameters();
        for (int i1 = 0, parametersLength = parameters.length; i1 < parametersLength; i1++) {
          if (parameters[i1].getType() instanceof PsiArrayType
              && !(existingParameters[i1].getType()
                  instanceof PsiArrayType)) { // prefer more specific type
            signatures.put(signature, info);
            continue nextConflict;
          }
        }
        PsiType returnType1 = method.getReturnType();
        PsiType returnType2 = existingMethod.getReturnType();
        if (returnType1 != null && returnType2 != null) {
          returnType1 = infoSubstitutor.substitute(returnType1);
          returnType2 =
              ((MethodCandidateInfo) existing).getSubstitutor(false).substitute(returnType2);
          if (!returnType1.equals(returnType2) && returnType1.isAssignableFrom(returnType2)) {
            conflicts.remove(i);
            i--;
            continue;
          }
        }

        // prefer derived class
        signatures.put(signature, info);
      } else {
        final PsiMethodCallExpression methodCallExpression =
            PsiTreeUtil.getParentOfType(myArgumentsList, PsiMethodCallExpression.class);
        if (methodCallExpression != null) {
          final PsiReferenceExpression expression = methodCallExpression.getMethodExpression();
          final PsiExpression qualifierExpression = expression.getQualifierExpression();
          PsiClass currentClass;
          if (qualifierExpression != null) {
            currentClass = PsiUtil.resolveClassInClassTypeOnly(qualifierExpression.getType());
          } else {
            currentClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
          }

          if (currentClass != null && existingClass != null && class1 != null) {
            final PsiSubstitutor eSubstitutor =
                TypeConversionUtil.getMaybeSuperClassSubstitutor(
                    existingClass, currentClass, PsiSubstitutor.EMPTY, null);
            final PsiSubstitutor cSubstitutor =
                TypeConversionUtil.getMaybeSuperClassSubstitutor(
                    class1, currentClass, PsiSubstitutor.EMPTY, null);
            if (eSubstitutor != null
                && cSubstitutor != null
                && MethodSignatureUtil.areSignaturesEqual(
                    existingMethod.getSignature(eSubstitutor), method.getSignature(cSubstitutor))) {
              final PsiType returnType = eSubstitutor.substitute(existingMethod.getReturnType());
              final PsiType returnType1 = cSubstitutor.substitute(method.getReturnType());
              if (returnType != null && returnType1 != null && !returnType1.equals(returnType)) {
                if (TypeConversionUtil.isAssignable(returnType, returnType1, false)) {
                  if (class1.isInterface() && !existingClass.isInterface()) continue;
                  conflicts.remove(existing);
                } else {
                  if (!TypeConversionUtil.isAssignable(returnType1, returnType, false)) continue;
                  conflicts.remove(i);
                }
                i--;
                break;
              }
            }
          }
        }
      }
    }
  }
Exemplo n.º 14
0
  @Nullable
  public static PsiType getFunctionalInterfaceType(
      PsiElement expression, final boolean tryToSubstitute, int paramIdx) {
    PsiElement parent = expression.getParent();
    PsiElement element = expression;
    while (parent instanceof PsiParenthesizedExpression
        || parent instanceof PsiConditionalExpression) {
      if (parent instanceof PsiConditionalExpression
          && ((PsiConditionalExpression) parent).getThenExpression() != element
          && ((PsiConditionalExpression) parent).getElseExpression() != element) break;
      element = parent;
      parent = parent.getParent();
    }
    if (parent instanceof PsiArrayInitializerExpression) {
      final PsiType psiType = ((PsiArrayInitializerExpression) parent).getType();
      if (psiType instanceof PsiArrayType) {
        return ((PsiArrayType) psiType).getComponentType();
      }
    } else if (parent instanceof PsiTypeCastExpression) {
      final PsiType castType = ((PsiTypeCastExpression) parent).getType();
      if (castType instanceof PsiIntersectionType) {
        for (PsiType conjunctType : ((PsiIntersectionType) castType).getConjuncts()) {
          if (getFunctionalInterfaceMethod(conjunctType) != null) return conjunctType;
        }
      }
      return castType;
    } else if (parent instanceof PsiVariable) {
      return ((PsiVariable) parent).getType();
    } else if (parent instanceof PsiAssignmentExpression
        && expression instanceof PsiExpression
        && !PsiUtil.isOnAssignmentLeftHand((PsiExpression) expression)) {
      final PsiExpression lExpression = ((PsiAssignmentExpression) parent).getLExpression();
      return lExpression.getType();
    } else if (parent instanceof PsiExpressionList) {
      final PsiExpressionList expressionList = (PsiExpressionList) parent;
      final int lambdaIdx = getLambdaIdx(expressionList, expression);
      if (lambdaIdx > -1) {

        PsiType cachedType = null;
        final Pair<PsiMethod, PsiSubstitutor> method = MethodCandidateInfo.getCurrentMethod(parent);
        if (method != null) {
          final PsiParameter[] parameters = method.first.getParameterList().getParameters();
          cachedType =
              lambdaIdx < parameters.length
                  ? method.second.substitute(
                      getNormalizedType(
                          parameters[adjustLambdaIdx(lambdaIdx, method.first, parameters)]))
                  : null;
          if (!tryToSubstitute) return cachedType;
        }

        PsiElement gParent = expressionList.getParent();

        if (gParent instanceof PsiAnonymousClass) {
          gParent = gParent.getParent();
        }

        if (gParent instanceof PsiCall) {
          final PsiCall contextCall = (PsiCall) gParent;
          final JavaResolveResult resolveResult = contextCall.resolveMethodGenerics();
          final PsiElement resolve = resolveResult.getElement();
          if (resolve instanceof PsiMethod) {
            final PsiParameter[] parameters =
                ((PsiMethod) resolve).getParameterList().getParameters();
            final int finalLambdaIdx = adjustLambdaIdx(lambdaIdx, (PsiMethod) resolve, parameters);
            if (finalLambdaIdx < parameters.length) {
              if (!tryToSubstitute) return getNormalizedType(parameters[finalLambdaIdx]);
              if (cachedType != null && paramIdx > -1) {
                final PsiMethod interfaceMethod = getFunctionalInterfaceMethod(cachedType);
                if (interfaceMethod != null) {
                  final PsiClassType.ClassResolveResult cachedResult =
                      PsiUtil.resolveGenericsClassInType(cachedType);
                  final PsiType interfaceMethodParameterType =
                      interfaceMethod.getParameterList().getParameters()[paramIdx].getType();
                  if (!dependsOnTypeParams(
                      cachedResult.getSubstitutor().substitute(interfaceMethodParameterType),
                      cachedType,
                      expression)) {
                    return cachedType;
                  }
                }
              }
              return PsiResolveHelper.ourGuard.doPreventingRecursion(
                  expression,
                  true,
                  new Computable<PsiType>() {
                    @Override
                    public PsiType compute() {
                      return resolveResult
                          .getSubstitutor()
                          .substitute(getNormalizedType(parameters[finalLambdaIdx]));
                    }
                  });
            }
          }
          return null;
        }
      }
    } else if (parent instanceof PsiReturnStatement) {
      final PsiLambdaExpression gParent =
          PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class);
      if (gParent != null) {
        return getFunctionalInterfaceTypeByContainingLambda(gParent);
      } else {
        final PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class);
        if (method != null) {
          return method.getReturnType();
        }
      }
    } else if (parent instanceof PsiLambdaExpression) {
      return getFunctionalInterfaceTypeByContainingLambda((PsiLambdaExpression) parent);
    }
    return null;
  }