private static @Nullable PsiMethod generateStaticFactory(@Nullable PsiMethod constructor,
                                                           PsiClass containingClass,
                                                           PsiTypeParameter[] typeParameters,
                                                           PsiJavaCodeReferenceElement reference) {
    final StringBuilder buf = new StringBuilder();
    final String modifier = VisibilityUtil.getVisibilityModifier(constructor != null ? constructor.getModifierList() : containingClass.getModifierList());
    if (!PsiModifier.PACKAGE_LOCAL.equals(modifier)) {
      buf.append(modifier);
      buf.append(" ");
    }
    buf.append("static <");
    //it's possible that constructor type parameters and class type parameters are same named:
    //it's important that class type parameters names are preserved (they are first in the list),
    //though constructor parameters would be renamed in case of conflicts
    final UniqueNameGenerator generator = new UniqueNameGenerator();
    buf.append(StringUtil.join(typeParameters, typeParameter -> {
      String result = generator.generateUniqueName(typeParameter.getName());
      final PsiClassType[] extendsListTypes = typeParameter.getSuperTypes();
      if (extendsListTypes.length > 0 &&
          (extendsListTypes.length != 1 || !CommonClassNames.JAVA_LANG_OBJECT.equals(extendsListTypes[0].getCanonicalText()))) {
        result += " extends " + StringUtil.join(extendsListTypes, PsiType::getCanonicalText, "&");
      }
      return result;
    }, ", "));
    buf.append(">");

    final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(containingClass.getProject());

    String qualifiedName = containingClass.getQualifiedName();

    PsiElement qualifier = reference != null ? reference.getQualifier() : null;
    if (qualifier instanceof PsiJavaCodeReferenceElement) {
      final JavaResolveResult resolveResult = ((PsiJavaCodeReferenceElement)qualifier).advancedResolve(false);
      final PsiElement element = resolveResult.getElement();
      if (element instanceof PsiClass) {
        final String outerClassSubstitutedQName =
          elementFactory.createType((PsiClass)element, resolveResult.getSubstitutor()).getInternalCanonicalText();
        qualifiedName = outerClassSubstitutedQName + "." + containingClass.getName();
      }
    } else if (reference != null && qualifier == null && containingClass.getContainingClass() != null) {
      qualifiedName = null;
    }

    buf.append(qualifiedName != null ? qualifiedName : containingClass.getName());
    final PsiTypeParameter[] parameters = containingClass.getTypeParameters();
    buf.append("<");
    buf.append(StringUtil.join(parameters, psiTypeParameter -> psiTypeParameter.getName(), ", "));
    buf.append("> ");

    String staticFactoryName = "staticFactory";
    final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(containingClass.getProject());
    staticFactoryName = styleManager.suggestUniqueVariableName(staticFactoryName, containingClass, false);
    buf.append(staticFactoryName);
    if (constructor == null) {
      buf.append("()");
    }
    else {
      buf.append("(").append(StringUtil.join(constructor.getParameterList().getParameters(), new Function<PsiParameter, String>() {
        int myIdx;
        @Override
        public String fun(PsiParameter psiParameter) {
          return psiParameter.getType().getCanonicalText() + " p" + myIdx++;
        }
      }, ",")).append(")");
      PsiClassType[] types = constructor.getThrowsList().getReferencedTypes();
      if (types.length > 0) {
        buf.append("throws ").append(StringUtil.join(types, type -> type.getCanonicalText(), ", "));
      }
    }
    buf.append("{}");

    try {
      return elementFactory.createMethodFromText(buf.toString(), constructor != null ? constructor : containingClass);
    }
    catch (IncorrectOperationException e) {
      return null;
    }
  }
private static @Nullable PsiMethod generateStaticFactory(@Nullable PsiMethod constructor,
                                                           PsiClass containingClass,
                                                           PsiTypeParameter[] typeParameters,
                                                           PsiJavaCodeReferenceElement reference)