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;
}