static List validate()

in litho-processor/src/main/java/com/facebook/litho/specmodels/model/PropValidation.java [306:473]


  static List<SpecModelValidationError> validate(
      SpecModel specModel,
      List<String> reservedPropNames,
      List<CommonPropModel> permittedCommonProps,
      EnumSet<RunMode> runMode) {
    final List<SpecModelValidationError> validationErrors = new ArrayList<>();

    final ImmutableList<PropModel> props = specModel.getProps();
    for (int i = 0, size = props.size(); i < size - 1; i++) {
      for (int j = i + 1; j < size; j++) {
        if (props.get(i).getName().equals(props.get(j).getName())) {
          validationErrors.add(
              new SpecModelValidationError(
                  props.get(i).getRepresentedObject(),
                  "The prop "
                      + props.get(i).getName()
                      + " is defined differently in different "
                      + "methods. Ensure that each instance of this prop is declared in the same "
                      + "way (this means having the same type, resType and values for isOptional, isCommonProp and overrideCommonPropBehavior)."));
        }
      }
    }

    for (PropModel prop : props) {
      if (!prop.isCommonProp() && prop.overrideCommonPropBehavior()) {
        validationErrors.add(
            new SpecModelValidationError(
                prop.getRepresentedObject(),
                "overrideCommonPropBehavior may only be true is isCommonProp is true."));
      }

      if (reservedPropNames.contains(prop.getName()) && !prop.isCommonProp()) {
        validationErrors.add(
            new SpecModelValidationError(
                prop.getRepresentedObject(),
                "'"
                    + prop.getName()
                    + "' is a reserved prop name used by the component's "
                    + "builder. Please use another name or add \"isCommonProp\" to the "
                    + "Prop's definition."));
      } else if (prop.isCommonProp()) {
        boolean validName = false;
        for (CommonPropModel commonPropModel : permittedCommonProps) {
          if (commonPropModel.name.equals(prop.getName())) {
            validName = true;
            if (!commonPropModel.type.equals(prop.getTypeName())) {
              validationErrors.add(
                  new SpecModelValidationError(
                      prop.getRepresentedObject(),
                      "A common prop with name "
                          + commonPropModel.name
                          + " must have type of: "
                          + commonPropModel.type));
            }
          }
        }

        if (!validName) {
          validationErrors.add(
              new SpecModelValidationError(
                  prop.getRepresentedObject(),
                  "Prop with isCommonProp and name "
                      + prop.getName()
                      + " is incorrectly defined - see PropValidation.java for a "
                      + "list of common props that may be used."));
        }
      }

      if (prop.hasVarArgs()) {
        TypeName typeName = prop.getTypeName();
        if (typeName instanceof ParameterizedTypeName) {
          ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) typeName;
          if (!parameterizedTypeName.rawType.equals(ClassNames.LIST)) {
            validationErrors.add(
                new SpecModelValidationError(
                    prop.getRepresentedObject(),
                    prop.getName() + " is a variable argument, and thus should be a List<> type."));
          }
        } else {
          validationErrors.add(
              new SpecModelValidationError(
                  prop.getRepresentedObject(),
                  prop.getName()
                      + " is a variable argument, and thus requires a parameterized List type."));
        }
      }

      TypeSpec typeSpec = prop.getTypeSpec();
      for (TypeName illegalPropType : ILLEGAL_PROP_TYPES) {

        if (typeSpec.isSameDeclaredType(illegalPropType)) {
          validationErrors.add(
              new SpecModelValidationError(
                  prop.getRepresentedObject(),
                  "Props may not be declared with argument type: "
                      + illegalPropType
                      + " or its inherited types."));
        } else if (!runMode.contains(RunMode.ABI) && typeSpec.isSubType(illegalPropType)) {
          validationErrors.add(
              new SpecModelValidationError(
                  prop.getRepresentedObject(),
                  "Props may not be declared with argument type: "
                      + illegalPropType
                      + " or its inherited types. "
                      + typeSpec.getTypeName()
                      + " is an inherited type of "
                      + illegalPropType));
        }
      }

      if (!prop.isOptional() && prop.hasDefault(specModel.getPropDefaults())) {
        validationErrors.add(
            new SpecModelValidationError(
                prop.getRepresentedObject(),
                prop.getName()
                    + " is not optional so it should not be declared with a default "
                    + "value."));
      }

      if ((prop.getResType() == ResType.DIMEN_SIZE
              || prop.getResType() == ResType.DIMEN_TEXT
              || prop.getResType() == ResType.DIMEN_OFFSET)
          && (MethodParamModelUtils.isAnnotatedWithExternalAnnotation(prop, ClassNames.PX)
              || MethodParamModelUtils.isAnnotatedWithExternalAnnotation(
                  prop, ClassNames.DIMENSION))) {
        validationErrors.add(
            new SpecModelValidationError(
                prop.getRepresentedObject(),
                "Props with resType "
                    + prop.getResType()
                    + " should not be annotated with "
                    + ClassNames.PX
                    + " or "
                    + ClassNames.DIMENSION
                    + ", since these annotations "
                    + "will automatically be added to the relevant builder methods in the "
                    + "generated code."));
      }

      validationErrors.addAll(validateResType(prop));
    }

    for (PropDefaultModel propDefault : specModel.getPropDefaults()) {
      final PropModel prop = SpecModelUtils.getPropWithName(specModel, propDefault.mName);
      if (prop == null) {
        validationErrors.add(
            new SpecModelValidationError(
                propDefault.mRepresentedObject,
                "PropDefault "
                    + propDefault.mName
                    + " of type "
                    + propDefault.mType
                    + " does not correspond to any defined prop"));
      } else if (!(propDefault.mType.box()).equals(prop.getTypeName().box())) {
        validationErrors.add(
            new SpecModelValidationError(
                propDefault.mRepresentedObject,
                "PropDefault "
                    + propDefault.mName
                    + " of type "
                    + propDefault.mType
                    + " should be of type "
                    + prop.getTypeName()));
      }
    }

    return validationErrors;
  }