diff options
Diffstat (limited to 'buildscripts/idl')
-rw-r--r-- | buildscripts/idl/idl/binder.py | 10 | ||||
-rw-r--r-- | buildscripts/idl/idl/errors.py | 15 | ||||
-rw-r--r-- | buildscripts/idl/idl/generator.py | 4 | ||||
-rw-r--r-- | buildscripts/idl/idl_check_compatibility.py | 15 | ||||
-rw-r--r-- | buildscripts/idl/tests/test_binder.py | 21 |
5 files changed, 50 insertions, 15 deletions
diff --git a/buildscripts/idl/idl/binder.py b/buildscripts/idl/idl/binder.py index 1b11d1af4f7..1511b6c1b07 100644 --- a/buildscripts/idl/idl/binder.py +++ b/buildscripts/idl/idl/binder.py @@ -438,7 +438,7 @@ def _bind_struct_field(ctxt, ast_field, idl_type): ast_field.type = _bind_struct_type(struct) ast_field.type.is_array = isinstance(idl_type, syntax.ArrayType) - _validate_field_of_type_struct(ctxt, ast_field) + _validate_default_of_type_struct(ctxt, ast_field) def _bind_variant_field(ctxt, ast_field, idl_type): @@ -747,11 +747,11 @@ def _validate_ignored_field(ctxt, field): ctxt.add_ignored_field_must_be_empty_error(field, field.name, "default") -def _validate_field_of_type_struct(ctxt, field): +def _validate_default_of_type_struct(ctxt, field): # type: (errors.ParserContext, Union[syntax.Field, ast.Field]) -> None - """Validate that for fields with a type of struct, no other properties are set.""" - if field.default is not None: - ctxt.add_struct_field_must_be_empty_error(field, field.name, "default") + """Validate that for fields with a type of struct, the only default permitted is true, which causes it to be default-constructed.""" + if (field.default is not None) and (field.default != "true"): + ctxt.add_struct_default_must_be_true_or_empty_error(field, field.name) def _validate_variant_type(ctxt, syntax_symbol, field): diff --git a/buildscripts/idl/idl/errors.py b/buildscripts/idl/idl/errors.py index f1c387df2f7..4efd18797f9 100644 --- a/buildscripts/idl/idl/errors.py +++ b/buildscripts/idl/idl/errors.py @@ -63,7 +63,7 @@ ERROR_ID_BAD_BSON_BINDATA_SUBTYPE_TYPE = "ID0015" ERROR_ID_BAD_BSON_BINDATA_SUBTYPE_VALUE = "ID0016" ERROR_ID_NO_STRINGDATA = "ID0017" ERROR_ID_FIELD_MUST_BE_EMPTY_FOR_IGNORED = "ID0018" -ERROR_ID_FIELD_MUST_BE_EMPTY_FOR_STRUCT = "ID0019" +ERROR_ID_DEFAULT_MUST_BE_TRUE_OR_EMPTY_FOR_STRUCT = "ID0019" ERROR_ID_CUSTOM_SCALAR_SERIALIZATION_NOT_SUPPORTED = "ID0020" ERROR_ID_BAD_ANY_TYPE_USE = "ID0021" ERROR_ID_BAD_NUMERIC_CPP_TYPE = "ID0022" @@ -462,14 +462,13 @@ class ParserContext(object): ("Field '%s' cannot contain a value for property '%s' when a field is marked as ignored" ) % (name, field_name)) - def add_struct_field_must_be_empty_error(self, location, name, field_name): - # type: (common.SourceLocation, str, str) -> None - """Add an error about field must be empty for fields of type struct.""" + def add_struct_default_must_be_true_or_empty_error(self, location, name): + # type: (common.SourceLocation, str) -> None + """Add an error about default must be True or empty for fields of type struct.""" # pylint: disable=invalid-name - self._add_error( - location, ERROR_ID_FIELD_MUST_BE_EMPTY_FOR_STRUCT, - ("Field '%s' cannot contain a value for property '%s' when a field's type is a struct") - % (name, field_name)) + self._add_error(location, ERROR_ID_DEFAULT_MUST_BE_TRUE_OR_EMPTY_FOR_STRUCT, ( + "Field '%s' can only contain value 'true' for property 'default' when a field's type is a struct" + ) % (name)) def add_not_custom_scalar_serialization_not_supported_error(self, location, ast_type, ast_parent, bson_type_name): diff --git a/buildscripts/idl/idl/generator.py b/buildscripts/idl/idl/generator.py index 6c3bc4948cc..d8b38d51a0c 100644 --- a/buildscripts/idl/idl/generator.py +++ b/buildscripts/idl/idl/generator.py @@ -617,10 +617,14 @@ class _CppHeaderFileWriter(_CppFileWriterBase): member_type = cpp_type_info.get_storage_type() member_name = _get_field_member_name(field) + # Struct fields are allowed to specify default: true so that the member gets default- + # constructed. if field.default and not field.constructed: if field.type.is_enum: self._writer.write_line('%s %s{%s::%s};' % (member_type, member_name, field.type.cpp_type, field.default)) + elif field.type.is_struct: + self._writer.write_line('%s %s;' % (member_type, member_name)) else: self._writer.write_line('%s %s{%s};' % (member_type, member_name, field.default)) else: diff --git a/buildscripts/idl/idl_check_compatibility.py b/buildscripts/idl/idl_check_compatibility.py index d34dbc83409..9aab17079f3 100644 --- a/buildscripts/idl/idl_check_compatibility.py +++ b/buildscripts/idl/idl_check_compatibility.py @@ -191,6 +191,15 @@ SKIPPED_FILES = [ "nsICollation.idl", "nsIStringBundle.idl", "nsIScriptableUConv.idl", "nsITextToSubURI.idl" ] +# Do not add commands that were visible to users in previously released versions. +IGNORE_COMMANDS_LIST: List[str] = [ + # The following commands were released behind a feature flag in 5.3 but were shelved in + # favor of getClusterParameter and setClusterParameter. Since the feature flag was not enabled + # in 5.3, they were effectively unusable and so can be safely removed from the strict API. + 'getChangeStreamOptions', + 'setChangeStreamOptions', +] + class FieldCompatibility: """Information about a Field to check compatibility.""" @@ -1193,6 +1202,12 @@ def check_compatibility(old_idl_dir: str, new_idl_dir: str, old_import_directori if old_cmd.api_version == "" or old_cmd.imported: continue + # Ignore select commands that were removed after being added to the strict API. + # Only commands that were never visible to the end-user in previous releases + # (i.e., hidden behind a feature flag) should be allowed here. + if old_cmd.command_name in IGNORE_COMMANDS_LIST: + continue + if old_cmd.api_version != "1": # We're not ready to handle future API versions yet. ctxt.add_command_invalid_api_version_error( diff --git a/buildscripts/idl/tests/test_binder.py b/buildscripts/idl/tests/test_binder.py index 2ce3dd45559..b52c755e34b 100644 --- a/buildscripts/idl/tests/test_binder.py +++ b/buildscripts/idl/tests/test_binder.py @@ -942,6 +942,23 @@ class TestBinder(testcase.IDLTestcase): always_serialize: true """)) + # Test field of a struct type with default=true + self.assert_bind(test_preamble + textwrap.dedent(""" + structs: + foo: + description: foo + fields: + field1: string + + bar: + description: foo + fields: + field2: + type: foo + default: true + + """)) + def test_field_negative(self): # type: () -> None """Negative field tests.""" @@ -964,7 +981,7 @@ class TestBinder(testcase.IDLTestcase): bindata_subtype: uuid """) - # Test field of a struct type with a default + # Test field of a struct type with a non-true default self.assert_bind_fail( test_preamble + textwrap.dedent(""" structs: @@ -980,7 +997,7 @@ class TestBinder(testcase.IDLTestcase): type: foo default: foo - """), idl.errors.ERROR_ID_FIELD_MUST_BE_EMPTY_FOR_STRUCT) + """), idl.errors.ERROR_ID_DEFAULT_MUST_BE_TRUE_OR_EMPTY_FOR_STRUCT) # Test array as field name self.assert_bind_fail( |