public static CodeBlock getDelegationCode()

in litho-processor/src/main/java/com/facebook/litho/specmodels/generator/DelegateMethodGenerator.java [249:438]


  public static CodeBlock getDelegationCode(
      SpecModel specModel,
      SpecMethodModel<DelegateMethod, Void> delegateMethod,
      DelegateMethodDescription methodDescription,
      @Nullable String contextParamName,
      @Nullable String interStagePropsParamName,
      EnumSet<RunMode> runMode) {
    final CodeBlock.Builder acquireStatements = CodeBlock.builder();
    final CodeBlock.Builder releaseStatements = CodeBlock.builder();

    final List<ParamTypeAndName> delegationParams =
        new ArrayList<>(delegateMethod.methodParams.size());

    final ImmutableList<TypeName> allowedParamTypes =
        methodDescription.allowedDelegateMethodArguments();

    // If null, find the first spec context from the delegate methods arguments.
    if (contextParamName == null) {
      contextParamName = getContextParamName(specModel, delegateMethod, methodDescription);
    }

    // Create a local variable for interstage props if they created or used.
    if (ComponentBodyGenerator.requiresInterStatePropContainer(
        delegateMethod.methodParams, methodDescription.optionalParameterTypes)) {
      acquireStatements.addStatement(
          "$L $L = $L",
          ClassNames.INTER_STAGE_PROPS_CONTAINER,
          ComponentBodyGenerator.LOCAL_INTER_STAGE_PROPS_CONTAINER_NAME,
          interStagePropsParamName != null ? interStagePropsParamName : "null");
    }

    final boolean requiresState =
        (methodDescription.createsState && !specModel.getStateValues().isEmpty())
            || delegateMethod.methodParams.stream().anyMatch(PREDICATE_NEEDS_STATE);

    if (requiresState && contextParamName != null) {
      acquireStatements.addStatement(
          "$L $L = $L",
          StateContainerGenerator.getStateContainerClassName(specModel),
          LOCAL_STATE_CONTAINER_NAME,
          STATE_CONTAINER_IMPL_GETTER + "(" + contextParamName + ")");
    }

    final Queue<TypeName> remainingAllowedTypes = new LinkedList<>(allowedParamTypes);
    int numberOfAllowedArgsUsed = 0;

    for (int i = 0, size = delegateMethod.methodParams.size(); i < size; i++) {
      final MethodParamModel methodParamModel = delegateMethod.methodParams.get(i);

      final boolean usesAllowedType =
          isAllowedTypeAndConsume(methodParamModel, remainingAllowedTypes);

      // Add delegate param if param type is allowed
      if (usesAllowedType) {
        numberOfAllowedArgsUsed++;
        delegationParams.add(
            ParamTypeAndName.create(methodParamModel.getTypeName(), methodParamModel.getName()));
      } else if (i < numberOfAllowedArgsUsed + methodDescription.optionalParameters.size()
          && shouldIncludeOptionalParameter(
              methodParamModel,
              methodDescription.optionalParameters.get(i - numberOfAllowedArgsUsed))) {
        final MethodParamModel extraDefinedParam =
            methodDescription.optionalParameters.get(i - numberOfAllowedArgsUsed);
        delegationParams.add(
            ParamTypeAndName.create(extraDefinedParam.getTypeName(), extraDefinedParam.getName()));
      } else if (methodParamModel instanceof DiffPropModel
          || methodParamModel instanceof DiffStateParamModel) {
        if (specModel instanceof HasPureRender
            && (methodParamModel instanceof StateParamModel
                || SpecModelUtils.getStateValueWithName(specModel, methodParamModel.getName())
                    != null)) {
          final String stateContainerClassNameWithTypeVars =
              StateGenerator.getStateContainerClassNameWithTypeVars(specModel);
          acquireStatements.addStatement(
              "$T $L = new $T(_prevImpl == null ? null : (($L) _prevStateContainer).$L, "
                  + "_nextImpl == null ? null : (($L) _nextStateContainer).$L)",
              methodParamModel.getTypeName(),
              methodParamModel.getName(),
              methodParamModel.getTypeName(),
              stateContainerClassNameWithTypeVars,
              methodParamModel.getName(),
              stateContainerClassNameWithTypeVars,
              methodParamModel.getName());
        } else {
          acquireStatements.addStatement(
              // Diff<type> name = new Diff<type>(...)
              "$T $L = new $T(_prevImpl == null ? null : _prevImpl.$L, "
                  + "_nextImpl == null ? null : _nextImpl.$L)",
              methodParamModel.getTypeName(),
              methodParamModel.getName(),
              methodParamModel.getTypeName(),
              ComponentBodyGenerator.getImplAccessor(
                  methodDescription.name, specModel, methodParamModel, "_prevScopedContext"),
              ComponentBodyGenerator.getImplAccessor(
                  methodDescription.name, specModel, methodParamModel, "_nextScopedContext"));
        }
        delegationParams.add(
            ParamTypeAndName.create(methodParamModel.getTypeName(), methodParamModel.getName()));
      } else if (isOutputType(methodParamModel.getTypeName())) {
        String localOutputName = methodParamModel.getName() + "Tmp";
        acquireStatements.add(
            "$T $L = new Output<>();\n", methodParamModel.getTypeName(), localOutputName);
        delegationParams.add(
            ParamTypeAndName.create(methodParamModel.getTypeName(), localOutputName));

        final boolean isPropOutput = SpecModelUtils.isPropOutput(specModel, methodParamModel);
        if (isPropOutput) {
          releaseStatements.beginControlFlow("if ($L.get() != null)", localOutputName);
        }
        releaseStatements.addStatement(
            "$L = $L.get()",
            getImplAccessor(specModel, methodDescription, methodParamModel, contextParamName),
            localOutputName);
        if (isPropOutput) {
          releaseStatements.endControlFlow();
        }
      } else if (isStateValueType(methodParamModel.getTypeName())) {
        acquireStatements.add(
            "$T $L = new StateValue<>();\n",
            methodParamModel.getTypeName(),
            methodParamModel.getName());
        delegationParams.add(
            ParamTypeAndName.create(methodParamModel.getTypeName(), methodParamModel.getName()));

        if (delegateMethod.name.toString().equals(LIFECYCLE_CREATE_INITIAL_STATE)) {
          releaseStatements.beginControlFlow("if ($L.get() != null)", methodParamModel.getName());
        }

        releaseStatements.addStatement(
            "$L = $L.get()",
            getImplAccessorFromContainer(
                methodDescription.name,
                specModel,
                methodParamModel,
                contextParamName,
                LOCAL_STATE_CONTAINER_NAME),
            methodParamModel.getName());

        if (delegateMethod.name.toString().equals(LIFECYCLE_CREATE_INITIAL_STATE)) {
          releaseStatements.endControlFlow();
        }

      } else if (methodParamModel instanceof RenderDataDiffModel) {
        final String diffName = "_" + methodParamModel.getName() + "Diff";
        CodeBlock block =
            CodeBlock.builder()
                // Diff<type> name = new Diff<type>(...)
                .add(
                    "$T $L = new $T(\n",
                    methodParamModel.getTypeName(),
                    diffName,
                    methodParamModel.getTypeName())
                .indent()
                .add(
                    "$L == null ? null : $L.$L,\n",
                    PREVIOUS_RENDER_DATA_FIELD_NAME,
                    PREVIOUS_RENDER_DATA_FIELD_NAME,
                    methodParamModel.getName())
                .add(
                    "$L);\n",
                    getImplAccessor(
                        methodDescription.name, specModel, methodParamModel, contextParamName))
                .unindent()
                .build();
        acquireStatements.add(block);
        delegationParams.add(ParamTypeAndName.create(methodParamModel.getTypeName(), diffName));
      } else {
        delegationParams.add(
            ParamTypeAndName.create(
                methodParamModel.getTypeName(),
                getImplAccessorFromContainer(
                    methodDescription.name,
                    specModel,
                    methodParamModel,
                    contextParamName,
                    LOCAL_STATE_CONTAINER_NAME)));
      }
    }

    return CodeBlock.builder()
        .add(acquireStatements.build())
        .add(
            getDelegationMethod(
                specModel,
                delegateMethod.name,
                methodDescription.returnType,
                ImmutableList.copyOf(delegationParams)))
        .add(releaseStatements.build())
        .build();
  }