/** signature should be changed for methods with type parameters */
 private void prepareMethodsChangeSignature(
     final PsiClass currentClass,
     final PsiElement memberToChangeSignature,
     final PsiType memberType) {
   if (memberToChangeSignature instanceof PsiMethod) {
     final PsiMethod method =
         MethodSignatureUtil.findMethodBySuperMethod(
             currentClass, (PsiMethod) memberToChangeSignature, true);
     if (method != null && method.getContainingClass() == currentClass) {
       myLabeler.addRoot(new TypeMigrationUsageInfo(method), memberType, method, false);
     }
   } else if (memberToChangeSignature instanceof PsiParameter
       && ((PsiParameter) memberToChangeSignature).getDeclarationScope() instanceof PsiMethod) {
     final PsiMethod superMethod =
         (PsiMethod) ((PsiParameter) memberToChangeSignature).getDeclarationScope();
     final int parameterIndex =
         superMethod.getParameterList().getParameterIndex((PsiParameter) memberToChangeSignature);
     final PsiMethod method =
         MethodSignatureUtil.findMethodBySuperMethod(currentClass, superMethod, true);
     if (method != null && method.getContainingClass() == currentClass) {
       final PsiParameter parameter = method.getParameterList().getParameters()[parameterIndex];
       if (!parameter.getType().equals(memberType)) {
         myLabeler.addRoot(new TypeMigrationUsageInfo(parameter), memberType, parameter, false);
       }
     }
   }
 }
  private static boolean isAppMain(PsiMethod psiMethod, RefMethod refMethod) {
    if (!refMethod.isStatic()) return false;
    if (!PsiType.VOID.equals(psiMethod.getReturnType())) return false;

    PsiMethod appMainPattern = ((RefMethodImpl) refMethod).getRefJavaManager().getAppMainPattern();
    if (MethodSignatureUtil.areSignaturesEqual(psiMethod, appMainPattern)) return true;

    PsiMethod appPremainPattern =
        ((RefMethodImpl) refMethod).getRefJavaManager().getAppPremainPattern();
    if (MethodSignatureUtil.areSignaturesEqual(psiMethod, appPremainPattern)) return true;

    PsiMethod appAgentmainPattern =
        ((RefMethodImpl) refMethod).getRefJavaManager().getAppAgentmainPattern();
    return MethodSignatureUtil.areSignaturesEqual(psiMethod, appAgentmainPattern);
  }
  @NotNull
  private static PsiMethod[] findSuperMethodsInternal(PsiMethod method, PsiClass parentClass) {
    List<MethodSignatureBackedByPsiMethod> outputMethods =
        findSuperMethodSignatures(method, parentClass, false);

    return MethodSignatureUtil.convertMethodSignaturesToMethods(outputMethods);
  }
 private static PsiSubstitutor calculateSubstitutor(
     PsiMethod derivedMethod, PsiMethod baseMethod) {
   PsiSubstitutor substitutor;
   if (derivedMethod.getManager().areElementsEquivalent(derivedMethod, baseMethod)) {
     substitutor = PsiSubstitutor.EMPTY;
   } else {
     final PsiClass baseClass = baseMethod.getContainingClass();
     final PsiClass derivedClass = derivedMethod.getContainingClass();
     if (baseClass != null
         && derivedClass != null
         && InheritanceUtil.isInheritorOrSelf(derivedClass, baseClass, true)) {
       final PsiSubstitutor superClassSubstitutor =
           TypeConversionUtil.getSuperClassSubstitutor(
               baseClass, derivedClass, PsiSubstitutor.EMPTY);
       final MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor);
       final MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY);
       final PsiSubstitutor superMethodSubstitutor =
           MethodSignatureUtil.getSuperMethodSignatureSubstitutor(
               methodSignature, superMethodSignature);
       substitutor =
           superMethodSubstitutor != null ? superMethodSubstitutor : superClassSubstitutor;
     } else {
       substitutor = PsiSubstitutor.EMPTY;
     }
   }
   return substitutor;
 }
