private void tryToMoveInitializers(
      PsiMethod constructor,
      HashSet<PsiMethod> subConstructors,
      LinkedHashSet<PsiField> movedFields)
      throws IncorrectOperationException {
    final LinkedHashMap<PsiField, Initializer> fieldsToInitializers =
        new LinkedHashMap<PsiField, Initializer>();
    boolean anyFound = false;

    for (PsiField field : movedFields) {
      PsiStatement commonInitializer = null;
      final ArrayList<PsiElement> fieldInitializersToRemove = new ArrayList<PsiElement>();
      for (PsiMethod subConstructor : subConstructors) {
        commonInitializer =
            hasCommonInitializer(
                commonInitializer, subConstructor, field, fieldInitializersToRemove);
        if (commonInitializer == null) break;
      }
      if (commonInitializer != null) {
        final ParametersAndMovedFieldsUsedCollector visitor =
            new ParametersAndMovedFieldsUsedCollector(movedFields);
        commonInitializer.accept(visitor);
        fieldsToInitializers.put(
            field,
            new Initializer(
                commonInitializer,
                visitor.getUsedFields(),
                visitor.getUsedParameters(),
                fieldInitializersToRemove));
        anyFound = true;
      }
    }

    if (!anyFound) return;

    {
      final Set<PsiField> initializedFields = fieldsToInitializers.keySet();
      Set<PsiField> unmovable =
          RefactoringUtil.transitiveClosure(
              new RefactoringUtil.Graph<PsiField>() {
                public Set<PsiField> getVertices() {
                  return initializedFields;
                }

                public Set<PsiField> getTargets(PsiField source) {
                  return fieldsToInitializers.get(source).movedFieldsUsed;
                }
              },
              new Condition<PsiField>() {
                public boolean value(PsiField object) {
                  return !initializedFields.contains(object);
                }
              });

      for (PsiField psiField : unmovable) {
        fieldsToInitializers.remove(psiField);
      }
    }

    final PsiElementFactory factory = JavaPsiFacade.getElementFactory(myProject);

    if (constructor == null) {
      constructor = (PsiMethod) myTargetSuperClass.add(factory.createConstructor());
      final String visibilityModifier =
          VisibilityUtil.getVisibilityModifier(myTargetSuperClass.getModifierList());
      PsiUtil.setModifierProperty(constructor, visibilityModifier, true);
    }

    ArrayList<PsiField> initializedFields = new ArrayList<PsiField>(fieldsToInitializers.keySet());

    Collections.sort(
        initializedFields,
        new Comparator<PsiField>() {
          public int compare(PsiField field1, PsiField field2) {
            Initializer i1 = fieldsToInitializers.get(field1);
            Initializer i2 = fieldsToInitializers.get(field2);
            if (i1.movedFieldsUsed.contains(field2)) return 1;
            if (i2.movedFieldsUsed.contains(field1)) return -1;
            return 0;
          }
        });

    for (final PsiField initializedField : initializedFields) {
      Initializer initializer = fieldsToInitializers.get(initializedField);

      // correct constructor parameters and subConstructors super calls
      final PsiParameterList parameterList = constructor.getParameterList();
      for (final PsiParameter parameter : initializer.usedParameters) {
        parameterList.add(parameter);
      }

      for (final PsiMethod subConstructor : subConstructors) {
        modifySuperCall(subConstructor, initializer.usedParameters);
      }

      PsiStatement assignmentStatement =
          (PsiStatement) constructor.getBody().add(initializer.initializer);

      PsiManager manager = PsiManager.getInstance(myProject);
      ChangeContextUtil.decodeContextInfo(
          assignmentStatement,
          myTargetSuperClass,
          RefactoringChangeUtil.createThisExpression(manager, null));
      for (PsiElement psiElement : initializer.statementsToRemove) {
        psiElement.delete();
      }
    }
  }
  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);
  }