private static MethodSpec generateDelegate()

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


  private static MethodSpec generateDelegate(
      SpecModel specModel,
      DelegateMethodDescription methodDescription,
      SpecMethodModel<DelegateMethod, Void> delegateMethod,
      EnumSet<RunMode> runMode) {
    final MethodSpec.Builder methodSpec =
        MethodSpec.methodBuilder(methodDescription.name)
            .addModifiers(methodDescription.accessType)
            .returns(methodDescription.returnType);

    for (AnnotationSpec annotation : methodDescription.annotations) {
      methodSpec.addAnnotation(annotation);
    }

    final ImmutableList<LifecycleMethodArgumentType> lifecycleArgs =
        methodDescription.lifecycleMethodArgumentTypes;
    final ImmutableList<MethodParamModel> delegateArgs = delegateMethod.methodParams;

    String contextParamName = null;
    String interStagePropsParamName = null;

    for (int i = 0, size = lifecycleArgs.size(); i < size; i++) {

      final TypeName lifecycleArg = lifecycleArgs.get(i).type;
      final TypeName delegateArg =
          delegateArgs.size() > i ? delegateArgs.get(i).getTypeName() : null;

      final String name;

      if (!lifecycleArg.equals(ClassNames.OBJECT) && !lifecycleArg.equals(delegateArg)) {
        name = "_" + i; // Use the counter to generate a placeholder name.
      } else {
        name = delegateArgs.get(i).getName(); // Use the name from the delegate method if its used.
      }

      // Cache the name of spec context argument.
      if (lifecycleArgs.get(i).type == specModel.getContextClass() && contextParamName == null) {
        contextParamName = name;
      }

      // Cache the name of spec context argument.
      if (lifecycleArgs.get(i).type == ClassNames.INTER_STAGE_PROPS_CONTAINER
          && interStagePropsParamName == null) {
        interStagePropsParamName = name;
      }

      methodSpec.addParameter(lifecycleArgs.get(i).type, name);
    }

    final boolean methodUsesDiffs =
        methodDescription.optionalParameterTypes.contains(DIFF_PROP)
            || methodDescription.optionalParameterTypes.contains(DIFF_STATE);
    final String componentName = specModel.getComponentName();

    for (TypeName exception : methodDescription.exceptions) {
      methodSpec.addException(exception);
    }

    if (methodUsesDiffs) {
      if (methodDescription.name.equals("shouldUpdate") && specModel instanceof HasPureRender) {
        methodSpec.addParameter(specModel.getComponentClass(), "_prevAbstractImpl");
        methodSpec.addParameter(specModel.getStateContainerClass(), "_prevStateContainer");
        methodSpec.addParameter(specModel.getComponentClass(), "_nextAbstractImpl");
        methodSpec.addParameter(specModel.getStateContainerClass(), "_nextStateContainer");

        methodSpec.beginControlFlow("if (!isPureRender())");
        methodSpec.addStatement("return true");
        methodSpec.endControlFlow();
      } else {
        methodSpec.addParameter(specModel.getContextClass(), "_prevScopedContext");
        methodSpec.addParameter(specModel.getComponentClass(), "_prevAbstractImpl");
        methodSpec.addParameter(specModel.getContextClass(), "_nextScopedContext");
        methodSpec.addParameter(specModel.getComponentClass(), "_nextAbstractImpl");
      }

      methodSpec.addStatement(
          "$L _prevImpl = ($L) _prevAbstractImpl", componentName, componentName);
      methodSpec.addStatement(
          "$L _nextImpl = ($L) _nextAbstractImpl", componentName, componentName);
    }

    if (!methodDescription.returnType.equals(TypeName.VOID)) {
      methodSpec.addStatement("$T _result", methodDescription.returnType);
    }

    methodSpec.addCode(
        getDelegationCode(
            specModel,
            delegateMethod,
            methodDescription,
            contextParamName,
            interStagePropsParamName,
            runMode));

    if (delegateMethod.name.toString().equals("onCreateLayout")
        || delegateMethod.name.toString().equals("onPrepare")) {
      SpecMethodModel<EventMethod, Void> registerRangesModel =
          specModel.getWorkingRangeRegisterMethod();

      if (registerRangesModel != null) {
        CodeBlock.Builder registerDelegation =
            CodeBlock.builder()
                .add(
                    "$L.$L(\n",
                    SpecModelUtils.getSpecAccessor(specModel),
                    registerRangesModel.name);

        registerDelegation.indent();
        for (int i = 0, size = registerRangesModel.methodParams.size(); i < size; i++) {
          final MethodParamModel methodParamModel = registerRangesModel.methodParams.get(i);
          registerDelegation.add(
              "($T) $L",
              methodParamModel.getTypeName(),
              getImplAccessor(specModel, methodDescription, methodParamModel, contextParamName));
          registerDelegation.add(
              (i < registerRangesModel.methodParams.size() - 1) ? ",\n" : ");\n");
        }
        registerDelegation.unindent();
        methodSpec.addCode(registerDelegation.build());
      }
    }

    if (!methodDescription.returnType.equals(TypeName.VOID)) {
      methodSpec.addStatement("return _result");
    }

    return methodSpec.build();
  }