@Override
  public void pushDownToClass(PsiElement targetElement, PushDownData<MemberInfo, PsiMember> pushDownData) {
    final PsiElementFactory factory = JavaPsiFacade.getElementFactory(pushDownData.getSourceClass().getProject());
    final PsiClass targetClass = targetElement instanceof PsiClass ? (PsiClass)targetElement : null;
    if (targetClass == null) {
      return;
    }
    final PsiClass sourceClass = (PsiClass)pushDownData.getSourceClass();
    final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(sourceClass, targetClass, PsiSubstitutor.EMPTY);
    for (MemberInfo memberInfo : pushDownData.getMembersToMove()) {
      PsiMember member = memberInfo.getMember();
      final List<PsiReference> refsToRebind = new ArrayList<>();
      final PsiModifierList list = member.getModifierList();
      LOG.assertTrue(list != null);
      if (list.hasModifierProperty(PsiModifier.STATIC) && !PsiUtil.isLocalOrAnonymousClass(targetClass)) {
        for (final PsiReference reference : ReferencesSearch.search(member)) {
          final PsiElement element = reference.getElement();
          if (element instanceof PsiReferenceExpression) {
            final PsiExpression qualifierExpression = ((PsiReferenceExpression)element).getQualifierExpression();
            if (qualifierExpression == null) {
              continue;
            }
            if (qualifierExpression instanceof PsiReferenceExpression) {
              PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve();
              if (!(resolve instanceof PsiClass) || resolve != sourceClass) {
                continue;
              }
              if (pushDownData.preserveExternalLinks() && !PsiTreeUtil.isAncestor(targetElement, element, false)) {
                continue;
              }
              PsiClass inheritor = InheritanceUtil.findEnclosingInstanceInScope(sourceClass, element, Conditions.alwaysTrue(), false);
              if (inheritor != null && inheritor != targetClass) {
                //usages in other targets should be updated on corresponding turns
                continue;
              }
            }
          }
          refsToRebind.add(reference);
        }
      }
      if (member instanceof PsiField) {
        ((PsiField)member).normalizeDeclaration();
      }

      member = (PsiMember)member.copy();
      RefactoringUtil.renameConflictingTypeParameters(member, targetClass);
      RefactoringUtil.replaceMovedMemberTypeParameters(member, PsiUtil.typeParametersIterable(sourceClass), substitutor, factory);
      PsiMember newMember = null;
      if (member instanceof PsiField) {
        if (sourceClass.isInterface() && !targetClass.isInterface()) {
          PsiUtil.setModifierProperty(member, PsiModifier.PUBLIC, true);
          PsiUtil.setModifierProperty(member, PsiModifier.STATIC, true);
          PsiUtil.setModifierProperty(member, PsiModifier.FINAL, true);
        }
        newMember = (PsiMember)targetClass.add(member);
      }
      else if (member instanceof PsiMethod method) {
        PsiMethod methodBySignature = MethodSignatureUtil.findMethodBySuperSignature(targetClass, method.getSignature(substitutor), false);
        boolean pushMethodToClass = methodBySignature == null;
        if (pushMethodToClass) {
          if (Arrays.stream(targetClass.findMethodsBySignature(method, true))
            .map(m -> m.getContainingClass())
            .filter(Objects::nonNull).anyMatch(aClass -> aClass.isInheritor(sourceClass, true))) {
            continue;
          }
          newMember = (PsiMethod)targetClass.add(method);
          final PsiMethod oldMethod = (PsiMethod)memberInfo.getMember();
          if (sourceClass.isInterface() && !targetClass.isInterface()) {
            PsiUtil.setModifierProperty(newMember, PsiModifier.PUBLIC, true);
            if (oldMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
              if (oldMethod.getBody() == null) {
                RefactoringUtil.makeMethodAbstract(targetClass, (PsiMethod)newMember);
              }
            }
            else {
              PsiUtil.setModifierProperty(newMember, PsiModifier.DEFAULT, false);
            }
          }

          if (memberInfo.isToAbstract()) {
            if (newMember.hasModifierProperty(PsiModifier.PRIVATE)) {
              PsiUtil.setModifierProperty(newMember, PsiModifier.PROTECTED, true);
            }

            pushDownData.getCommentPolicy().processNewJavaDoc(((PsiMethod)newMember).getDocComment());
            OverrideImplementUtil.annotateOnOverrideImplement((PsiMethod)newMember, targetClass, (PsiMethod)memberInfo.getMember());
          }
        }
        else { //abstract method: remove @Override
          if (!memberInfo.isToAbstract()) {
            final PsiAnnotation annotation = AnnotationUtil.findAnnotation(methodBySignature, "java.lang.Override");
            if (annotation != null && !leaveOverrideAnnotation(sourceClass, substitutor, method)) {
              annotation.delete();
            }
            PsiParameter[] sourceParameters = method.getParameterList().getParameters();
            PsiParameter[] targetParameters = methodBySignature.getParameterList().getParameters();
            for (int i = 0; i < sourceParameters.length; i++) {
              GenerateMembersUtil.copyAnnotations(sourceParameters[i], targetParameters[i]);
            }
            GenerateMembersUtil.copyAnnotations(method, methodBySignature);
          }
          final PsiDocComment oldDocComment = method.getDocComment();
          if (oldDocComment != null) {
            final PsiDocComment docComment = methodBySignature.getDocComment();
            final int policy = pushDownData.getCommentPolicy().getJavaDocPolicy();
            if (policy == DocCommentPolicy.COPY || policy == DocCommentPolicy.MOVE) {
              if (docComment != null) {
                docComment.replace(oldDocComment);
              }
              else {
                methodBySignature.getParent().addBefore(oldDocComment, methodBySignature);
              }
            }
          }
          inlineSuperCall(memberInfo, methodBySignature);
        }
      }
      else if (member instanceof PsiClass) {
        if (sourceClass.isInterface() && !targetClass.isInterface()) {
          PsiUtil.setModifierProperty(member, PsiModifier.PUBLIC, true);
        }
        if (Boolean.FALSE.equals(memberInfo.getOverrides())) {
          final PsiClass psiClass = (PsiClass)memberInfo.getMember();
          PsiClassType classType = null;
          if (!targetClass.isInheritor(psiClass, false)) {
            final PsiClassType[] types = memberInfo.getSourceReferenceList().getReferencedTypes();
            for (PsiClassType type : types) {
              if (type.resolve() == psiClass) {
                classType = (PsiClassType)substitutor.substitute(type);
              }
            }
            PsiJavaCodeReferenceElement classRef = classType != null ? factory.createReferenceElementByType(classType) : factory.createClassReferenceElement(psiClass);
            PsiReferenceList extendsImplementsList = psiClass.isInterface() && !targetClass.isInterface()
                                                     ? targetClass.getImplementsList()
                                                     : targetClass.getExtendsList();
            if (extendsImplementsList != null) {
              extendsImplementsList.add(classRef);
            }
          }
        }
        else {
          newMember = (PsiMember)targetClass.add(member);
        }
      }
      else if (member instanceof PsiClassInitializer) {
        newMember = (PsiMember)targetClass.add(member);
      }

      if (newMember != null) {
        decodeRefs(sourceClass, newMember, targetClass);
        //rebind imports first
        refsToRebind.sort(Comparator.comparing(PsiReference::getElement, PsiUtil.BY_POSITION));
        for (PsiReference psiReference : refsToRebind) {
          JavaCodeStyleManager.getInstance(sourceClass.getProject()).shortenClassReferences(psiReference.bindToElement(newMember));
        }
        final JavaRefactoringListenerManager listenerManager = JavaRefactoringListenerManager.getInstance(newMember.getProject());
        ((JavaRefactoringListenerManagerImpl)listenerManager).fireMemberMoved(sourceClass, newMember);
      }
    }
  }
@Override
  public void pushDownToClass(PsiElement targetElement, PushDownData<MemberInfo, PsiMember> pushDownData)