private Collection<PsiMethod> addAllMethodsForBaseBuilderClass(@NotNull PsiClass psiClass, @NotNull PsiAnnotation psiAnnotation,
                                                                 @NotNull PsiClass baseClassBuilder, List<BuilderInfo> builderInfos,
                                                                 @NotNull PsiClassType bType, @NotNull PsiClassType cType) {
    final Collection<PsiMethod> result = new ArrayList<>();

    final Map<String, List<List<PsiType>>> existingMethodsWithParameters =
      BuilderHandler.getExistingMethodsWithParameterTypes(baseClassBuilder);

    // create builder methods
    for (BuilderInfo info : builderInfos) {
      result.addAll(info.renderBuilderMethods(existingMethodsWithParameters));
    }

    final PsiManager psiManager = psiClass.getManager();
    final boolean forceCallSuper = PsiClassUtil.hasSuperClass(psiClass);

    if (shouldGenerateToBuilderMethods(psiAnnotation)) {
      // precalculate obtainVia
      builderInfos.forEach(BuilderInfo::withObtainVia);

      final PsiClassType typeWithGenerics = PsiClassUtil.getTypeWithGenerics(psiClass);
      final PsiClassType typeWithWildcardsForSuperBuilderTypeParameters =
        getTypeWithWildcardsForSuperBuilderTypeParameters(baseClassBuilder);
      if (!BuilderHandler.matchMethodWithParams(existingMethodsWithParameters, STATIC_FILL_VALUES_METHOD_NAME,
                                                List.of(typeWithGenerics, typeWithWildcardsForSuperBuilderTypeParameters))) {
        // create '$fillValuesFromInstanceIntoBuilder' method
        final LombokLightMethodBuilder methodBuilder = new LombokLightMethodBuilder(psiManager, STATIC_FILL_VALUES_METHOD_NAME)
          .withMethodReturnType(PsiTypes.voidType())
          .withParameter(INSTANCE_VARIABLE_NAME, typeWithGenerics)
          .withParameter(BUILDER_VARIABLE_NAME, typeWithWildcardsForSuperBuilderTypeParameters)
          .withContainingClass(baseClassBuilder)
          .withNavigationElement(psiClass)
          .withModifier(PsiModifier.PRIVATE)
          .withModifier(PsiModifier.STATIC);
        addTypeParameters(psiClass, null, methodBuilder);

        final String toBuilderMethodCalls = builderInfos.stream()
          .map(BuilderInfo::renderToBuilderCallWithoutPrependLogic)
          .collect(Collectors.joining(';' + BUILDER_VARIABLE_NAME + '.', BUILDER_VARIABLE_NAME + '.', ";\n"));

        methodBuilder.withBodyText(toBuilderMethodCalls);
        result.add(methodBuilder);
      }

      if (!BuilderHandler.matchMethodWithParams(existingMethodsWithParameters, FILL_VALUES_METHOD_NAME, List.of(cType))) {
        // create '$fillValuesFrom' method
        final LombokLightMethodBuilder methodBuilder = new LombokLightMethodBuilder(psiManager, FILL_VALUES_METHOD_NAME)
          .withMethodReturnType(bType)
          .withParameter(INSTANCE_VARIABLE_NAME, cType)
          .withContainingClass(baseClassBuilder)
          .withNavigationElement(psiClass)
          .withModifier(PsiModifier.PROTECTED);

        final String callSuperCode = "super." + FILL_VALUES_METHOD_NAME + "(" + INSTANCE_VARIABLE_NAME + ");\n";
        final String codeBlockText = String.format("%s%s.%s(%s, this);\nreturn self();", forceCallSuper ? callSuperCode : "",
                                                   baseClassBuilder.getQualifiedName(), STATIC_FILL_VALUES_METHOD_NAME,
                                                   INSTANCE_VARIABLE_NAME);
        methodBuilder.withBodyText(codeBlockText);

        result.add(methodBuilder);
      }
    }

    if (!BuilderHandler.matchMethodWithParams(existingMethodsWithParameters, SELF_METHOD, Collections.emptyList())) {
      // create 'self' method
      final LombokLightMethodBuilder selfMethod = new LombokLightMethodBuilder(psiManager, SELF_METHOD)
        .withMethodReturnType(bType)
        .withContainingClass(baseClassBuilder)
        .withNavigationElement(psiClass)
        .withModifier(PsiModifier.ABSTRACT)
        .withModifier(PsiModifier.PROTECTED);
      result.add(selfMethod);
    }

    final String buildMethodName = getBuildMethodName(psiAnnotation);
    if (!BuilderHandler.matchMethodWithParams(existingMethodsWithParameters, buildMethodName, Collections.emptyList())) {
      // create 'build' method
      final LombokLightMethodBuilder buildMethod = new LombokLightMethodBuilder(psiManager, buildMethodName)
        .withMethodReturnType(cType)
        .withContainingClass(baseClassBuilder)
        .withNavigationElement(psiClass)
        .withModifier(PsiModifier.ABSTRACT)
        .withModifier(PsiModifier.PUBLIC);

      createRelevantNonNullAnnotation(psiClass, buildMethod);

      result.add(buildMethod);
    }

    if (!BuilderHandler.matchMethodWithParams(existingMethodsWithParameters, ToStringProcessor.TO_STRING_METHOD_NAME,
                                              Collections.emptyList())) {
      // create 'toString' method
      result.add(createToStringMethod(psiAnnotation, baseClassBuilder, forceCallSuper));
    }

    return result;
  }
private Collection<PsiMethod> addAllMethodsForBaseBuilderClass(@NotNull PsiClass psiClass, @NotNull PsiAnnotation psiAnnotation,
                                                                 @NotNull PsiClass baseClassBuilder, List<BuilderInfo> builderInfos,
                                                                 @NotNull PsiClassType bType, @NotNull PsiClassType cType)