private static PsiMethod createFactoryMethod(@NotNull Project project,
                                               @NotNull PsiClass containingClass, @Nullable PsiMethod constructor,
                                               @NotNull String defaultFactoryName) {
    PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
    PsiClassType type = factory.createType(containingClass, PsiSubstitutor.EMPTY);
    PsiMethod factoryMethod = factory.createMethod(defaultFactoryName, type);
    if (constructor != null) {
      factoryMethod.getParameterList().replace(constructor.getParameterList());
      factoryMethod.getThrowsList().replace(constructor.getThrowsList());
    }

    Collection<String> names = new HashSet<>();
    for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(constructor != null ? constructor : containingClass)) {
      if (!names.contains(typeParameter.getName())) { //Otherwise type parameter is hidden in the constructor
        names.add(typeParameter.getName());
        Objects.requireNonNull(factoryMethod.getTypeParameterList()).addAfter(typeParameter, null);
      }
    }

    PsiReturnStatement returnStatement =
      (PsiReturnStatement)factory.createStatementFromText("return new A();", null);
    PsiNewExpression newExpression = (PsiNewExpression)Objects.requireNonNull(returnStatement.getReturnValue());
    PsiJavaCodeReferenceElement classRef = factory.createReferenceElementByType(type);
    Objects.requireNonNull(newExpression.getClassReference()).replace(classRef);
    PsiExpressionList argumentList = Objects.requireNonNull(newExpression.getArgumentList());

    PsiParameter[] params = factoryMethod.getParameterList().getParameters();

    for (PsiParameter parameter : params) {
      PsiExpression paramRef = factory.createExpressionFromText(parameter.getName(), null);
      argumentList.add(paramRef);
    }
    Objects.requireNonNull(factoryMethod.getBody()).add(returnStatement);

    PsiMember visibilityOwner = constructor == null ? containingClass : constructor;
    PsiUtil.setModifierProperty(factoryMethod, VisibilityUtil.getVisibilityModifier(visibilityOwner.getModifierList()), true);

    boolean inner = containingClass.getContainingClass() != null && !containingClass.hasModifierProperty(PsiModifier.STATIC);

    if (!inner) {
      PsiUtil.setModifierProperty(factoryMethod, PsiModifier.STATIC, true);
    }

    return (PsiMethod)CodeStyleManager.getInstance(project).reformat(factoryMethod);
  }
private static PsiMethod createFactoryMethod(@NotNull Project project,
                                               @NotNull PsiClass containingClass, @Nullable PsiMethod constructor,
                                               @NotNull String defaultFactoryName)