Beispiel #5
0
    @Override
    public boolean isMemberEnabled(MemberInfo member) {
      final PsiClass currentSuperClass = getSuperClass();
      if (currentSuperClass == null) return true;
      if (myMemberInfoStorage.getDuplicatedMemberInfos(currentSuperClass).contains(member))
        return false;
      if (myMemberInfoStorage.getExtending(currentSuperClass).contains(member.getMember()))
        return false;
      final boolean isInterface = currentSuperClass.isInterface();
      if (!isInterface) return true;

      PsiElement element = member.getMember();
      if (element instanceof PsiClass && ((PsiClass) element).isInterface()) return true;
      if (element instanceof PsiField) {
        return ((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC);
      }
      if (element instanceof PsiMethod) {
        final PsiSubstitutor superSubstitutor =
            TypeConversionUtil.getSuperClassSubstitutor(
                currentSuperClass, myClass, PsiSubstitutor.EMPTY);
        final MethodSignature signature = ((PsiMethod) element).getSignature(superSubstitutor);
        final PsiMethod superClassMethod =
            MethodSignatureUtil.findMethodBySignature(currentSuperClass, signature, false);
        if (superClassMethod != null && !PsiUtil.isLanguageLevel8OrHigher(currentSuperClass))
          return false;
        return !((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC)
            || PsiUtil.isLanguageLevel8OrHigher(currentSuperClass);
      }
      return true;
    }
 public boolean isAvailable(
     @NotNull final Project project, final Editor editor, final PsiFile file) {
   return myMethod != null
       && myMethod.isValid()
       && myClass != null
       && myClass.isValid()
       && myClass.getManager().isInProject(myClass)
       && myText != null
       && MethodSignatureUtil.findMethodBySignature(myClass, myMethod, false) == null;
 }
 private static boolean isMultipleInterfacesImplementation(
     final PsiMethod method, PsiMethod originalMethod, final PsiElement[] allElementsToDelete) {
   final PsiMethod[] methods = method.findSuperMethods();
   for (PsiMethod superMethod : methods) {
     if (ArrayUtil.find(allElementsToDelete, superMethod) < 0
         && !MethodSignatureUtil.isSuperMethod(originalMethod, superMethod)) {
       return true;
     }
   }
   return false;
 }
 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 boolean isMainOrPremainMethod(@NotNull PsiMethod method) {
    if (!PsiType.VOID.equals(method.getReturnType())) return false;
    String name = method.getName();
    if (!("main".equals(name) || "premain".equals(name))) return false;

    PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
    MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY);
    try {
      MethodSignature main = createSignatureFromText(factory, "void main(String[] args);");
      if (MethodSignatureUtil.areSignaturesEqual(signature, main)) return true;
      MethodSignature premain =
          createSignatureFromText(
              factory, "void premain(String args, java.lang.instrument.Instrumentation i);");
      if (MethodSignatureUtil.areSignaturesEqual(signature, premain)) return true;
    } catch (IncorrectOperationException e) {
      LOG.error(e);
    }

    return false;
  }
 private static boolean callerSignatureIsAboutToChangeToo(
     final PsiMethod caller, final UsageInfo[] usages) {
   for (UsageInfo usage : usages) {
     if (usage instanceof MethodCallUsageInfo
         && MethodSignatureUtil.isSuperMethod(
             ((MethodCallUsageInfo) usage).getReferencedMethod(), caller)) {
       return true;
     }
   }
   return false;
 }
 @Nullable
 private static PsiMethod getMethod(PsiClass psiClass, MethodSignature methodSignature) {
   final PsiMethod[] methodsByName = psiClass.findMethodsByName(methodSignature.getName(), true);
   for (PsiMethod psiMethod : methodsByName) {
     if (MethodSignatureUtil.areSignaturesEqual(
         getMethodSignature(psiMethod, psiClass, psiMethod.getContainingClass()),
         methodSignature)) {
       return psiMethod;
     }
   }
   return null;
 }
Beispiel #12
0
    private boolean isOverridden(
        PsiClass inheritor, PsiMethod method, PsiMethod superMethod, PsiClass superInterface) {
      // calculate substitutor of containingClass --> inheritor
      PsiSubstitutor substitutor =
          TypeConversionUtil.getSuperClassSubstitutor(
              myContainingClass, inheritor, PsiSubstitutor.EMPTY);
      // calculate substitutor of inheritor --> superInterface
      substitutor =
          TypeConversionUtil.getSuperClassSubstitutor(superInterface, inheritor, substitutor);

      return MethodSignatureUtil.isSubsignature(
          superMethod.getSignature(substitutor), method.getSignature(PsiSubstitutor.EMPTY));
    }
 @Override
 public boolean setupDefaultValues(
     ChangeInfo changeInfo, Ref<UsageInfo[]> refUsages, Project project) {
   if (!(changeInfo instanceof JavaChangeInfo)) return true;
   for (UsageInfo usageInfo : refUsages.get()) {
     if (usageInfo instanceof GrMethodCallUsageInfo) {
       GrMethodCallUsageInfo methodCallUsageInfo = (GrMethodCallUsageInfo) usageInfo;
       if (methodCallUsageInfo.isToChangeArguments()) {
         final PsiElement element = methodCallUsageInfo.getElement();
         if (element == null) continue;
         final PsiMethod caller = RefactoringUtil.getEnclosingMethod(element);
         final boolean needDefaultValue =
             !((JavaChangeInfo) changeInfo).getMethodsToPropagateParameters().contains(caller);
         final PsiMethod referencedMethod = methodCallUsageInfo.getReferencedMethod();
         if (needDefaultValue
             && (caller == null
                 || referencedMethod == null
                 || !MethodSignatureUtil.isSuperMethod(referencedMethod, caller))) {
           final ParameterInfo[] parameters = changeInfo.getNewParameters();
           for (ParameterInfo parameter : parameters) {
             final String defaultValue = parameter.getDefaultValue();
             if (defaultValue == null && parameter.getOldIndex() == -1) {
               ((ParameterInfoImpl) parameter).setDefaultValue("");
               if (!ApplicationManager.getApplication().isUnitTestMode()) {
                 final PsiType type =
                     ((ParameterInfoImpl) parameter)
                         .getTypeWrapper()
                         .getType(element, element.getManager());
                 final DefaultValueChooser chooser =
                     new DefaultValueChooser(
                         project, parameter.getName(), PsiTypesUtil.getDefaultValueOfType(type));
                 chooser.show();
                 if (chooser.isOK()) {
                   if (chooser.feelLucky()) {
                     parameter.setUseAnySingleVariable(true);
                   } else {
                     ((ParameterInfoImpl) parameter).setDefaultValue(chooser.getDefaultValue());
                   }
                 } else {
                   return false;
                 }
               }
             }
           }
         }
       }
     }
   }
   return true;
 }
  @Override
  public boolean isAvailable(
      @NotNull Project project,
      @NotNull PsiFile file,
      @NotNull PsiElement startElement,
      @NotNull PsiElement endElement) {
    final PsiClass myClass = (PsiClass) startElement;

    return myMethodPrototype != null
        && myMethodPrototype.isValid()
        && myClass.isValid()
        && myClass.getManager().isInProject(myClass)
        && myText != null
        && MethodSignatureUtil.findMethodBySignature(myClass, myMethodPrototype, false) == null;
  }
 @Nullable
 private static List<MethodSignature> hasSubsignature(List<MethodSignature> signatures) {
   for (MethodSignature signature : signatures) {
     boolean subsignature = true;
     for (MethodSignature methodSignature : signatures) {
       if (!signature.equals(methodSignature)) {
         if (!MethodSignatureUtil.isSubsignature(signature, methodSignature)) {
           subsignature = false;
           break;
         }
       }
     }
     if (subsignature) return Collections.singletonList(signature);
   }
   return signatures;
 }
    private boolean shouldFixSuper(PsiMethod method) {
      for (PsiMember element : myMembersAfterMove) {
        if (element instanceof PsiMethod) {
          PsiMethod member = (PsiMethod) element;
          // if there is such member among moved members, super qualifier
          // should not be removed
          final PsiManager manager = method.getManager();
          if (manager.areElementsEquivalent(
                  member.getContainingClass(), method.getContainingClass())
              && MethodSignatureUtil.areSignaturesEqual(member, method)) {
            return false;
          }
        }
      }

      final PsiMethod methodFromSuper = myTargetSuperClass.findMethodBySignature(method, false);
      return methodFromSuper == null;
    }
  private static boolean isSuperMethod(
      PsiClass aClass,
      HierarchicalMethodSignature hierarchicalMethodSignature,
      HierarchicalMethodSignature superSignatureHierarchical) {
    PsiMethod superMethod = superSignatureHierarchical.getMethod();
    PsiClass superClass = superMethod.getContainingClass();
    PsiClass containingClass = hierarchicalMethodSignature.getMethod().getContainingClass();
    if (!superMethod.isConstructor()) {
      if (!aClass.equals(superClass)) {
        if (PsiUtil.isAccessible(aClass.getProject(), superMethod, aClass, aClass)) {
          if (MethodSignatureUtil.isSubsignature(
              superSignatureHierarchical, hierarchicalMethodSignature)) {
            if (superClass != null) {
              if (superClass.isInterface()
                  || CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) {
                if (superMethod.hasModifierProperty(PsiModifier.DEFAULT)
                    || hierarchicalMethodSignature
                        .getMethod()
                        .hasModifierProperty(PsiModifier.DEFAULT)) {
                  return !InheritanceUtil.isInheritorOrSelf(superClass, containingClass, true);
                }
                return true;
              }

              if (containingClass != null) {
                if (containingClass.isInterface()) {
                  return false;
                }

                if (!aClass.isInterface()
                    && !InheritanceUtil.isInheritorOrSelf(superClass, containingClass, true)) {
                  return true;
                }
              }
            }
          }
        }
      }
    }
    return false;
  }
  @Override
  public boolean isCallToSuperMethod(PsiExpression expression, PsiMethod method) {
    if (expression instanceof PsiMethodCallExpression) {
      PsiMethodCallExpression methodCall = (PsiMethodCallExpression) expression;
      if (methodCall.getMethodExpression().getQualifierExpression() instanceof PsiSuperExpression) {
        PsiMethod superMethod = (PsiMethod) methodCall.getMethodExpression().resolve();
        if (superMethod == null || !MethodSignatureUtil.areSignaturesEqual(method, superMethod))
          return false;
        PsiExpression[] args = methodCall.getArgumentList().getExpressions();
        PsiParameter[] parms = method.getParameterList().getParameters();

        for (int i = 0; i < args.length; i++) {
          PsiExpression arg = args[i];
          if (!(arg instanceof PsiReferenceExpression)) return false;
          if (!parms[i].equals(((PsiReferenceExpression) arg).resolve())) return false;
        }

        return true;
      }
    }

    return false;
  }
  private Specifics isMoreSpecific(
      @NotNull MethodCandidateInfo info1,
      @NotNull MethodCandidateInfo info2,
      @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel,
      @NotNull LanguageLevel languageLevel) {
    PsiMethod method1 = info1.getElement();
    PsiMethod method2 = info2.getElement();
    final PsiClass class1 = method1.getContainingClass();
    final PsiClass class2 = method2.getContainingClass();

    final PsiParameter[] params1 = method1.getParameterList().getParameters();
    final PsiParameter[] params2 = method2.getParameterList().getParameters();

    final PsiTypeParameter[] typeParameters1 = method1.getTypeParameters();
    final PsiTypeParameter[] typeParameters2 = method2.getTypeParameters();
    final PsiSubstitutor classSubstitutor1 =
        info1.getSubstitutor(false); // substitutions for method type parameters will be ignored
    final PsiSubstitutor classSubstitutor2 = info2.getSubstitutor(false);

    final int max = Math.max(params1.length, params2.length);
    PsiType[] types1 = PsiType.createArray(max);
    PsiType[] types2 = PsiType.createArray(max);
    final boolean varargsPosition =
        applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.VARARGS;
    for (int i = 0; i < max; i++) {
      ProgressManager.checkCanceled();
      PsiType type1 =
          params1.length > 0 ? params1[Math.min(i, params1.length - 1)].getType() : null;
      PsiType type2 =
          params2.length > 0 ? params2[Math.min(i, params2.length - 1)].getType() : null;
      if (varargsPosition) {
        if (type1 instanceof PsiEllipsisType
            && type2 instanceof PsiEllipsisType
            && params1.length == params2.length
            && class1 != null
            && (!JavaVersionService.getInstance().isAtLeast(class1, JavaSdkVersion.JDK_1_7)
                || ((PsiArrayType) type1)
                    .getComponentType()
                    .equalsToText(CommonClassNames.JAVA_LANG_OBJECT)
                || ((PsiArrayType) type2)
                    .getComponentType()
                    .equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) {
          type1 = ((PsiEllipsisType) type1).toArrayType();
          type2 = ((PsiEllipsisType) type2).toArrayType();
        } else {
          type1 =
              type1 instanceof PsiEllipsisType ? ((PsiArrayType) type1).getComponentType() : type1;
          type2 =
              type2 instanceof PsiEllipsisType ? ((PsiArrayType) type2).getComponentType() : type2;
        }
      }

      types1[i] = type1;
      types2[i] = type2;
    }

    boolean sameBoxing = true;
    int[] boxingHappened = new int[2];
    for (int i = 0; i < types1.length; i++) {
      ProgressManager.checkCanceled();
      PsiType type1 = classSubstitutor1.substitute(types1[i]);
      PsiType type2 = classSubstitutor2.substitute(types2[i]);
      PsiType argType = i < getActualParameterTypes().length ? getActualParameterTypes()[i] : null;

      boolean boxingInFirst = false;
      if (isBoxingHappened(argType, type1, languageLevel)) {
        boxingHappened[0] += 1;
        boxingInFirst = true;
      }

      boolean boxingInSecond = false;
      if (isBoxingHappened(argType, type2, languageLevel)) {
        boxingHappened[1] += 1;
        boxingInSecond = true;
      }
      sameBoxing &= boxingInFirst == boxingInSecond;
    }
    if (boxingHappened[0] == 0 && boxingHappened[1] > 0) return Specifics.FIRST;
    if (boxingHappened[0] > 0 && boxingHappened[1] == 0) return Specifics.SECOND;

    if (sameBoxing) {
      final PsiSubstitutor siteSubstitutor1 = info1.getSiteSubstitutor();
      final PsiSubstitutor siteSubstitutor2 = info2.getSiteSubstitutor();

      final PsiType[] types2AtSite = typesAtSite(types2, siteSubstitutor2);
      final PsiType[] types1AtSite = typesAtSite(types1, siteSubstitutor1);

      final PsiSubstitutor methodSubstitutor1 =
          calculateMethodSubstitutor(
              typeParameters1, method1, siteSubstitutor1, types1, types2AtSite, languageLevel);
      boolean applicable12 =
          isApplicableTo(
              types2AtSite, method1, languageLevel, varargsPosition, methodSubstitutor1, method2);

      final PsiSubstitutor methodSubstitutor2 =
          calculateMethodSubstitutor(
              typeParameters2, method2, siteSubstitutor2, types2, types1AtSite, languageLevel);
      boolean applicable21 =
          isApplicableTo(
              types1AtSite, method2, languageLevel, varargsPosition, methodSubstitutor2, method1);

      if (!myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
        final boolean typeArgsApplicable12 =
            GenericsUtil.isTypeArgumentsApplicable(
                typeParameters1, methodSubstitutor1, myArgumentsList, !applicable21);
        final boolean typeArgsApplicable21 =
            GenericsUtil.isTypeArgumentsApplicable(
                typeParameters2, methodSubstitutor2, myArgumentsList, !applicable12);

        if (!typeArgsApplicable12) {
          applicable12 = false;
        }

        if (!typeArgsApplicable21) {
          applicable21 = false;
        }
      }

      if (applicable12 || applicable21) {

        if (applicable12 && !applicable21) return Specifics.SECOND;
        if (applicable21 && !applicable12) return Specifics.FIRST;

        final boolean abstract1 = method1.hasModifierProperty(PsiModifier.ABSTRACT);
        final boolean abstract2 = method2.hasModifierProperty(PsiModifier.ABSTRACT);
        if (abstract1 && !abstract2) {
          return Specifics.SECOND;
        }
        if (abstract2 && !abstract1) {
          return Specifics.FIRST;
        }
      }

      if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)
          && myArgumentsList instanceof PsiExpressionList
          && (typeParameters1.length == 0 || typeParameters2.length == 0)) {
        boolean toCompareFunctional = false;
        if (types1.length > 0 && types2.length > 0) {
          for (int i = 0; i < getActualParametersLength(); i++) {
            final PsiType type1 = types1[Math.min(i, types1.length - 1)];
            final PsiType type2 = types2[Math.min(i, types2.length - 1)];
            // from 15.12.2.5 Choosing the Most Specific Method
            // In addition, a functional interface type S is more specific than a functional
            // interface type T for an expression exp
            // if T is not a subtype of S and one of the following conditions apply.
            if (LambdaUtil.isFunctionalType(type1)
                && !TypeConversionUtil.erasure(type1).isAssignableFrom(type2)
                && LambdaUtil.isFunctionalType(type2)
                && !TypeConversionUtil.erasure(type2).isAssignableFrom(type1)) {
              types1AtSite[Math.min(i, types1.length - 1)] = PsiType.NULL;
              types2AtSite[Math.min(i, types2.length - 1)] = PsiType.NULL;
              toCompareFunctional = true;
            }
          }
        }

        if (toCompareFunctional) {
          final boolean applicable12ignoreFunctionalType =
              isApplicableTo(
                  types2AtSite,
                  method1,
                  languageLevel,
                  varargsPosition,
                  calculateMethodSubstitutor(
                      typeParameters1,
                      method1,
                      siteSubstitutor1,
                      types1,
                      types2AtSite,
                      languageLevel),
                  null);
          final boolean applicable21ignoreFunctionalType =
              isApplicableTo(
                  types1AtSite,
                  method2,
                  languageLevel,
                  varargsPosition,
                  calculateMethodSubstitutor(
                      typeParameters2,
                      method2,
                      siteSubstitutor2,
                      types2,
                      types1AtSite,
                      languageLevel),
                  null);

          if (applicable12ignoreFunctionalType || applicable21ignoreFunctionalType) {
            Specifics specifics = null;
            for (int i = 0; i < getActualParametersLength(); i++) {
              if (types1AtSite[Math.min(i, types1.length - 1)] == PsiType.NULL
                  && types2AtSite[Math.min(i, types2.length - 1)] == PsiType.NULL) {
                Specifics specific =
                    isFunctionalTypeMoreSpecific(
                        info1, info2, ((PsiExpressionList) myArgumentsList).getExpressions()[i], i);
                if (specific == Specifics.NEITHER) {
                  specifics = Specifics.NEITHER;
                  break;
                }

                if (specifics == null) {
                  specifics = specific;
                } else if (specifics != specific) {
                  specifics = Specifics.NEITHER;
                  break;
                }
              }
            }

            if (!applicable12ignoreFunctionalType && applicable21ignoreFunctionalType) {
              return specifics == Specifics.FIRST ? Specifics.FIRST : Specifics.NEITHER;
            }

            if (!applicable21ignoreFunctionalType && applicable12ignoreFunctionalType) {
              return specifics == Specifics.SECOND ? Specifics.SECOND : Specifics.NEITHER;
            }

            return specifics;
          }
        }
      }
    } else if (varargsPosition) {
      final PsiType lastParamType1 = classSubstitutor1.substitute(types1[types1.length - 1]);
      final PsiType lastParamType2 = classSubstitutor2.substitute(types2[types1.length - 1]);
      final boolean assignable1 = TypeConversionUtil.isAssignable(lastParamType2, lastParamType1);
      final boolean assignable2 = TypeConversionUtil.isAssignable(lastParamType1, lastParamType2);
      if (assignable1 && !assignable2) {
        return Specifics.FIRST;
      }
      if (assignable2 && !assignable1) {
        return Specifics.SECOND;
      }
    }

    if (class1 != class2) {
      if (class2.isInheritor(class1, true) || class1.isInterface() && !class2.isInterface()) {
        if (MethodSignatureUtil.isSubsignature(
            method1.getSignature(info1.getSubstitutor(false)),
            method2.getSignature(info2.getSubstitutor(false)))) {
          return Specifics.SECOND;
        } else if (method1.hasModifierProperty(PsiModifier.STATIC)
            && method2.hasModifierProperty(PsiModifier.STATIC)
            && boxingHappened[0] == 0) {
          return Specifics.SECOND;
        }
      } else if (MethodSignatureUtil.areErasedParametersEqual(
              method1.getSignature(PsiSubstitutor.EMPTY),
              method2.getSignature(PsiSubstitutor.EMPTY))
          && MethodSignatureUtil.isSubsignature(
              method2.getSignature(info2.getSubstitutor(false)),
              method1.getSignature(info1.getSubstitutor(false)))) {
        return Specifics.FIRST;
      } else if (class1.isInheritor(class2, true) || class2.isInterface()) {
        if (method1.hasModifierProperty(PsiModifier.STATIC)
            && method2.hasModifierProperty(PsiModifier.STATIC)
            && boxingHappened[0] == 0) {
          return Specifics.FIRST;
        }
      }
    }

    final boolean raw1 = PsiUtil.isRawSubstitutor(method1, classSubstitutor1);
    final boolean raw2 = PsiUtil.isRawSubstitutor(method2, classSubstitutor2);
    if (raw1 ^ raw2) {
      return raw1 ? Specifics.SECOND : Specifics.FIRST;
    }

    final boolean varargs1 = info1.isVarargs();
    final boolean varargs2 = info2.isVarargs();
    if (varargs1 ^ varargs2) {
      return varargs1 ? Specifics.SECOND : Specifics.FIRST;
    }

    return Specifics.NEITHER;
  }
  private static void checkSuperclassMembers(
      PsiClass superClass,
      MemberInfoBase<? extends PsiMember>[] infos,
      MultiMap<PsiElement, String> conflictsList) {
    for (MemberInfoBase<? extends PsiMember> info : infos) {
      PsiMember member = info.getMember();
      boolean isConflict = false;
      if (member instanceof PsiField) {
        String name = member.getName();

        isConflict = superClass.findFieldByName(name, false) != null;
      } else if (member instanceof PsiMethod) {
        PsiSubstitutor superSubstitutor =
            TypeConversionUtil.getSuperClassSubstitutor(
                superClass, member.getContainingClass(), PsiSubstitutor.EMPTY);
        MethodSignature signature = ((PsiMethod) member).getSignature(superSubstitutor);
        final PsiMethod superClassMethod =
            MethodSignatureUtil.findMethodBySignature(superClass, signature, false);
        isConflict = superClassMethod != null;
      }

      if (isConflict) {
        String message =
            RefactoringBundle.message(
                "0.already.contains.a.1",
                RefactoringUIUtil.getDescription(superClass, false),
                RefactoringUIUtil.getDescription(member, false));
        message = CommonRefactoringUtil.capitalize(message);
        conflictsList.putValue(superClass, message);
      }

      if (member instanceof PsiMethod) {
        final PsiMethod method = (PsiMethod) member;
        final PsiModifierList modifierList = method.getModifierList();
        if (!modifierList.hasModifierProperty(PsiModifier.PRIVATE)) {
          for (PsiClass subClass : ClassInheritorsSearch.search(superClass)) {
            if (method.getContainingClass() != subClass) {
              MethodSignature signature =
                  ((PsiMethod) member)
                      .getSignature(
                          TypeConversionUtil.getSuperClassSubstitutor(
                              superClass, subClass, PsiSubstitutor.EMPTY));
              final PsiMethod wouldBeOverriden =
                  MethodSignatureUtil.findMethodBySignature(subClass, signature, false);
              if (wouldBeOverriden != null
                  && VisibilityUtil.compare(
                          VisibilityUtil.getVisibilityModifier(wouldBeOverriden.getModifierList()),
                          VisibilityUtil.getVisibilityModifier(modifierList))
                      > 0) {
                conflictsList.putValue(
                    wouldBeOverriden,
                    CommonRefactoringUtil.capitalize(
                        RefactoringUIUtil.getDescription(method, true)
                            + " in super class would clash with local method from "
                            + RefactoringUIUtil.getDescription(subClass, true)));
              }
            }
          }
        }
      }
    }
  }
  static void setupPatternMethods(
      PsiManager manager,
      GlobalSearchScope searchScope,
      List<PsiMethod> patternMethods,
      IntArrayList indices) {
    final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(manager.getProject());
    final PsiClass collectionClass =
        javaPsiFacade.findClass(CommonClassNames.JAVA_UTIL_COLLECTION, searchScope);
    PsiType[] javaLangObject = {PsiType.getJavaLangObject(manager, searchScope)};
    MethodSignature removeSignature =
        MethodSignatureUtil.createMethodSignature(
            "remove", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
    if (collectionClass != null) {
      PsiMethod remove =
          MethodSignatureUtil.findMethodBySignature(collectionClass, removeSignature, false);
      addMethod(remove, 0, patternMethods, indices);

      MethodSignature containsSignature =
          MethodSignatureUtil.createMethodSignature(
              "contains", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod contains =
          MethodSignatureUtil.findMethodBySignature(collectionClass, containsSignature, false);
      addMethod(contains, 0, patternMethods, indices);

      if (PsiUtil.isLanguageLevel5OrHigher(collectionClass)) {
        PsiClassType wildcardCollection =
            javaPsiFacade
                .getElementFactory()
                .createType(collectionClass, PsiWildcardType.createUnbounded(manager));
        MethodSignature removeAllSignature =
            MethodSignatureUtil.createMethodSignature(
                "removeAll",
                new PsiType[] {wildcardCollection},
                PsiTypeParameter.EMPTY_ARRAY,
                PsiSubstitutor.EMPTY);
        PsiMethod removeAll =
            MethodSignatureUtil.findMethodBySignature(collectionClass, removeAllSignature, false);
        addMethod(removeAll, 0, patternMethods, indices);
      }
    }

    final PsiClass listClass =
        javaPsiFacade.findClass(CommonClassNames.JAVA_UTIL_LIST, searchScope);
    if (listClass != null) {
      MethodSignature indexofSignature =
          MethodSignatureUtil.createMethodSignature(
              "indexOf", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod indexof =
          MethodSignatureUtil.findMethodBySignature(listClass, indexofSignature, false);
      addMethod(indexof, 0, patternMethods, indices);
      MethodSignature lastindexofSignature =
          MethodSignatureUtil.createMethodSignature(
              "lastIndexOf", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod lastindexof =
          MethodSignatureUtil.findMethodBySignature(listClass, lastindexofSignature, false);
      addMethod(lastindexof, 0, patternMethods, indices);
    }

    final PsiClass mapClass = javaPsiFacade.findClass(CommonClassNames.JAVA_UTIL_MAP, searchScope);
    if (mapClass != null) {
      PsiMethod remove =
          MethodSignatureUtil.findMethodBySignature(mapClass, removeSignature, false);
      addMethod(remove, 0, patternMethods, indices);
      MethodSignature getSignature =
          MethodSignatureUtil.createMethodSignature(
              "get", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod get = MethodSignatureUtil.findMethodBySignature(mapClass, getSignature, false);
      addMethod(get, 0, patternMethods, indices);
      MethodSignature containsKeySignature =
          MethodSignatureUtil.createMethodSignature(
              "containsKey", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod containsKey =
          MethodSignatureUtil.findMethodBySignature(mapClass, containsKeySignature, false);
      addMethod(containsKey, 0, patternMethods, indices);
      MethodSignature containsValueSignature =
          MethodSignatureUtil.createMethodSignature(
              "containsValue", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod containsValue =
          MethodSignatureUtil.findMethodBySignature(mapClass, containsValueSignature, false);
      addMethod(containsValue, 1, patternMethods, indices);
    }

    final PsiClass concurrentMapClass =
        javaPsiFacade.findClass(CommonClassNames.JAVA_UTIL_CONCURRENT_HASH_MAP, searchScope);
    if (concurrentMapClass != null) {
      MethodSignature containsSignature =
          MethodSignatureUtil.createMethodSignature(
              "contains", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod contains =
          MethodSignatureUtil.findMethodBySignature(concurrentMapClass, containsSignature, false);
      addMethod(contains, 1, patternMethods, indices);
    }
  }
  private void doMoveMethod(PsiSubstitutor substitutor, MemberInfo info) {
    PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject);
    PsiMethod method = (PsiMethod) info.getMember();
    PsiMethod sibling = method;
    PsiMethod anchor = null;
    while (sibling != null) {
      sibling = PsiTreeUtil.getNextSiblingOfType(sibling, PsiMethod.class);
      if (sibling != null) {
        anchor =
            MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(
                method.getContainingClass(),
                myTargetSuperClass,
                sibling.getSignature(PsiSubstitutor.EMPTY),
                false);
        if (anchor != null) {
          break;
        }
      }
    }
    PsiMethod methodCopy = (PsiMethod) method.copy();
    Language language = myTargetSuperClass.getLanguage();
    final PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(methodCopy, false);
    if (superClassMethod != null && superClassMethod.findDeepestSuperMethods().length == 0
        || method.findSuperMethods(myTargetSuperClass).length == 0) {
      deleteOverrideAnnotationIfFound(methodCopy);
    }
    boolean isOriginalMethodAbstract =
        method.hasModifierProperty(PsiModifier.ABSTRACT)
            || method.hasModifierProperty(PsiModifier.DEFAULT);
    boolean isOriginalMethodPrototype =
        method instanceof HaxeFunctionPrototypeDeclarationWithAttributes;
    if (myIsTargetInterface || info.isToAbstract()) {
      ChangeContextUtil.clearContextInfo(method);

      if (!info.isToAbstract()
          && !method.hasModifierProperty(PsiModifier.ABSTRACT)
          && PsiUtil.isLanguageLevel8OrHigher(myTargetSuperClass)) {
        // pull as default
        RefactoringUtil.makeMethodDefault(methodCopy);
        isOriginalMethodAbstract = true;
      } else {
        RefactoringUtil.makeMethodAbstract(myTargetSuperClass, methodCopy);
      }

      RefactoringUtil.replaceMovedMemberTypeParameters(
          methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);

      myJavaDocPolicy.processCopiedJavaDoc(
          methodCopy.getDocComment(), method.getDocComment(), isOriginalMethodAbstract);

      final PsiMember movedElement;
      if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
        movedElement =
            (PsiMember) superClassMethod.replace(convertMethodToLanguage(methodCopy, language));
      } else {
        methodCopy =
            HaxeElementGenerator.createFunctionPrototypeDeclarationWithAttributes(
                myProject, methodCopy.getText().trim() + ";");

        movedElement =
            anchor != null
                ? (PsiMember) myTargetSuperClass.addBefore(methodCopy, anchor)
                : (PsiMember)
                    myTargetSuperClass.addBefore(methodCopy, myTargetSuperClass.getRBrace());

        reformat(movedElement);
      }
      CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(method.getProject());
      if (styleSettings.INSERT_OVERRIDE_ANNOTATION) {
        if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myIsTargetInterface
            || PsiUtil.isLanguageLevel6OrHigher(mySourceClass)) {
          new AddAnnotationFix(Override.class.getName(), method)
              .invoke(method.getProject(), null, mySourceClass.getContainingFile());
        }
      }
      if (!PsiUtil.isLanguageLevel6OrHigher(mySourceClass) && myIsTargetInterface) {
        if (isOriginalMethodAbstract) {
          for (PsiMethod oMethod : OverridingMethodsSearch.search(method)) {
            deleteOverrideAnnotationIfFound(oMethod);
          }
        }
        deleteOverrideAnnotationIfFound(method);
      }
      myMembersAfterMove.add(movedElement);
      // if (isOriginalMethodAbstract) {
      method.delete();
      // }
    } else {
      if (isOriginalMethodAbstract) {
        PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true);
      }
      RefactoringUtil.replaceMovedMemberTypeParameters(
          methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
      fixReferencesToStatic(methodCopy);

      if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
        superClassMethod.replace(convertMethodToLanguage(methodCopy, language));
      } else {
        final PsiMember movedElement =
            anchor != null
                ? (PsiMember)
                    myTargetSuperClass.addBefore(
                        convertMethodToLanguage(methodCopy, language), anchor)
                : (PsiMember)
                    myTargetSuperClass.addBefore(
                        convertMethodToLanguage(methodCopy, language),
                        myTargetSuperClass.getRBrace());
        reformat(movedElement);
        myMembersAfterMove.add(movedElement);
      }
      method.delete();
    }
  }
  // uses hierarchy signature tree if available, traverses class structure by itself otherwise
  public static boolean isSuperMethodSmart(
      @NotNull PsiMethod method, @NotNull PsiMethod superMethod) {
    // boolean old = PsiSuperMethodUtil.isSuperMethod(method, superMethod);

    if (method == superMethod) return false;
    PsiClass aClass = method.getContainingClass();
    PsiClass superClass = superMethod.getContainingClass();

    if (aClass == null || superClass == null || superClass == aClass) return false;

    if (!canHaveSuperMethod(method, true, false)) return false;

    PsiMethod[] superMethods = null;
    Map<MethodSignature, HierarchicalMethodSignature> cachedMap =
        SIGNATURES_KEY.getCachedValueOrNull(aClass);
    if (cachedMap != null) {
      HierarchicalMethodSignature signature =
          cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY));
      if (signature != null) {
        superMethods =
            MethodSignatureUtil.convertMethodSignaturesToMethods(signature.getSuperSignatures());
      }
    }
    if (superMethods == null) {
      PsiClassType[] directSupers = aClass.getSuperTypes();
      List<PsiMethod> found = null;
      boolean canceled = false;
      for (PsiClassType directSuper : directSupers) {
        PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics();
        if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) {
          // generics
          canceled = true;
          break;
        }
        PsiClass directSuperClass = resolveResult.getElement();
        if (directSuperClass == null) continue;
        PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false);
        if (candidates.length != 0) {
          if (found == null) found = new ArrayList<PsiMethod>();
          for (PsiMethod candidate : candidates) {
            if (PsiUtil.canBeOverriden(candidate)) found.add(candidate);
          }
        }
      }
      superMethods =
          canceled
              ? null
              : found == null ? PsiMethod.EMPTY_ARRAY : found.toArray(new PsiMethod[found.size()]);
    }
    if (superMethods == null) {
      superMethods =
          MethodSignatureUtil.convertMethodSignaturesToMethods(
              method.getHierarchicalMethodSignature().getSuperSignatures());
    }

    for (PsiMethod superCandidate : superMethods) {
      if (superMethod.equals(superCandidate) || isSuperMethodSmart(superCandidate, superMethod))
        return true;
    }
    return false;
  }
  private static void setupPatternMethods(
      PsiManager manager,
      GlobalSearchScope searchScope,
      List<PsiMethod> patternMethods,
      IntArrayList indices) {
    final PsiClass collectionClass =
        JavaPsiFacade.getInstance(manager.getProject())
            .findClass("java.util.Collection", searchScope);
    PsiType[] javaLangObject = {PsiType.getJavaLangObject(manager, searchScope)};
    MethodSignature removeSignature =
        MethodSignatureUtil.createMethodSignature(
            "remove", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
    if (collectionClass != null) {
      PsiMethod remove =
          MethodSignatureUtil.findMethodBySignature(collectionClass, removeSignature, false);
      addMethod(remove, 0, patternMethods, indices);
      MethodSignature containsSignature =
          MethodSignatureUtil.createMethodSignature(
              "contains", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod contains =
          MethodSignatureUtil.findMethodBySignature(collectionClass, containsSignature, false);
      addMethod(contains, 0, patternMethods, indices);
    }

    final PsiClass listClass =
        JavaPsiFacade.getInstance(manager.getProject()).findClass("java.util.List", searchScope);
    if (listClass != null) {
      MethodSignature indexofSignature =
          MethodSignatureUtil.createMethodSignature(
              "indexOf", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod indexof =
          MethodSignatureUtil.findMethodBySignature(listClass, indexofSignature, false);
      addMethod(indexof, 0, patternMethods, indices);
      MethodSignature lastindexofSignature =
          MethodSignatureUtil.createMethodSignature(
              "lastIndexOf", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod lastindexof =
          MethodSignatureUtil.findMethodBySignature(listClass, lastindexofSignature, false);
      addMethod(lastindexof, 0, patternMethods, indices);
    }

    final PsiClass mapClass =
        JavaPsiFacade.getInstance(manager.getProject()).findClass("java.util.Map", searchScope);
    if (mapClass != null) {
      PsiMethod remove =
          MethodSignatureUtil.findMethodBySignature(mapClass, removeSignature, false);
      addMethod(remove, 0, patternMethods, indices);
      MethodSignature getSignature =
          MethodSignatureUtil.createMethodSignature(
              "get", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod get = MethodSignatureUtil.findMethodBySignature(mapClass, getSignature, false);
      addMethod(get, 0, patternMethods, indices);
      MethodSignature containsKeySignature =
          MethodSignatureUtil.createMethodSignature(
              "containsKey", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod containsKey =
          MethodSignatureUtil.findMethodBySignature(mapClass, containsKeySignature, false);
      addMethod(containsKey, 0, patternMethods, indices);
      MethodSignature containsValueSignature =
          MethodSignatureUtil.createMethodSignature(
              "containsValue", javaLangObject, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
      PsiMethod containsValue =
          MethodSignatureUtil.findMethodBySignature(mapClass, containsValueSignature, false);
      addMethod(containsValue, 1, patternMethods, indices);
    }
  }
  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;
              }
            }
          }
        }
      }
    }
  }
 public static boolean isExtendsSignature(
     MethodSignature superSignatureCandidate, MethodSignature subSignature) {
   return MethodSignatureUtil.isSubsignature(superSignatureCandidate, subSignature);
 }
  @Override
  protected void processIntention(@NotNull PsiElement element, Project project, Editor editor)
      throws IncorrectOperationException {
    final GrField field;
    if (element.getParent() instanceof GrField) {
      field = (GrField) element.getParent();
    } else {
      final PsiReference ref = element.getReference();
      LOG.assertTrue(ref != null);
      PsiElement resolved = ref.resolve();
      if (resolved instanceof GrAccessorMethod) {
        resolved = ((GrAccessorMethod) resolved).getProperty();
      }
      LOG.assertTrue(resolved instanceof GrField);
      field = (GrField) resolved;
    }

    final HashSet<PsiReference> usages = new HashSet<PsiReference>();
    usages.addAll(ReferencesSearch.search(field).findAll());
    final GrAccessorMethod[] getters = field.getGetters();
    for (GrAccessorMethod getter : getters) {
      usages.addAll(MethodReferencesSearch.search(getter).findAll());
    }
    final GrAccessorMethod setter = field.getSetter();
    if (setter != null) {
      usages.addAll(MethodReferencesSearch.search(setter).findAll());
    }

    final String fieldName = field.getName();
    LOG.assertTrue(fieldName != null);
    final Collection<PsiElement> fieldUsages = new HashSet<PsiElement>();
    MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
    for (PsiReference usage : usages) {
      final PsiElement psiElement = usage.getElement();
      if (PsiUtil.isMethodUsage(psiElement)) continue;
      if (!GroovyFileType.GROOVY_LANGUAGE.equals(psiElement.getLanguage())) {
        conflicts.putValue(
            psiElement,
            GroovyIntentionsBundle.message("closure.is.accessed.outside.of.groovy", fieldName));
      } else {
        if (psiElement instanceof GrReferenceExpression) {
          fieldUsages.add(psiElement);
          if (PsiUtil.isAccessedForWriting((GrExpression) psiElement)) {
            conflicts.putValue(
                psiElement,
                GroovyIntentionsBundle.message("write.access.to.closure.variable", fieldName));
          }
        } else if (psiElement instanceof GrArgumentLabel) {
          conflicts.putValue(
              psiElement,
              GroovyIntentionsBundle.message("field.is.used.in.argument.label", fieldName));
        }
      }
    }
    final PsiClass containingClass = field.getContainingClass();
    final GrExpression initializer = field.getInitializerGroovy();
    LOG.assertTrue(initializer != null);
    final PsiType type = initializer.getType();
    LOG.assertTrue(type instanceof GrClosureType);
    final GrSignature signature = ((GrClosureType) type).getSignature();
    final List<MethodSignature> signatures =
        GrClosureSignatureUtil.generateAllMethodSignaturesBySignature(fieldName, signature);
    for (MethodSignature s : signatures) {
      final PsiMethod method = MethodSignatureUtil.findMethodBySignature(containingClass, s, true);
      if (method != null) {
        conflicts.putValue(
            method,
            GroovyIntentionsBundle.message(
                "method.with.signature.already.exists",
                GroovyPresentationUtil.getSignaturePresentation(s)));
      }
    }
    if (conflicts.size() > 0) {
      final ConflictsDialog conflictsDialog =
          new ConflictsDialog(
              project,
              conflicts,
              new Runnable() {
                @Override
                public void run() {
                  execute(field, fieldUsages);
                }
              });
      conflictsDialog.show();
      if (conflictsDialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) return;
    }
    execute(field, fieldUsages);
  }
  private void doMoveMethod(PsiSubstitutor substitutor, GrMemberInfo info) {
    GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(myProject);
    GrMethod method = (GrMethod) info.getMember();
    PsiMethod sibling = method;
    PsiMethod anchor = null;
    while (sibling != null) {
      sibling = PsiTreeUtil.getNextSiblingOfType(sibling, PsiMethod.class);
      if (sibling != null) {
        anchor =
            MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(
                method.getContainingClass(),
                myTargetSuperClass,
                sibling.getSignature(PsiSubstitutor.EMPTY),
                false);
        if (anchor != null) {
          break;
        }
      }
    }

    GrMethod methodCopy = (GrMethod) method.copy();
    if (method.findSuperMethods(myTargetSuperClass).length == 0) {
      deleteOverrideAnnotationIfFound(methodCopy);
    }

    final boolean isOriginalMethodAbstract =
        method.hasModifierProperty(PsiModifier.ABSTRACT)
            || method.hasModifierProperty(PsiModifier.DEFAULT);
    if (myTargetSuperClass.isInterface() || info.isToAbstract()) {
      GroovyChangeContextUtil.clearContextInfo(method);
      RefactoringUtil.makeMethodAbstract(myTargetSuperClass, methodCopy);
      if (myTargetSuperClass.isInterface()) {
        PsiUtil.setModifierProperty(methodCopy, PsiModifier.ABSTRACT, false);
      }
      replaceMovedMemberTypeParameters(
          methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);

      final GrMethod movedElement =
          anchor != null
              ? (GrMethod) myTargetSuperClass.addBefore(methodCopy, anchor)
              : (GrMethod) myTargetSuperClass.add(methodCopy);
      CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(method.getProject());
      if (styleSettings.INSERT_OVERRIDE_ANNOTATION) {
        if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myTargetSuperClass.isInterface()
            || PsiUtil.isLanguageLevel6OrHigher(mySourceClass)) {
          new AddAnnotationFix(CommonClassNames.JAVA_LANG_OVERRIDE, method)
              .invoke(method.getProject(), null, mySourceClass.getContainingFile());
        }
      }

      GrDocComment oldDoc = method.getDocComment();
      if (oldDoc != null) {
        GrDocCommentUtil.setDocComment(movedElement, oldDoc);
      }

      myDocCommentPolicy.processCopiedJavaDoc(
          methodCopy.getDocComment(), oldDoc, isOriginalMethodAbstract);

      myMembersAfterMove.add(movedElement);
      if (isOriginalMethodAbstract) {
        deleteMemberWithDocComment(method);
      }
    } else {
      if (isOriginalMethodAbstract) {
        PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true);
      }

      // fixReferencesToStatic(methodCopy, movedMembers);
      replaceMovedMemberTypeParameters(
          methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
      final PsiMethod superClassMethod =
          myTargetSuperClass.findMethodBySignature(methodCopy, false);
      final GrMethod movedElement;
      if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
        movedElement = (GrMethod) superClassMethod.replace(methodCopy);
      } else {
        movedElement =
            anchor != null
                ? (GrMethod) myTargetSuperClass.addBefore(methodCopy, anchor)
                : (GrMethod) myTargetSuperClass.add(methodCopy);
        myMembersAfterMove.add(movedElement);
      }

      GrDocCommentUtil.setDocComment(movedElement, method.getDocComment());

      deleteMemberWithDocComment(method);
    }
  }
  private static void findParameterUsages(
      final PsiParameter parameter, final List<UsageInfo> usages) {
    final PsiMethod method = (PsiMethod) parameter.getDeclarationScope();
    final int parameterIndex = method.getParameterList().getParameterIndex(parameter);
    // search for refs to current method only, do not search for refs to overriding methods, they'll
    // be searched separately
    ReferencesSearch.search(method)
        .forEach(
            reference -> {
              PsiElement element = reference.getElement();
              if (element != null) {
                final JavaSafeDeleteDelegate safeDeleteDelegate =
                    JavaSafeDeleteDelegate.EP.forLanguage(element.getLanguage());
                if (safeDeleteDelegate != null) {
                  safeDeleteDelegate.createUsageInfoForParameter(
                      reference, usages, parameter, method);
                }
                if (!parameter.isVarArgs()
                    && !RefactoringChangeUtil.isSuperMethodCall(element.getParent())) {
                  final PsiParameter paramInCaller =
                      SafeDeleteJavaCallerChooser.isTheOnlyOneParameterUsage(
                          element.getParent(), parameterIndex, method);
                  if (paramInCaller != null) {
                    final PsiMethod callerMethod = (PsiMethod) paramInCaller.getDeclarationScope();
                    if (ApplicationManager.getApplication().isUnitTestMode()) {
                      usages.add(
                          new SafeDeleteParameterCallHierarchyUsageInfo(
                              callerMethod, paramInCaller, callerMethod));
                    } else {
                      usages.add(
                          new SafeDeleteParameterCallHierarchyUsageInfo(
                              method, parameter, callerMethod));
                    }
                  }
                }
              }
              return true;
            });

    ReferencesSearch.search(parameter)
        .forEach(
            reference -> {
              PsiElement element = reference.getElement();
              final PsiDocTag docTag = PsiTreeUtil.getParentOfType(element, PsiDocTag.class);
              if (docTag != null) {
                usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(docTag, parameter, true));
                return true;
              }

              boolean isSafeDelete = false;
              if (element.getParent().getParent() instanceof PsiMethodCallExpression) {
                PsiMethodCallExpression call =
                    (PsiMethodCallExpression) element.getParent().getParent();
                PsiReferenceExpression methodExpression = call.getMethodExpression();
                if (methodExpression.getText().equals(PsiKeyword.SUPER)) {
                  isSafeDelete = true;
                } else if (methodExpression.getQualifierExpression()
                    instanceof PsiSuperExpression) {
                  final PsiMethod superMethod = call.resolveMethod();
                  if (superMethod != null
                      && MethodSignatureUtil.isSuperMethod(superMethod, method)) {
                    isSafeDelete = true;
                  }
                }
              }

              usages.add(
                  new SafeDeleteReferenceJavaDeleteUsageInfo(element, parameter, isSafeDelete));
              return true;
            });

    findFunctionalExpressions(usages, method);
  }