diff options
-rw-r--r-- | buildscripts/idl/idl/ast.py | 1 | ||||
-rw-r--r-- | buildscripts/idl/idl/binder.py | 34 | ||||
-rw-r--r-- | buildscripts/idl/idl/common.py | 15 | ||||
-rw-r--r-- | buildscripts/idl/idl/enum_types.py | 11 | ||||
-rw-r--r-- | buildscripts/idl/idl/parser.py | 33 | ||||
-rw-r--r-- | buildscripts/idl/idl/syntax.py | 6 | ||||
-rw-r--r-- | src/mongo/db/session_txn_record.idl | 10 | ||||
-rw-r--r-- | src/mongo/idl/idl_test.cpp | 6 | ||||
-rw-r--r-- | src/mongo/idl/unittest.idl | 8 | ||||
-rw-r--r-- | src/mongo/idl/unittest_import.idl | 12 | ||||
-rw-r--r-- | src/mongo/util/uuid.h | 8 |
11 files changed, 117 insertions, 27 deletions
diff --git a/buildscripts/idl/idl/ast.py b/buildscripts/idl/idl/ast.py index cd925d709a4..e0aa71d0b34 100644 --- a/buildscripts/idl/idl/ast.py +++ b/buildscripts/idl/idl/ast.py @@ -179,6 +179,7 @@ class Enum(common.SourceLocation): """Construct an Enum.""" self.name = None # type: unicode self.description = None # type: unicode + self.cpp_namespace = None # type: unicode self.type = None # type: unicode self.values = [] # type: List[EnumValue] diff --git a/buildscripts/idl/idl/binder.py b/buildscripts/idl/idl/binder.py index 354acca9742..9addc6b6104 100644 --- a/buildscripts/idl/idl/binder.py +++ b/buildscripts/idl/idl/binder.py @@ -392,6 +392,31 @@ def _validate_doc_sequence_field(ctxt, ast_field): ctxt.add_bad_non_object_as_doc_sequence_error(ast_field, ast_field.name) +def _normalize_method_name(cpp_type_name, cpp_method_name): + # type: (unicode, unicode) -> unicode + """Normalize the method name to be fully-qualified with the type name.""" + # Default deserializer + if not cpp_method_name: + return cpp_method_name + + # Global function + if cpp_method_name.startswith('::'): + return cpp_method_name + + # Method is full qualified already + if cpp_method_name.startswith(cpp_type_name): + return cpp_method_name + + # Get the unqualified type name + type_name = cpp_type_name.split("::")[-1] + + # Method is prefixed with just the type name + if cpp_method_name.startswith(type_name): + return '::'.join(cpp_type_name.split('::')[0:-1]) + "::" + cpp_method_name + + return cpp_method_name + + def _bind_field(ctxt, parsed_spec, field): # type: (errors.ParserContext, syntax.IDLSpec, syntax.Field) -> ast.Field """ @@ -444,7 +469,7 @@ def _bind_field(ctxt, parsed_spec, field): # Copy over only the needed information if this a struct or a type if isinstance(syntax_symbol, syntax.Struct): struct = cast(syntax.Struct, syntax_symbol) - ast_field.struct_type = struct.name + ast_field.struct_type = common.qualify_cpp_name(struct.cpp_namespace, struct.name) ast_field.bson_serialization_type = ["object"] _validate_field_of_type_struct(ctxt, field) @@ -452,7 +477,7 @@ def _bind_field(ctxt, parsed_spec, field): enum_type_info = enum_types.get_type_info(cast(syntax.Enum, syntax_symbol)) ast_field.enum_type = True - ast_field.cpp_type = enum_type_info.get_cpp_type_name() + ast_field.cpp_type = enum_type_info.get_qualified_cpp_type_name() ast_field.bson_serialization_type = enum_type_info.get_bson_types() ast_field.serializer = enum_type_info.get_enum_serializer_name() ast_field.deserializer = enum_type_info.get_enum_deserializer_name() @@ -466,8 +491,8 @@ def _bind_field(ctxt, parsed_spec, field): ast_field.cpp_type = idltype.cpp_type ast_field.bson_serialization_type = idltype.bson_serialization_type ast_field.bindata_subtype = idltype.bindata_subtype - ast_field.serializer = idltype.serializer - ast_field.deserializer = idltype.deserializer + ast_field.serializer = _normalize_method_name(idltype.cpp_type, idltype.serializer) + ast_field.deserializer = _normalize_method_name(idltype.cpp_type, idltype.deserializer) ast_field.default = idltype.default if field.default: @@ -627,6 +652,7 @@ def _bind_enum(ctxt, idl_enum): ast_enum.name = idl_enum.name ast_enum.description = idl_enum.description ast_enum.type = idl_enum.type + ast_enum.cpp_namespace = idl_enum.cpp_namespace enum_type_info = enum_types.get_type_info(idl_enum) if not enum_type_info: diff --git a/buildscripts/idl/idl/common.py b/buildscripts/idl/idl/common.py index 7eb4bbe4e1e..1a52477998d 100644 --- a/buildscripts/idl/idl/common.py +++ b/buildscripts/idl/idl/common.py @@ -31,6 +31,12 @@ COMMAND_NAMESPACE_IGNORED = "ignored" def title_case(name): # type: (unicode) -> unicode """Return a CapitalCased version of a string.""" + + # Only capitalize the last part of a fully-qualified name + pos = name.rfind("::") + if pos > -1: + return name[:pos + 2] + name[pos + 2:pos + 3].upper() + name[pos + 3:] + return name[0:1].upper() + name[1:] @@ -40,6 +46,15 @@ def camel_case(name): return name[0:1].lower() + name[1:] +def qualify_cpp_name(cpp_namespace, cpp_type_name): + # type: (unicode, unicode) -> unicode + """Preprend a type name with a C++ namespace if cpp_namespace is not None.""" + if cpp_namespace: + return cpp_namespace + "::" + cpp_type_name + + return cpp_type_name + + def _escape_template_string(template): # type: (unicode) -> unicode """Escape the '$' in template strings unless followed by '{'.""" diff --git a/buildscripts/idl/idl/enum_types.py b/buildscripts/idl/idl/enum_types.py index 3caed6f67da..e9e7214d2ad 100644 --- a/buildscripts/idl/idl/enum_types.py +++ b/buildscripts/idl/idl/enum_types.py @@ -40,6 +40,11 @@ class EnumTypeInfoBase(object): """Construct a EnumTypeInfoBase.""" self._enum = idl_enum + def get_qualified_cpp_type_name(self): + # type: () -> unicode + """Get the fully qualified C++ type name for an enum.""" + return common.qualify_cpp_name(self._enum.cpp_namespace, self.get_cpp_type_name()) + @abstractmethod def get_cpp_type_name(self): # type: () -> unicode @@ -61,7 +66,8 @@ class EnumTypeInfoBase(object): def get_enum_deserializer_name(self): # type: () -> unicode """Return the name of deserializer function with non-method prefix.""" - return "::" + self._get_enum_deserializer_name() + return "::" + common.qualify_cpp_name(self._enum.cpp_namespace, + self._get_enum_deserializer_name()) def _get_enum_serializer_name(self): # type: () -> unicode @@ -72,7 +78,8 @@ class EnumTypeInfoBase(object): def get_enum_serializer_name(self): # type: () -> unicode """Return the name of serializer function with non-method prefix.""" - return "::" + self._get_enum_serializer_name() + return "::" + common.qualify_cpp_name(self._enum.cpp_namespace, + self._get_enum_serializer_name()) @abstractmethod def get_cpp_value_assignment(self, enum_value): diff --git a/buildscripts/idl/idl/parser.py b/buildscripts/idl/idl/parser.py index fd0af9b1445..0f45fe93255 100644 --- a/buildscripts/idl/idl/parser.py +++ b/buildscripts/idl/idl/parser.py @@ -27,6 +27,7 @@ from yaml import nodes from typing import Any, Callable, Dict, List, Set, Tuple, Union from . import common +from . import cpp_types from . import errors from . import syntax @@ -427,6 +428,36 @@ def _parse_command(ctxt, spec, name, node): spec.symbols.add_command(ctxt, command) +def _prefix_with_namespace(cpp_namespace, cpp_name): + # type: (unicode, unicode) -> unicode + """Preface a C++ type name with a namespace if not already qualified or a primitive type.""" + if "::" in cpp_name or cpp_types.is_primitive_scalar_type(cpp_name): + return cpp_name + + return cpp_namespace + "::" + cpp_name + + +def _propagate_globals(spec): + # type: (syntax.IDLSpec) -> None + """Propagate the globals information to each type and struct as needed.""" + if not spec.globals or not spec.globals.cpp_namespace: + return + + cpp_namespace = spec.globals.cpp_namespace + + for struct in spec.symbols.structs: + struct.cpp_namespace = cpp_namespace + + for command in spec.symbols.commands: + command.cpp_namespace = cpp_namespace + + for idlenum in spec.symbols.enums: + idlenum.cpp_namespace = cpp_namespace + + for idltype in spec.symbols.types: + idltype.cpp_type = _prefix_with_namespace(cpp_namespace, idltype.cpp_type) + + def _parse(stream, error_file_name): # type: (Any, unicode) -> syntax.IDLParsedSpec """ @@ -483,6 +514,8 @@ def _parse(stream, error_file_name): if ctxt.errors.has_errors(): return syntax.IDLParsedSpec(None, ctxt.errors) else: + _propagate_globals(spec) + return syntax.IDLParsedSpec(spec, None) diff --git a/buildscripts/idl/idl/syntax.py b/buildscripts/idl/idl/syntax.py index 056d2e9dc3a..6ea14171f74 100644 --- a/buildscripts/idl/idl/syntax.py +++ b/buildscripts/idl/idl/syntax.py @@ -350,6 +350,9 @@ class Struct(common.SourceLocation): # imported file, and no code is generated for it. self.imported = False # type: bool + # Internal property: cpp_namespace from globals section + self.cpp_namespace = None # type: unicode + super(Struct, self).__init__(file_name, line, column) @@ -403,4 +406,7 @@ class Enum(common.SourceLocation): # imported file, and no code is generated for it. self.imported = False # type: bool + # Internal property: cpp_namespace from globals section + self.cpp_namespace = None # type: unicode + super(Enum, self).__init__(file_name, line, column) diff --git a/src/mongo/db/session_txn_record.idl b/src/mongo/db/session_txn_record.idl index c9924a32a32..c7943d0964b 100644 --- a/src/mongo/db/session_txn_record.idl +++ b/src/mongo/db/session_txn_record.idl @@ -35,15 +35,7 @@ global: imports: - "mongo/idl/basic_types.idl" - "mongo/db/logical_session_id.idl" - -# TODO: SERVER-31278 import from repl/replication_types.idl instead -types: - optime: - bson_serialization_type: object - description: A document representing an OpTime. - cpp_type: "repl::OpTime" - serializer: repl::OpTime::toBSON - deserializer: repl::OpTime::parse + - "mongo/db/repl/replication_types.idl" structs: sessionTxnRecord: diff --git a/src/mongo/idl/idl_test.cpp b/src/mongo/idl/idl_test.cpp index 9f26f03633f..fe2a845aa3d 100644 --- a/src/mongo/idl/idl_test.cpp +++ b/src/mongo/idl/idl_test.cpp @@ -35,6 +35,7 @@ #include "mongo/util/net/op_msg.h" using namespace mongo::idl::test; +using namespace mongo::idl::import; namespace mongo { @@ -896,7 +897,8 @@ TEST(IDLArrayTests, TestArraysOfComplexTypes) { assert_same_types<decltype(testStruct.getField4()), const std::vector<mongo::ObjectBasicType>&>(); assert_same_types<decltype(testStruct.getField5()), const std::vector<mongo::BSONObj>&>(); - assert_same_types<decltype(testStruct.getField6()), const std::vector<mongo::One_string>&>(); + assert_same_types<decltype(testStruct.getField6()), + const std::vector<mongo::idl::import::One_string>&>(); assert_same_types<decltype(testStruct.getField1o()), const boost::optional<std::vector<std::int64_t>>&>(); @@ -909,7 +911,7 @@ TEST(IDLArrayTests, TestArraysOfComplexTypes) { assert_same_types<decltype(testStruct.getField5o()), const boost::optional<std::vector<mongo::BSONObj>>&>(); assert_same_types<decltype(testStruct.getField6o()), - const boost::optional<std::vector<mongo::One_string>>&>(); + const boost::optional<std::vector<mongo::idl::import::One_string>>&>(); std::vector<std::int64_t> field1{1, 2, 3}; ASSERT_TRUE(field1 == testStruct.getField1()); diff --git a/src/mongo/idl/unittest.idl b/src/mongo/idl/unittest.idl index ccb16e86dca..159977fadeb 100644 --- a/src/mongo/idl/unittest.idl +++ b/src/mongo/idl/unittest.idl @@ -110,14 +110,6 @@ types: ################################################################################################## enums: - IntEnum: - description: "An example int enum" - type: int - values: - a0: 0 - b1: 1 - c2: 2 - StringEnum: description: "An example string enum" type: string diff --git a/src/mongo/idl/unittest_import.idl b/src/mongo/idl/unittest_import.idl index 73e25833d67..9cf75014cd8 100644 --- a/src/mongo/idl/unittest_import.idl +++ b/src/mongo/idl/unittest_import.idl @@ -15,7 +15,7 @@ # IDL Unit Tests IDL file for testing imported structs global: - cpp_namespace: "mongo" + cpp_namespace: "mongo::idl::import" imports: - "mongo/idl/basic_types.idl" @@ -97,3 +97,13 @@ structs: description: UnitTest for a single UUID fields: value: uuid + +enums: + + IntEnum: + description: "An example int enum" + type: int + values: + a0: 0 + b1: 1 + c2: 2 diff --git a/src/mongo/util/uuid.h b/src/mongo/util/uuid.h index d5c3f7c71b3..61f55ab044c 100644 --- a/src/mongo/util/uuid.h +++ b/src/mongo/util/uuid.h @@ -45,6 +45,12 @@ namespace repl { class OplogEntryBase; } // namespace repl +namespace idl { +namespace import { +class One_UUID; +} // namespace import +} // namespace idl + /** * A UUID is a 128-bit unique identifier, per RFC 4122, v4, using * a secure random number generator. @@ -55,7 +61,7 @@ class UUID { // Make the IDL generated parser a friend friend class ConfigsvrShardCollectionResponse; friend class DbCheckOplogCollection; - friend class One_UUID; + friend class idl::import::One_UUID; friend class LogicalSessionId; friend class LogicalSessionToClient; friend class LogicalSessionIdToClient; |