def check_reply_field_type(ctxt: IDLCompatibilityContext, old_field_type: Optional[Union[syntax.Enum, syntax.Struct, syntax.Type]], new_field_type: Optional[Union[syntax.Enum, syntax.Struct, syntax.Type]], cmd_name: str, field_name: str, old_idl_file: syntax.IDLParsedSpec, new_idl_file: syntax.IDLParsedSpec, old_idl_file_path: str, new_idl_file_path: str): """Check compatibility between old and new reply field type.""" # pylint: disable=too-many-arguments,too-many-branches if old_field_type is None: ctxt.add_reply_field_type_invalid_error(cmd_name, field_name, old_idl_file_path) ctxt.errors.dump_errors() sys.exit(1) if new_field_type is None: ctxt.add_reply_field_type_invalid_error(cmd_name, field_name, new_idl_file_path) ctxt.errors.dump_errors() sys.exit(1) if isinstance(old_field_type, syntax.Type): if isinstance(new_field_type, syntax.Type): if "any" in old_field_type.bson_serialization_type: ctxt.add_old_reply_field_bson_any_error(cmd_name, field_name, old_field_type.name, old_idl_file_path) elif "any" in new_field_type.bson_serialization_type: ctxt.add_new_reply_field_bson_any_error(cmd_name, field_name, new_field_type.name, new_idl_file_path) else: check_subset(ctxt, cmd_name, field_name, new_field_type.name, new_field_type.bson_serialization_type, old_field_type.bson_serialization_type, new_idl_file_path) else: ctxt.add_new_reply_field_type_enum_or_struct_error( cmd_name, field_name, new_field_type.name, old_field_type.name, new_idl_file_path) elif isinstance(old_field_type, syntax.Enum): if isinstance(new_field_type, syntax.Enum): check_subset(ctxt, cmd_name, field_name, new_field_type.name, new_field_type.values, old_field_type.values, new_idl_file_path) else: ctxt.add_new_reply_field_type_not_enum_error(cmd_name, field_name, new_field_type.name, old_field_type.name, new_idl_file_path) elif isinstance(old_field_type, syntax.Struct): if isinstance(new_field_type, syntax.Struct): check_reply_fields(ctxt, old_field_type, new_field_type, cmd_name, old_idl_file, new_idl_file, old_idl_file_path, new_idl_file_path) else: ctxt.add_new_reply_field_type_not_struct_error( cmd_name, field_name, new_field_type.name, old_field_type.name, new_idl_file_path)
def check_reply_field_type_recursive( ctxt: IDLCompatibilityContext, old_field_type: syntax.Type, new_field_type: Optional[Union[syntax.Enum, syntax.Struct, syntax.Type]], cmd_name: str, field_name: str, old_idl_file: syntax.IDLParsedSpec, new_idl_file: syntax.IDLParsedSpec, old_idl_file_path: str, new_idl_file_path: str) -> None: # pylint: disable=too-many-arguments,too-many-branches """Check compatibility between old and new reply field type if old field type is a syntax.Type instance.""" if not isinstance(new_field_type, syntax.Type): ctxt.add_new_reply_field_type_enum_or_struct_error( cmd_name, field_name, new_field_type.name, old_field_type.name, new_idl_file_path) return if "any" in old_field_type.bson_serialization_type: ctxt.add_old_reply_field_bson_any_error(cmd_name, field_name, old_field_type.name, old_idl_file_path) return if "any" in new_field_type.bson_serialization_type: ctxt.add_new_reply_field_bson_any_error(cmd_name, field_name, new_field_type.name, new_idl_file_path) return if isinstance(old_field_type, syntax.VariantType): # If the new type is not variant just check the single type. new_variant_types = new_field_type.variant_types if isinstance( new_field_type, syntax.VariantType) else [new_field_type] old_variant_types = old_field_type.variant_types # Check that new variant types are a subset of old variant types. for new_variant_type in new_variant_types: old_variant_type_exists = False for old_variant_type in old_variant_types: if old_variant_type.name == new_variant_type.name: old_variant_type_exists = True # Check that the old and new version of each variant type is also compatible. check_reply_field_type_recursive( ctxt, old_variant_type, new_variant_type, cmd_name, field_name, old_idl_file, new_idl_file, old_idl_file_path, new_idl_file_path) if not old_variant_type_exists: ctxt.add_new_reply_field_variant_type_not_subset_error( cmd_name, field_name, new_field_type.name, new_idl_file_path) # If new type is variant and has a struct as a variant type, compare old and new variant_struct_type. # Since enums can't be part of variant types, we don't explicitly check for enums. if isinstance(new_field_type, syntax.VariantType) and new_field_type.variant_struct_type is not None: if old_field_type.variant_struct_type is None: ctxt.add_new_reply_field_variant_type_not_subset_error( cmd_name, field_name, new_field_type.variant_struct_type.name, new_idl_file_path) else: check_reply_fields(ctxt, old_field_type.variant_struct_type, new_field_type.variant_struct_type, cmd_name, old_idl_file, new_idl_file, old_idl_file_path, new_idl_file_path) else: if isinstance(new_field_type, syntax.VariantType): ctxt.add_new_reply_field_variant_type_error(cmd_name, field_name, old_field_type.name, new_field_type.name, new_idl_file_path) else: check_subset(ctxt, cmd_name, field_name, new_field_type.name, new_field_type.bson_serialization_type, old_field_type.bson_serialization_type, new_idl_file_path)
def check_reply_field_type_recursive( ctxt: IDLCompatibilityContext, old_field_type: syntax.Type, new_field_type: Optional[Union[syntax.Enum, syntax.Struct, syntax.Type]], cmd_name: str, field_name: str, old_idl_file: syntax.IDLParsedSpec, new_idl_file: syntax.IDLParsedSpec, old_idl_file_path: str, new_idl_file_path: str) -> None: # pylint: disable=too-many-arguments,too-many-branches """Check compatibility between old and new reply field type if old field type is a syntax.Type instance.""" if not isinstance(new_field_type, syntax.Type): ctxt.add_new_reply_field_type_enum_or_struct_error( cmd_name, field_name, new_field_type.name, old_field_type.name, new_idl_file_path) return # If bson_serialization_type switches from 'any' to non-any type. if "any" in old_field_type.bson_serialization_type and "any" not in new_field_type.bson_serialization_type: ctxt.add_old_reply_field_bson_any_error(cmd_name, field_name, old_field_type.name, old_idl_file_path) return # If bson_serialization_type switches from non-any to 'any' type. if "any" not in old_field_type.bson_serialization_type and "any" in new_field_type.bson_serialization_type: ctxt.add_new_reply_field_bson_any_error(cmd_name, field_name, old_field_type.name, new_idl_file_path) return allow_name: str = cmd_name + "-reply-" + field_name if "any" in old_field_type.bson_serialization_type: # If 'any' is not explicitly allowed as the bson_serialization_type. if allow_name not in ALLOW_ANY_TYPE_LIST: ctxt.add_reply_field_bson_any_not_allowed_error( cmd_name, field_name, old_field_type.name, old_idl_file_path) return if old_field_type.cpp_type != new_field_type.cpp_type: ctxt.add_reply_field_cpp_type_not_equal_error( cmd_name, field_name, new_field_type.name, new_idl_file_path) if isinstance(old_field_type, syntax.VariantType): # If the new type is not variant just check the single type. new_variant_types = new_field_type.variant_types if isinstance( new_field_type, syntax.VariantType) else [new_field_type] old_variant_types = old_field_type.variant_types # Check that new variant types are a subset of old variant types. for new_variant_type in new_variant_types: for old_variant_type in old_variant_types: if old_variant_type.name == new_variant_type.name: # Check that the old and new version of each variant type is also compatible. check_reply_field_type_recursive( ctxt, old_variant_type, new_variant_type, cmd_name, field_name, old_idl_file, new_idl_file, old_idl_file_path, new_idl_file_path) break else: # new_variant_type was not found in old_variant_types. ctxt.add_new_reply_field_variant_type_not_subset_error( cmd_name, field_name, new_variant_type.name, new_idl_file_path) # If new type is variant and has a struct as a variant type, compare old and new variant_struct_type. # Since enums can't be part of variant types, we don't explicitly check for enums. if isinstance(new_field_type, syntax.VariantType ) and new_field_type.variant_struct_type is not None: if old_field_type.variant_struct_type is None: ctxt.add_new_reply_field_variant_type_not_subset_error( cmd_name, field_name, new_field_type.variant_struct_type.name, new_idl_file_path) else: check_reply_fields(ctxt, old_field_type.variant_struct_type, new_field_type.variant_struct_type, cmd_name, old_idl_file, new_idl_file, old_idl_file_path, new_idl_file_path) else: if isinstance(new_field_type, syntax.VariantType): ctxt.add_new_reply_field_variant_type_error( cmd_name, field_name, old_field_type.name, new_idl_file_path) else: check_subset(ctxt, cmd_name, field_name, new_field_type.name, new_field_type.bson_serialization_type, old_field_type.bson_serialization_type, new_idl_file_path)