ublic Optional<PsiMethod> createToBuilderMethodIfNecessary(@NotNull PsiClass containingClass,
                                                              @Nullable PsiMethod psiMethod,
                                                              @NotNull PsiClass builderPsiClass,
                                                              @NotNull PsiAnnotation psiAnnotation) {
    if (!PsiAnnotationUtil.getBooleanAnnotationValue(psiAnnotation, TO_BUILDER_ANNOTATION_KEY, false)) {
      return Optional.empty();
    }

    final List<BuilderInfo> builderInfos = createBuilderInfos(psiAnnotation, containingClass, psiMethod, builderPsiClass);
    builderInfos.forEach(BuilderInfo::withObtainVia);

    final PsiType psiTypeWithGenerics;
    if (null != psiMethod) {
      psiTypeWithGenerics = calculateResultType(builderInfos, builderPsiClass, containingClass);
    }
    else {
      psiTypeWithGenerics = PsiClassUtil.getTypeWithGenerics(builderPsiClass);
    }

    final LombokLightMethodBuilder methodBuilder = new LombokLightMethodBuilder(containingClass.getManager(), TO_BUILDER_METHOD_NAME)
      .withMethodReturnType(psiTypeWithGenerics)
      .withContainingClass(containingClass)
      .withNavigationElement(psiAnnotation)
      .withModifier(getBuilderOuterAccessVisibility(psiAnnotation));

    final String toBuilderPrependStatements = builderInfos.stream()
      .map(BuilderInfo::renderToBuilderPrependStatement)
      .filter(Predicate.not(StringUtil::isEmpty))
      .collect(Collectors.joining("\n"));

    final String toBuilderMethodCalls = builderInfos.stream()
      .map(BuilderInfo::renderToBuilderCallWithPrependLogic)
      .filter(Predicate.not(StringUtil::isEmpty))
      .collect(() -> new StringJoiner(".", ".", "").setEmptyValue(""), StringJoiner::add, StringJoiner::merge)
      .toString();

    final String toBuilderAppendStatements = builderInfos.stream()
      .map(BuilderInfo::renderToBuilderAppendStatement)
      .filter(Predicate.not(StringUtil::isEmpty))
      .collect(Collectors.joining("\n"));

    final String canonicalText = psiTypeWithGenerics.getCanonicalText(false);
    final String blockText;
    if (toBuilderAppendStatements.isEmpty()) {
      blockText = toBuilderPrependStatements +
                  String.format("\nreturn new %s()%s;", canonicalText, toBuilderMethodCalls);
    }
    else {
      blockText = toBuilderPrependStatements +
                  String.format("\nfinal %s %s = new %s()%s;\n", canonicalText, BUILDER_TEMP_VAR, canonicalText, toBuilderMethodCalls) +
                  toBuilderAppendStatements +
                  String.format("\nreturn %s;", BUILDER_TEMP_VAR);
    }

    methodBuilder.withBodyText(blockText);

    createRelevantNonNullAnnotation(containingClass, methodBuilder);

    return Optional.of(methodBuilder);
  }

ublic Optional<PsiMethod> createToBuilderMethodIfNecessary(@NotNull PsiClass containingClass,
                                                              @Nullable PsiMethod psiMethod,
                                                              @NotNull PsiClass builderPsiClass,
                                                              @NotNull PsiAnnotation psiAnnotation) 