blob: 3b8f0fac1193919ca2621d53f9d778a9df67d14c [file] [log] [blame]
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generates C++ source files from a mojom.Module."""
import mojom.generate.generator as generator
import mojom.generate.module as mojom
import mojom.generate.pack as pack
from mojom.generate.template_expander import UseJinja
_kind_to_cpp_type = {
mojom.BOOL: "bool",
mojom.INT8: "int8_t",
mojom.UINT8: "uint8_t",
mojom.INT16: "int16_t",
mojom.UINT16: "uint16_t",
mojom.INT32: "int32_t",
mojom.UINT32: "uint32_t",
mojom.FLOAT: "float",
mojom.INT64: "int64_t",
mojom.UINT64: "uint64_t",
mojom.DOUBLE: "double",
}
_kind_to_cpp_literal_suffix = {
mojom.UINT8: "U",
mojom.UINT16: "U",
mojom.UINT32: "U",
mojom.FLOAT: "f",
mojom.UINT64: "ULL",
}
class _NameFormatter(object):
"""A formatter for the names of kinds or values."""
def __init__(self, token, variant):
self._token = token
self._variant = variant
def Format(self, separator, prefixed=False, internal=False,
include_variant=False, omit_namespace_for_module=None,
flatten_nested_kind=False):
"""Formats the name according to the given configuration.
Args:
separator: Separator between different parts of the name.
prefixed: Whether a leading separator should be added.
internal: Returns the name in the "internal" namespace.
include_variant: Whether to include variant as namespace. If |internal| is
True, then this flag is ignored and variant is not included.
omit_namespace_for_module: If the token is from the specified module,
don't add the namespaces of the module to the name.
flatten_nested_kind: It is allowed to define enums inside structs and
interfaces. If this flag is set to True, this method concatenates the
parent kind and the nested kind with '_', instead of treating the
parent kind as a scope."""
parts = []
if self._ShouldIncludeNamespace(omit_namespace_for_module):
if prefixed:
parts.append("")
parts.extend(self._GetNamespace())
if include_variant and self._variant and not internal:
parts.append(self._variant)
parts.extend(self._GetName(internal, flatten_nested_kind))
return separator.join(parts)
def FormatForCpp(self, omit_namespace_for_module=None, internal=False,
flatten_nested_kind=False):
return self.Format(
"::", prefixed=True,
omit_namespace_for_module=omit_namespace_for_module,
internal=internal, include_variant=True,
flatten_nested_kind=flatten_nested_kind)
def FormatForMojom(self):
return self.Format(".")
def _MapKindName(self, token, internal):
if not internal:
return token.name
if (mojom.IsStructKind(token) or mojom.IsUnionKind(token) or
mojom.IsEnumKind(token)):
return token.name + "_Data"
return token.name
def _GetName(self, internal, flatten_nested_kind):
if isinstance(self._token, mojom.EnumValue):
name_parts = _NameFormatter(self._token.enum, self._variant)._GetName(
internal, flatten_nested_kind)
name_parts.append(self._token.name)
return name_parts
name_parts = []
if internal:
name_parts.append("internal")
if (flatten_nested_kind and mojom.IsEnumKind(self._token) and
self._token.parent_kind):
name = "%s_%s" % (self._token.parent_kind.name,
self._MapKindName(self._token, internal))
name_parts.append(name)
return name_parts
if self._token.parent_kind:
name_parts.append(self._MapKindName(self._token.parent_kind, internal))
name_parts.append(self._MapKindName(self._token, internal))
return name_parts
def _ShouldIncludeNamespace(self, omit_namespace_for_module):
return self._token.module and (
not omit_namespace_for_module or
self._token.module.path != omit_namespace_for_module.path)
def _GetNamespace(self):
if self._token.module:
return NamespaceToArray(self._token.module.namespace)
def NamespaceToArray(namespace):
return namespace.split(".") if namespace else []
def GetWtfHashFnNameForEnum(enum):
return _NameFormatter(enum, None).Format("_", internal=True,
flatten_nested_kind=True) + "HashFn"
def IsNativeOnlyKind(kind):
return (mojom.IsStructKind(kind) or mojom.IsEnumKind(kind)) and \
kind.native_only
def UseCustomSerializer(kind):
return mojom.IsStructKind(kind) and kind.custom_serializer
def AllEnumValues(enum):
"""Return all enum values associated with an enum.
Args:
enum: {mojom.Enum} The enum type.
Returns:
{Set[int]} The values.
"""
return set(field.numeric_value for field in enum.fields)
def GetCppPodType(kind):
return _kind_to_cpp_type[kind]
def RequiresContextForDataView(kind):
for field in kind.fields:
if mojom.IsReferenceKind(field.kind):
return True
return False
def ShouldInlineStruct(struct):
# TODO(darin): Base this on the size of the wrapper class.
if len(struct.fields) > 4:
return False
for field in struct.fields:
if mojom.IsReferenceKind(field.kind) and not mojom.IsStringKind(field.kind):
return False
return True
def ShouldInlineUnion(union):
return not any(
mojom.IsReferenceKind(field.kind) and not mojom.IsStringKind(field.kind)
for field in union.fields)
class StructConstructor(object):
"""Represents a constructor for a generated struct.
Fields:
fields: {[Field]} All struct fields in order.
params: {[Field]} The fields that are passed as params.
"""
def __init__(self, fields, params):
self._fields = fields
self._params = set(params)
@property
def params(self):
return [field for field in self._fields if field in self._params]
@property
def fields(self):
for field in self._fields:
yield (field, field in self._params)
class Generator(generator.Generator):
def __init__(self, *args, **kwargs):
super(Generator, self).__init__(*args, **kwargs)
def _GetExtraTraitsHeaders(self):
extra_headers = set()
for typemap in self._GetAllUsedTypemaps():
extra_headers.update(typemap.get("traits_headers", []))
return sorted(extra_headers)
def _GetAllUsedTypemaps(self):
"""Returns the typemaps for types needed for serialization in this module.
A type is needed for serialization if it is contained by a struct or union
defined in this module, is a parameter of a message in an interface in
this module or is contained within another type needed for serialization.
"""
used_typemaps = []
seen_types = set()
def AddKind(kind):
if (mojom.IsIntegralKind(kind) or mojom.IsStringKind(kind) or
mojom.IsDoubleKind(kind) or mojom.IsFloatKind(kind) or
mojom.IsAnyHandleKind(kind) or
mojom.IsInterfaceKind(kind) or
mojom.IsInterfaceRequestKind(kind) or
mojom.IsAssociatedKind(kind)):
pass
elif mojom.IsArrayKind(kind):
AddKind(kind.kind)
elif mojom.IsMapKind(kind):
AddKind(kind.key_kind)
AddKind(kind.value_kind)
else:
name = self._GetFullMojomNameForKind(kind)
if name in seen_types:
return
seen_types.add(name)
typemap = self.typemap.get(name, None)
if typemap:
used_typemaps.append(typemap)
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
for field in kind.fields:
AddKind(field.kind)
for kind in self.module.structs + self.module.unions:
for field in kind.fields:
AddKind(field.kind)
for interface in self.module.interfaces:
for method in interface.methods:
for parameter in method.parameters + (method.response_parameters or []):
AddKind(parameter.kind)
return used_typemaps
def _GetExtraPublicHeaders(self):
all_enums = list(self.module.enums)
for struct in self.module.structs:
all_enums.extend(struct.enums)
for interface in self.module.interfaces:
all_enums.extend(interface.enums)
types = set(self._GetFullMojomNameForKind(typename)
for typename in
self.module.structs + all_enums + self.module.unions)
headers = set()
for typename, typemap in self.typemap.iteritems():
if typename in types:
headers.update(typemap.get("public_headers", []))
return sorted(headers)
def _GetDirectlyUsedKinds(self):
for struct in self.module.structs + self.module.unions:
for field in struct.fields:
yield field.kind
for interface in self.module.interfaces:
for method in interface.methods:
for param in method.parameters + (method.response_parameters or []):
yield param.kind
def _GetJinjaExports(self):
all_enums = list(self.module.enums)
for struct in self.module.structs:
all_enums.extend(struct.enums)
for interface in self.module.interfaces:
all_enums.extend(interface.enums)
return {
"all_enums": all_enums,
"disallow_interfaces": self.disallow_interfaces,
"disallow_native_types": self.disallow_native_types,
"enums": self.module.enums,
"export_attribute": self.export_attribute,
"export_header": self.export_header,
"extra_public_headers": self._GetExtraPublicHeaders(),
"extra_traits_headers": self._GetExtraTraitsHeaders(),
"for_blink": self.for_blink,
"imports": self.module.imports,
"interfaces": self.module.interfaces,
"kinds": self.module.kinds,
"module": self.module,
"namespace": self.module.namespace,
"namespaces_as_array": NamespaceToArray(self.module.namespace),
"structs": self.module.structs,
"support_lazy_serialization": self.support_lazy_serialization,
"unions": self.module.unions,
"variant": self.variant,
}
@staticmethod
def GetTemplatePrefix():
return "cpp_templates"
def GetFilters(self):
cpp_filters = {
"all_enum_values": AllEnumValues,
"constant_value": self._ConstantValue,
"contains_handles_or_interfaces": mojom.ContainsHandlesOrInterfaces,
"contains_move_only_members": self._ContainsMoveOnlyMembers,
"cpp_data_view_type": self._GetCppDataViewType,
"cpp_field_type": self._GetCppFieldType,
"cpp_union_field_type": self._GetCppUnionFieldType,
"cpp_pod_type": GetCppPodType,
"cpp_union_getter_return_type": self._GetUnionGetterReturnType,
"cpp_union_trait_getter_return_type": self._GetUnionTraitGetterReturnType,
"cpp_wrapper_call_type": self._GetCppWrapperCallType,
"cpp_wrapper_param_type": self._GetCppWrapperParamType,
"cpp_wrapper_param_type_new": self._GetCppWrapperParamTypeNew,
"cpp_wrapper_type": self._GetCppWrapperType,
"default_value": self._DefaultValue,
"expression_to_text": self._ExpressionToText,
"format_constant_declaration": self._FormatConstantDeclaration,
"get_container_validate_params_ctor_args":
self._GetContainerValidateParamsCtorArgs,
"get_name_for_kind": self._GetNameForKind,
"get_pad": pack.GetPad,
"get_qualified_name_for_kind": self._GetQualifiedNameForKind,
"has_callbacks": mojom.HasCallbacks,
"has_sync_methods": mojom.HasSyncMethods,
"method_supports_lazy_serialization":
self._MethodSupportsLazySerialization,
"requires_context_for_data_view": RequiresContextForDataView,
"should_inline": ShouldInlineStruct,
"should_inline_union": ShouldInlineUnion,
"is_array_kind": mojom.IsArrayKind,
"is_enum_kind": mojom.IsEnumKind,
"is_integral_kind": mojom.IsIntegralKind,
"is_interface_kind": mojom.IsInterfaceKind,
"is_native_only_kind": IsNativeOnlyKind,
"is_any_handle_kind": mojom.IsAnyHandleKind,
"is_any_interface_kind": mojom.IsAnyInterfaceKind,
"is_any_handle_or_interface_kind": mojom.IsAnyHandleOrInterfaceKind,
"is_associated_kind": mojom.IsAssociatedKind,
"is_hashable": self._IsHashableKind,
"is_map_kind": mojom.IsMapKind,
"is_nullable_kind": mojom.IsNullableKind,
"is_object_kind": mojom.IsObjectKind,
"is_reference_kind": mojom.IsReferenceKind,
"is_string_kind": mojom.IsStringKind,
"is_struct_kind": mojom.IsStructKind,
"is_typemapped_kind": self._IsTypemappedKind,
"is_union_kind": mojom.IsUnionKind,
"passes_associated_kinds": mojom.PassesAssociatedKinds,
"struct_constructors": self._GetStructConstructors,
"under_to_camel": generator.ToCamel,
"unmapped_type_for_serializer": self._GetUnmappedTypeForSerializer,
"use_custom_serializer": UseCustomSerializer,
"wtf_hash_fn_name_for_enum": GetWtfHashFnNameForEnum,
}
return cpp_filters
@UseJinja("module.h.tmpl")
def _GenerateModuleHeader(self):
return self._GetJinjaExports()
@UseJinja("module.cc.tmpl")
def _GenerateModuleSource(self):
return self._GetJinjaExports()
@UseJinja("module-shared.h.tmpl")
def _GenerateModuleSharedHeader(self):
return self._GetJinjaExports()
@UseJinja("module-shared-internal.h.tmpl")
def _GenerateModuleSharedInternalHeader(self):
return self._GetJinjaExports()
@UseJinja("module-shared-message-ids.h.tmpl")
def _GenerateModuleSharedMessageIdsHeader(self):
return self._GetJinjaExports()
@UseJinja("module-shared.cc.tmpl")
def _GenerateModuleSharedSource(self):
return self._GetJinjaExports()
def GenerateFiles(self, args):
self.module.Stylize(generator.Stylizer())
if self.generate_non_variant_code:
if self.generate_message_ids:
self.Write(self._GenerateModuleSharedMessageIdsHeader(),
"%s-shared-message-ids.h" % self.module.path)
else:
self.Write(self._GenerateModuleSharedHeader(),
"%s-shared.h" % self.module.path)
self.Write(self._GenerateModuleSharedInternalHeader(),
"%s-shared-internal.h" % self.module.path)
self.Write(self._GenerateModuleSharedSource(),
"%s-shared.cc" % self.module.path)
else:
suffix = "-%s" % self.variant if self.variant else ""
self.Write(self._GenerateModuleHeader(),
"%s%s.h" % (self.module.path, suffix))
self.Write(self._GenerateModuleSource(),
"%s%s.cc" % (self.module.path, suffix))
def _ConstantValue(self, constant):
return self._ExpressionToText(constant.value, kind=constant.kind)
def _DefaultValue(self, field):
if not field.default:
return ""
if mojom.IsStructKind(field.kind):
assert field.default == "default"
if self._IsTypemappedKind(field.kind):
return ""
return "%s::New()" % self._GetNameForKind(field.kind)
expression = self._ExpressionToText(field.default, kind=field.kind)
if mojom.IsEnumKind(field.kind) and self._IsTypemappedKind(field.kind):
expression = "mojo::internal::ConvertEnumValue<%s, %s>(%s)" % (
self._GetNameForKind(field.kind), self._GetCppWrapperType(field.kind),
expression)
return expression
def _GetNameForKind(self, kind, internal=False, flatten_nested_kind=False,
add_same_module_namespaces=False):
return _NameFormatter(kind, self.variant).FormatForCpp(
internal=internal, flatten_nested_kind=flatten_nested_kind,
omit_namespace_for_module = (None if add_same_module_namespaces
else self.module))
def _GetQualifiedNameForKind(self, kind, internal=False,
flatten_nested_kind=False, include_variant=True):
return _NameFormatter(
kind, self.variant if include_variant else None).FormatForCpp(
internal=internal, flatten_nested_kind=flatten_nested_kind)
def _GetFullMojomNameForKind(self, kind):
return _NameFormatter(kind, self.variant).FormatForMojom()
def _IsTypemappedKind(self, kind):
return hasattr(kind, "name") and \
self._GetFullMojomNameForKind(kind) in self.typemap
def _IsHashableKind(self, kind):
"""Check if the kind can be hashed.
Args:
kind: {Kind} The kind to check.
Returns:
{bool} True if a value of this kind can be hashed.
"""
checked = set()
def Check(kind):
if kind.spec in checked:
return True
checked.add(kind.spec)
if mojom.IsNullableKind(kind):
return False
elif mojom.IsStructKind(kind):
if kind.native_only:
return False
if (self._IsTypemappedKind(kind) and
not self.typemap[self._GetFullMojomNameForKind(kind)]["hashable"]):
return False
return all(Check(field.kind) for field in kind.fields)
elif mojom.IsEnumKind(kind):
return not self._IsTypemappedKind(kind) or self.typemap[
self._GetFullMojomNameForKind(kind)]["hashable"]
elif mojom.IsUnionKind(kind):
return all(Check(field.kind) for field in kind.fields)
elif mojom.IsAnyHandleKind(kind):
return False
elif mojom.IsAnyInterfaceKind(kind):
return False
# TODO(crbug.com/735301): Arrays and maps could be made hashable. We just
# don't have a use case yet.
elif mojom.IsArrayKind(kind):
return False
elif mojom.IsMapKind(kind):
return False
else:
return True
return Check(kind)
def _GetNativeTypeName(self, typemapped_kind):
return self.typemap[self._GetFullMojomNameForKind(typemapped_kind)][
"typename"]
def _FormatConstantDeclaration(self, constant, nested=False):
if mojom.IsStringKind(constant.kind):
if nested:
return "const char %s[]" % constant.name
return "%sextern const char %s[]" % \
((self.export_attribute + " ") if self.export_attribute else "",
constant.name)
return "constexpr %s %s = %s" % (
GetCppPodType(constant.kind), constant.name,
self._ConstantValue(constant))
def _GetCppWrapperType(self, kind, add_same_module_namespaces=False):
def _AddOptional(type_name):
return "base::Optional<%s>" % type_name
if self._IsTypemappedKind(kind):
type_name = self._GetNativeTypeName(kind)
if (mojom.IsNullableKind(kind) and
not self.typemap[self._GetFullMojomNameForKind(kind)][
"nullable_is_same_type"]):
type_name = _AddOptional(type_name)
return type_name
if mojom.IsEnumKind(kind):
return self._GetNameForKind(
kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return "%sPtr" % self._GetNameForKind(
kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsArrayKind(kind):
pattern = "WTF::Vector<%s>" if self.for_blink else "std::vector<%s>"
if mojom.IsNullableKind(kind):
pattern = _AddOptional(pattern)
return pattern % self._GetCppWrapperType(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsMapKind(kind):
pattern = ("WTF::HashMap<%s, %s>" if self.for_blink else
"base::flat_map<%s, %s>")
if mojom.IsNullableKind(kind):
pattern = _AddOptional(pattern)
return pattern % (
self._GetCppWrapperType(
kind.key_kind,
add_same_module_namespaces=add_same_module_namespaces),
self._GetCppWrapperType(
kind.value_kind,
add_same_module_namespaces=add_same_module_namespaces))
if mojom.IsInterfaceKind(kind):
return "%sPtrInfo" % self._GetNameForKind(
kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsInterfaceRequestKind(kind):
return "%sRequest" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsAssociatedInterfaceKind(kind):
return "%sAssociatedPtrInfo" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsAssociatedInterfaceRequestKind(kind):
return "%sAssociatedRequest" % self._GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsStringKind(kind):
if self.for_blink:
return "WTF::String"
type_name = "std::string"
return (_AddOptional(type_name) if mojom.IsNullableKind(kind)
else type_name)
if mojom.IsGenericHandleKind(kind):
return "mojo::ScopedHandle"
if mojom.IsDataPipeConsumerKind(kind):
return "mojo::ScopedDataPipeConsumerHandle"
if mojom.IsDataPipeProducerKind(kind):
return "mojo::ScopedDataPipeProducerHandle"
if mojom.IsMessagePipeKind(kind):
return "mojo::ScopedMessagePipeHandle"
if mojom.IsSharedBufferKind(kind):
return "mojo::ScopedSharedBufferHandle"
if not kind in _kind_to_cpp_type:
raise Exception("Unrecognized kind %s" % kind.spec)
return _kind_to_cpp_type[kind]
def _IsMoveOnlyKind(self, kind):
if self._IsTypemappedKind(kind):
if mojom.IsEnumKind(kind):
return False
return self.typemap[self._GetFullMojomNameForKind(kind)]["move_only"]
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return True
if mojom.IsArrayKind(kind):
return self._IsMoveOnlyKind(kind.kind)
if mojom.IsMapKind(kind):
return (self._IsMoveOnlyKind(kind.value_kind) or
self._IsMoveOnlyKind(kind.key_kind))
if mojom.IsAnyHandleOrInterfaceKind(kind):
return True
return False
def _IsCopyablePassByValue(self, kind):
if not self._IsTypemappedKind(kind):
return False
return self.typemap[self._GetFullMojomNameForKind(kind)][
"copyable_pass_by_value"]
def _ShouldPassParamByValue(self, kind):
return ((not mojom.IsReferenceKind(kind)) or self._IsMoveOnlyKind(kind) or
self._IsCopyablePassByValue(kind))
def _GetCppWrapperCallType(self, kind):
# TODO: Remove this once interfaces are always passed as PtrInfo.
if mojom.IsInterfaceKind(kind):
return "%sPtr" % self._GetNameForKind(kind)
return self._GetCppWrapperType(kind)
def _GetCppWrapperParamType(self, kind):
# TODO: Remove all usage of this method in favor of
# _GetCppWrapperParamTypeNew. This requires all generated code which passes
# interface handles to use PtrInfo instead of Ptr.
if mojom.IsInterfaceKind(kind):
return "%sPtr" % self._GetNameForKind(kind)
cpp_wrapper_type = self._GetCppWrapperType(kind)
return (cpp_wrapper_type if self._ShouldPassParamByValue(kind)
else "const %s&" % cpp_wrapper_type)
def _GetCppWrapperParamTypeNew(self, kind):
cpp_wrapper_type = self._GetCppWrapperType(kind)
return (cpp_wrapper_type if self._ShouldPassParamByValue(kind)
else "const %s&" % cpp_wrapper_type)
def _GetCppFieldType(self, kind):
if mojom.IsStructKind(kind):
return ("mojo::internal::Pointer<%s>" %
self._GetNameForKind(kind, internal=True))
if mojom.IsUnionKind(kind):
return "%s" % self._GetNameForKind(kind, internal=True)
if mojom.IsArrayKind(kind):
return ("mojo::internal::Pointer<mojo::internal::Array_Data<%s>>" %
self._GetCppFieldType(kind.kind))
if mojom.IsMapKind(kind):
return ("mojo::internal::Pointer<mojo::internal::Map_Data<%s, %s>>" %
(self._GetCppFieldType(kind.key_kind),
self._GetCppFieldType(kind.value_kind)))
if mojom.IsInterfaceKind(kind):
return "mojo::internal::Interface_Data"
if mojom.IsInterfaceRequestKind(kind):
return "mojo::internal::Handle_Data"
if mojom.IsAssociatedInterfaceKind(kind):
return "mojo::internal::AssociatedInterface_Data"
if mojom.IsAssociatedInterfaceRequestKind(kind):
return "mojo::internal::AssociatedEndpointHandle_Data"
if mojom.IsEnumKind(kind):
return "int32_t"
if mojom.IsStringKind(kind):
return "mojo::internal::Pointer<mojo::internal::String_Data>"
if mojom.IsAnyHandleKind(kind):
return "mojo::internal::Handle_Data"
return _kind_to_cpp_type[kind]
def _GetCppUnionFieldType(self, kind):
if mojom.IsUnionKind(kind):
return ("mojo::internal::Pointer<%s>" %
self._GetNameForKind(kind, internal=True))
return self._GetCppFieldType(kind)
def _GetUnionGetterReturnType(self, kind):
if mojom.IsReferenceKind(kind):
return "%s&" % self._GetCppWrapperType(kind)
return self._GetCppWrapperType(kind)
def _GetUnionTraitGetterReturnType(self, kind):
"""Get field type used in UnionTraits template specialization.
The type may be qualified as UnionTraits specializations live outside the
namespace where e.g. structs are defined.
Args:
kind: {Kind} The type of the field.
Returns:
{str} The C++ type to use for the field.
"""
if mojom.IsReferenceKind(kind):
return "%s&" % self._GetCppWrapperType(kind,
add_same_module_namespaces=True)
return self._GetCppWrapperType(kind, add_same_module_namespaces=True)
def _KindMustBeSerialized(self, kind, processed_kinds=None):
if not processed_kinds:
processed_kinds = set()
if kind in processed_kinds:
return False
if (self._IsTypemappedKind(kind) and
self.typemap[self._GetFullMojomNameForKind(kind)]["force_serialize"]):
return True
processed_kinds.add(kind)
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return any(self._KindMustBeSerialized(field.kind,
processed_kinds=processed_kinds)
for field in kind.fields)
return False
def _MethodSupportsLazySerialization(self, method):
if not self.support_lazy_serialization:
return False
# TODO(crbug.com/753433): Support lazy serialization for methods which pass
# associated handles.
if mojom.MethodPassesAssociatedKinds(method):
return False
return not any(self._KindMustBeSerialized(param.kind) for param in
method.parameters + (method.response_parameters or []))
def _TranslateConstants(self, token, kind):
if isinstance(token, mojom.NamedValue):
return self._GetNameForKind(token, flatten_nested_kind=True)
if isinstance(token, mojom.BuiltinValue):
if token.value == "double.INFINITY":
return "std::numeric_limits<double>::infinity()"
if token.value == "float.INFINITY":
return "std::numeric_limits<float>::infinity()"
if token.value == "double.NEGATIVE_INFINITY":
return "-std::numeric_limits<double>::infinity()"
if token.value == "float.NEGATIVE_INFINITY":
return "-std::numeric_limits<float>::infinity()"
if token.value == "double.NAN":
return "std::numeric_limits<double>::quiet_NaN()"
if token.value == "float.NAN":
return "std::numeric_limits<float>::quiet_NaN()"
if (kind is not None and mojom.IsFloatKind(kind)):
return token if token.isdigit() else token + "f";
# Per C++11, 2.14.2, the type of an integer literal is the first of the
# corresponding list in Table 6 in which its value can be represented. In
# this case, the list for decimal constants with no suffix is:
# int, long int, long long int
# The standard considers a program ill-formed if it contains an integer
# literal that cannot be represented by any of the allowed types.
#
# As it turns out, MSVC doesn't bother trying to fall back to long long int,
# so the integral constant -2147483648 causes it grief: it decides to
# represent 2147483648 as an unsigned integer, and then warns that the unary
# minus operator doesn't make sense on unsigned types. Doh!
if kind == mojom.INT32 and token == "-2147483648":
return "(-%d - 1) /* %s */" % (
2**31 - 1, "Workaround for MSVC bug; see https://crbug.com/445618")
return "%s%s" % (token, _kind_to_cpp_literal_suffix.get(kind, ""))
def _ExpressionToText(self, value, kind=None):
return self._TranslateConstants(value, kind)
def _ContainsMoveOnlyMembers(self, struct):
for field in struct.fields:
if self._IsMoveOnlyKind(field.kind):
return True
return False
def _GetStructConstructors(self, struct):
"""Returns a list of constructors for a struct.
Params:
struct: {Struct} The struct to return constructors for.
Returns:
{[StructConstructor]} A list of StructConstructors that should be
generated for |struct|.
"""
if not mojom.IsStructKind(struct):
raise TypeError
# Types that are neither copyable nor movable can't be passed to a struct
# constructor so only generate a default constructor.
if any(self._IsTypemappedKind(field.kind) and self.typemap[
self._GetFullMojomNameForKind(field.kind)]["non_copyable_non_movable"]
for field in struct.fields):
return [StructConstructor(struct.fields, [])]
param_counts = [0]
for version in struct.versions:
if param_counts[-1] != version.num_fields:
param_counts.append(version.num_fields)
ordinal_fields = sorted(struct.fields, key=lambda field: field.ordinal)
return (StructConstructor(struct.fields, ordinal_fields[:param_count])
for param_count in param_counts)
def _GetContainerValidateParamsCtorArgs(self, kind):
if mojom.IsStringKind(kind):
expected_num_elements = 0
element_is_nullable = False
key_validate_params = "nullptr"
element_validate_params = "nullptr"
enum_validate_func = "nullptr"
elif mojom.IsMapKind(kind):
expected_num_elements = 0
element_is_nullable = False
key_validate_params = self._GetNewContainerValidateParams(mojom.Array(
kind=kind.key_kind))
element_validate_params = self._GetNewContainerValidateParams(mojom.Array(
kind=kind.value_kind))
enum_validate_func = "nullptr"
else: # mojom.IsArrayKind(kind)
expected_num_elements = generator.ExpectedArraySize(kind) or 0
element_is_nullable = mojom.IsNullableKind(kind.kind)
key_validate_params = "nullptr"
element_validate_params = self._GetNewContainerValidateParams(kind.kind)
if mojom.IsEnumKind(kind.kind):
enum_validate_func = ("%s::Validate" %
self._GetQualifiedNameForKind(kind.kind, internal=True,
flatten_nested_kind=True))
else:
enum_validate_func = "nullptr"
if enum_validate_func == "nullptr":
if key_validate_params == "nullptr":
return "%d, %s, %s" % (expected_num_elements,
"true" if element_is_nullable else "false",
element_validate_params)
else:
return "%s, %s" % (key_validate_params, element_validate_params)
else:
return "%d, %s" % (expected_num_elements, enum_validate_func)
def _GetNewContainerValidateParams(self, kind):
if (not mojom.IsArrayKind(kind) and not mojom.IsMapKind(kind) and
not mojom.IsStringKind(kind)):
return "nullptr"
return "new mojo::internal::ContainerValidateParams(%s)" % (
self._GetContainerValidateParamsCtorArgs(kind))
def _GetCppDataViewType(self, kind, qualified=False):
def _GetName(input_kind):
return _NameFormatter(input_kind, None).FormatForCpp(
omit_namespace_for_module=(None if qualified else self.module),
flatten_nested_kind=True)
if mojom.IsEnumKind(kind):
return _GetName(kind)
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return "%sDataView" % _GetName(kind)
if mojom.IsArrayKind(kind):
return "mojo::ArrayDataView<%s>" % (
self._GetCppDataViewType(kind.kind, qualified))
if mojom.IsMapKind(kind):
return ("mojo::MapDataView<%s, %s>" % (
self._GetCppDataViewType(kind.key_kind, qualified),
self._GetCppDataViewType(kind.value_kind, qualified)))
if mojom.IsStringKind(kind):
return "mojo::StringDataView"
if mojom.IsInterfaceKind(kind):
return "%sPtrDataView" % _GetName(kind)
if mojom.IsInterfaceRequestKind(kind):
return "%sRequestDataView" % _GetName(kind.kind)
if mojom.IsAssociatedInterfaceKind(kind):
return "%sAssociatedPtrInfoDataView" % _GetName(kind.kind)
if mojom.IsAssociatedInterfaceRequestKind(kind):
return "%sAssociatedRequestDataView" % _GetName(kind.kind)
if mojom.IsGenericHandleKind(kind):
return "mojo::ScopedHandle"
if mojom.IsDataPipeConsumerKind(kind):
return "mojo::ScopedDataPipeConsumerHandle"
if mojom.IsDataPipeProducerKind(kind):
return "mojo::ScopedDataPipeProducerHandle"
if mojom.IsMessagePipeKind(kind):
return "mojo::ScopedMessagePipeHandle"
if mojom.IsSharedBufferKind(kind):
return "mojo::ScopedSharedBufferHandle"
return _kind_to_cpp_type[kind]
def _GetUnmappedTypeForSerializer(self, kind):
return self._GetCppDataViewType(kind, qualified=True)