xref: /aosp_15_r20/external/libchrome/mojo/public/tools/bindings/generators/mojom_cpp_generator.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1# Copyright 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Generates C++ source files from a mojom.Module."""
6
7import mojom.generate.generator as generator
8import mojom.generate.module as mojom
9import mojom.generate.pack as pack
10from mojom.generate.template_expander import UseJinja
11
12
13_kind_to_cpp_type = {
14  mojom.BOOL:                  "bool",
15  mojom.INT8:                  "int8_t",
16  mojom.UINT8:                 "uint8_t",
17  mojom.INT16:                 "int16_t",
18  mojom.UINT16:                "uint16_t",
19  mojom.INT32:                 "int32_t",
20  mojom.UINT32:                "uint32_t",
21  mojom.FLOAT:                 "float",
22  mojom.INT64:                 "int64_t",
23  mojom.UINT64:                "uint64_t",
24  mojom.DOUBLE:                "double",
25}
26
27_kind_to_cpp_literal_suffix = {
28  mojom.UINT8:        "U",
29  mojom.UINT16:       "U",
30  mojom.UINT32:       "U",
31  mojom.FLOAT:        "f",
32  mojom.UINT64:       "ULL",
33}
34
35
36class _NameFormatter(object):
37  """A formatter for the names of kinds or values."""
38
39  def __init__(self, token, variant):
40    self._token = token
41    self._variant = variant
42
43  def Format(self, separator, prefixed=False, internal=False,
44             include_variant=False, omit_namespace_for_module=None,
45             flatten_nested_kind=False):
46    """Formats the name according to the given configuration.
47
48    Args:
49      separator: Separator between different parts of the name.
50      prefixed: Whether a leading separator should be added.
51      internal: Returns the name in the "internal" namespace.
52      include_variant: Whether to include variant as namespace. If |internal| is
53          True, then this flag is ignored and variant is not included.
54      omit_namespace_for_module: If the token is from the specified module,
55          don't add the namespaces of the module to the name.
56      flatten_nested_kind: It is allowed to define enums inside structs and
57          interfaces. If this flag is set to True, this method concatenates the
58          parent kind and the nested kind with '_', instead of treating the
59          parent kind as a scope."""
60
61    parts = []
62    if self._ShouldIncludeNamespace(omit_namespace_for_module):
63      if prefixed:
64        parts.append("")
65      parts.extend(self._GetNamespace())
66      if include_variant and self._variant and not internal:
67        parts.append(self._variant)
68    parts.extend(self._GetName(internal, flatten_nested_kind))
69    return separator.join(parts)
70
71  def FormatForCpp(self, omit_namespace_for_module=None, internal=False,
72                   flatten_nested_kind=False):
73    return self.Format(
74        "::", prefixed=True,
75        omit_namespace_for_module=omit_namespace_for_module,
76        internal=internal, include_variant=True,
77        flatten_nested_kind=flatten_nested_kind)
78
79  def FormatForMojom(self):
80    return self.Format(".")
81
82  def _MapKindName(self, token, internal):
83    if not internal:
84      return token.name
85    if (mojom.IsStructKind(token) or mojom.IsUnionKind(token) or
86        mojom.IsEnumKind(token)):
87      return token.name + "_Data"
88    return token.name
89
90  def _GetName(self, internal, flatten_nested_kind):
91    if isinstance(self._token, mojom.EnumValue):
92      name_parts = _NameFormatter(self._token.enum, self._variant)._GetName(
93          internal, flatten_nested_kind)
94      name_parts.append(self._token.name)
95      return name_parts
96
97    name_parts = []
98    if internal:
99      name_parts.append("internal")
100
101    if (flatten_nested_kind and mojom.IsEnumKind(self._token) and
102        self._token.parent_kind):
103      name = "%s_%s" % (self._token.parent_kind.name,
104                        self._MapKindName(self._token, internal))
105      name_parts.append(name)
106      return name_parts
107
108    if self._token.parent_kind:
109      name_parts.append(self._MapKindName(self._token.parent_kind, internal))
110    name_parts.append(self._MapKindName(self._token, internal))
111    return name_parts
112
113  def _ShouldIncludeNamespace(self, omit_namespace_for_module):
114    return self._token.module and (
115        not omit_namespace_for_module or
116        self._token.module.path != omit_namespace_for_module.path)
117
118  def _GetNamespace(self):
119    if self._token.module:
120      return NamespaceToArray(self._token.module.namespace)
121
122
123def NamespaceToArray(namespace):
124  return namespace.split(".") if namespace else []
125
126
127def GetWtfHashFnNameForEnum(enum):
128  return _NameFormatter(enum, None).Format("_", internal=True,
129                                           flatten_nested_kind=True) + "HashFn"
130
131
132def IsNativeOnlyKind(kind):
133  return (mojom.IsStructKind(kind) or mojom.IsEnumKind(kind)) and \
134      kind.native_only
135
136
137def UseCustomSerializer(kind):
138  return mojom.IsStructKind(kind) and kind.custom_serializer
139
140
141def AllEnumValues(enum):
142  """Return all enum values associated with an enum.
143
144  Args:
145    enum: {mojom.Enum} The enum type.
146
147  Returns:
148   {Set[int]} The values.
149  """
150  return set(field.numeric_value for field in enum.fields)
151
152
153def GetCppPodType(kind):
154  return _kind_to_cpp_type[kind]
155
156
157def RequiresContextForDataView(kind):
158  for field in kind.fields:
159    if mojom.IsReferenceKind(field.kind):
160      return True
161  return False
162
163
164def ShouldInlineStruct(struct):
165  # TODO(darin): Base this on the size of the wrapper class.
166  if len(struct.fields) > 4:
167    return False
168  for field in struct.fields:
169    if mojom.IsReferenceKind(field.kind) and not mojom.IsStringKind(field.kind):
170      return False
171  return True
172
173
174def ShouldInlineUnion(union):
175  return not any(
176      mojom.IsReferenceKind(field.kind) and not mojom.IsStringKind(field.kind)
177           for field in union.fields)
178
179
180class StructConstructor(object):
181  """Represents a constructor for a generated struct.
182
183  Fields:
184    fields: {[Field]} All struct fields in order.
185    params: {[Field]} The fields that are passed as params.
186  """
187
188  def __init__(self, fields, params):
189    self._fields = fields
190    self._params = set(params)
191
192  @property
193  def params(self):
194    return [field for field in self._fields if field in self._params]
195
196  @property
197  def fields(self):
198    for field in self._fields:
199      yield (field, field in self._params)
200
201
202class Generator(generator.Generator):
203  def __init__(self, *args, **kwargs):
204    super(Generator, self).__init__(*args, **kwargs)
205
206  def _GetExtraTraitsHeaders(self):
207    extra_headers = set()
208    for typemap in self._GetAllUsedTypemaps():
209      extra_headers.update(typemap.get("traits_headers", []))
210    return sorted(extra_headers)
211
212  def _GetAllUsedTypemaps(self):
213    """Returns the typemaps for types needed for serialization in this module.
214
215    A type is needed for serialization if it is contained by a struct or union
216    defined in this module, is a parameter of a message in an interface in
217    this module or is contained within another type needed for serialization.
218    """
219    used_typemaps = []
220    seen_types = set()
221    def AddKind(kind):
222      if (mojom.IsIntegralKind(kind) or mojom.IsStringKind(kind) or
223          mojom.IsDoubleKind(kind) or mojom.IsFloatKind(kind) or
224          mojom.IsAnyHandleKind(kind) or
225          mojom.IsInterfaceKind(kind) or
226          mojom.IsInterfaceRequestKind(kind) or
227          mojom.IsAssociatedKind(kind)):
228        pass
229      elif mojom.IsArrayKind(kind):
230        AddKind(kind.kind)
231      elif mojom.IsMapKind(kind):
232        AddKind(kind.key_kind)
233        AddKind(kind.value_kind)
234      else:
235        name = self._GetFullMojomNameForKind(kind)
236        if name in seen_types:
237          return
238        seen_types.add(name)
239
240        typemap = self.typemap.get(name, None)
241        if typemap:
242          used_typemaps.append(typemap)
243        if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
244          for field in kind.fields:
245            AddKind(field.kind)
246
247    for kind in self.module.structs + self.module.unions:
248      for field in kind.fields:
249        AddKind(field.kind)
250
251    for interface in self.module.interfaces:
252      for method in interface.methods:
253        for parameter in method.parameters + (method.response_parameters or []):
254          AddKind(parameter.kind)
255
256    return used_typemaps
257
258  def _GetExtraPublicHeaders(self):
259    headers = set()
260
261    all_enums = list(self.module.enums)
262    for struct in self.module.structs:
263      all_enums.extend(struct.enums)
264    for interface in self.module.interfaces:
265      all_enums.extend(interface.enums)
266      if interface.uuid:
267        headers.add('base/token.h')
268
269    types = set(self._GetFullMojomNameForKind(typename)
270                for typename in
271                self.module.structs + all_enums + self.module.unions)
272    for typename, typemap in self.typemap.items():
273      if typename in types:
274        headers.update(typemap.get("public_headers", []))
275    return sorted(headers)
276
277  def _GetDirectlyUsedKinds(self):
278    for struct in self.module.structs + self.module.unions:
279      for field in struct.fields:
280        yield field.kind
281
282    for interface in self.module.interfaces:
283      for method in interface.methods:
284        for param in method.parameters + (method.response_parameters or []):
285          yield param.kind
286
287  def _GetJinjaExports(self):
288    all_enums = list(self.module.enums)
289    for struct in self.module.structs:
290      all_enums.extend(struct.enums)
291    for interface in self.module.interfaces:
292      all_enums.extend(interface.enums)
293
294    return {
295      "all_enums": all_enums,
296      "disallow_interfaces": self.disallow_interfaces,
297      "disallow_native_types": self.disallow_native_types,
298      "enums": self.module.enums,
299      "export_attribute": self.export_attribute,
300      "export_header": self.export_header,
301      "extra_public_headers": self._GetExtraPublicHeaders(),
302      "extra_traits_headers": self._GetExtraTraitsHeaders(),
303      "for_blink": self.for_blink,
304      "imports": self.module.imports,
305      "interfaces": self.module.interfaces,
306      "kinds": self.module.kinds,
307      "module": self.module,
308      "namespace": self.module.namespace,
309      "namespaces_as_array": NamespaceToArray(self.module.namespace),
310      "structs": self.module.structs,
311      "support_lazy_serialization": self.support_lazy_serialization,
312      "unions": self.module.unions,
313      "use_once_callback": self.use_once_callback,
314      "variant": self.variant,
315    }
316
317  @staticmethod
318  def GetTemplatePrefix():
319    return "cpp_templates"
320
321  def GetFilters(self):
322    cpp_filters = {
323      "all_enum_values": AllEnumValues,
324      "constant_value": self._ConstantValue,
325      "contains_handles_or_interfaces": mojom.ContainsHandlesOrInterfaces,
326      "contains_move_only_members": self._ContainsMoveOnlyMembers,
327      "cpp_data_view_type": self._GetCppDataViewType,
328      "cpp_field_type": self._GetCppFieldType,
329      "cpp_union_field_type": self._GetCppUnionFieldType,
330      "cpp_pod_type": GetCppPodType,
331      "cpp_union_getter_return_type": self._GetUnionGetterReturnType,
332      "cpp_union_trait_getter_return_type": self._GetUnionTraitGetterReturnType,
333      "cpp_wrapper_call_type": self._GetCppWrapperCallType,
334      "cpp_wrapper_param_type": self._GetCppWrapperParamType,
335      "cpp_wrapper_param_type_new": self._GetCppWrapperParamTypeNew,
336      "cpp_wrapper_type": self._GetCppWrapperType,
337      "default_value": self._DefaultValue,
338      "expression_to_text": self._ExpressionToText,
339      "format_constant_declaration": self._FormatConstantDeclaration,
340      "get_container_validate_params_ctor_args":
341          self._GetContainerValidateParamsCtorArgs,
342      "get_name_for_kind": self._GetNameForKind,
343      "get_pad": pack.GetPad,
344      "get_qualified_name_for_kind": self._GetQualifiedNameForKind,
345      "has_callbacks": mojom.HasCallbacks,
346      "has_sync_methods": mojom.HasSyncMethods,
347      "method_supports_lazy_serialization":
348          self._MethodSupportsLazySerialization,
349      "requires_context_for_data_view": RequiresContextForDataView,
350      "should_inline": ShouldInlineStruct,
351      "should_inline_union": ShouldInlineUnion,
352      "is_array_kind": mojom.IsArrayKind,
353      "is_enum_kind": mojom.IsEnumKind,
354      "is_integral_kind": mojom.IsIntegralKind,
355      "is_interface_kind": mojom.IsInterfaceKind,
356      "is_native_only_kind": IsNativeOnlyKind,
357      "is_any_handle_kind": mojom.IsAnyHandleKind,
358      "is_any_interface_kind": mojom.IsAnyInterfaceKind,
359      "is_any_handle_or_interface_kind": mojom.IsAnyHandleOrInterfaceKind,
360      "is_associated_kind": mojom.IsAssociatedKind,
361      "is_hashable": self._IsHashableKind,
362      "is_map_kind": mojom.IsMapKind,
363      "is_nullable_kind": mojom.IsNullableKind,
364      "is_object_kind": mojom.IsObjectKind,
365      "is_reference_kind": mojom.IsReferenceKind,
366      "is_string_kind": mojom.IsStringKind,
367      "is_struct_kind": mojom.IsStructKind,
368      "is_typemapped_kind": self._IsTypemappedKind,
369      "is_union_kind": mojom.IsUnionKind,
370      "passes_associated_kinds": mojom.PassesAssociatedKinds,
371      "struct_constructors": self._GetStructConstructors,
372      "under_to_camel": generator.ToCamel,
373      "unmapped_type_for_serializer": self._GetUnmappedTypeForSerializer,
374      "use_custom_serializer": UseCustomSerializer,
375      "wtf_hash_fn_name_for_enum": GetWtfHashFnNameForEnum,
376    }
377    return cpp_filters
378
379  @UseJinja("module.h.tmpl")
380  def _GenerateModuleHeader(self):
381    return self._GetJinjaExports()
382
383  @UseJinja("module.cc.tmpl")
384  def _GenerateModuleSource(self):
385    return self._GetJinjaExports()
386
387  @UseJinja("module-shared.h.tmpl")
388  def _GenerateModuleSharedHeader(self):
389    return self._GetJinjaExports()
390
391  @UseJinja("module-shared-internal.h.tmpl")
392  def _GenerateModuleSharedInternalHeader(self):
393    return self._GetJinjaExports()
394
395  @UseJinja("module-shared-message-ids.h.tmpl")
396  def _GenerateModuleSharedMessageIdsHeader(self):
397    return self._GetJinjaExports()
398
399  @UseJinja("module-shared.cc.tmpl")
400  def _GenerateModuleSharedSource(self):
401    return self._GetJinjaExports()
402
403  def GenerateFiles(self, args):
404    self.module.Stylize(generator.Stylizer())
405
406    if self.generate_non_variant_code:
407      if self.generate_message_ids:
408        self.Write(self._GenerateModuleSharedMessageIdsHeader(),
409           "%s-shared-message-ids.h" % self.module.path)
410      else:
411        self.Write(self._GenerateModuleSharedHeader(),
412                   "%s-shared.h" % self.module.path)
413        self.Write(self._GenerateModuleSharedInternalHeader(),
414                   "%s-shared-internal.h" % self.module.path)
415        self.Write(self._GenerateModuleSharedSource(),
416                   "%s-shared.cc" % self.module.path)
417    else:
418      suffix = "-%s" % self.variant if self.variant else ""
419      self.Write(self._GenerateModuleHeader(),
420                 "%s%s.h" % (self.module.path, suffix))
421      self.Write(self._GenerateModuleSource(),
422                 "%s%s.cc" % (self.module.path, suffix))
423
424  def _ConstantValue(self, constant):
425    return self._ExpressionToText(constant.value, kind=constant.kind)
426
427  def _DefaultValue(self, field):
428    if not field.default:
429      return ""
430
431    if mojom.IsStructKind(field.kind):
432      assert field.default == "default"
433      if self._IsTypemappedKind(field.kind):
434        return ""
435      return "%s::New()" % self._GetNameForKind(field.kind)
436
437    expression = self._ExpressionToText(field.default, kind=field.kind)
438    if mojom.IsEnumKind(field.kind) and self._IsTypemappedKind(field.kind):
439      expression = "mojo::internal::ConvertEnumValue<%s, %s>(%s)" % (
440          self._GetNameForKind(field.kind), self._GetCppWrapperType(field.kind),
441          expression)
442    return expression
443
444  def _GetNameForKind(self, kind, internal=False, flatten_nested_kind=False,
445                      add_same_module_namespaces=False):
446    return _NameFormatter(kind, self.variant).FormatForCpp(
447        internal=internal, flatten_nested_kind=flatten_nested_kind,
448        omit_namespace_for_module = (None if add_same_module_namespaces
449                                          else self.module))
450
451  def _GetQualifiedNameForKind(self, kind, internal=False,
452                               flatten_nested_kind=False, include_variant=True):
453    return _NameFormatter(
454        kind, self.variant if include_variant else None).FormatForCpp(
455            internal=internal, flatten_nested_kind=flatten_nested_kind)
456
457  def _GetFullMojomNameForKind(self, kind):
458    return _NameFormatter(kind, self.variant).FormatForMojom()
459
460  def _IsTypemappedKind(self, kind):
461    return hasattr(kind, "name") and \
462        self._GetFullMojomNameForKind(kind) in self.typemap
463
464  def _IsHashableKind(self, kind):
465    """Check if the kind can be hashed.
466
467    Args:
468      kind: {Kind} The kind to check.
469
470    Returns:
471      {bool} True if a value of this kind can be hashed.
472    """
473    checked = set()
474    def Check(kind):
475      if kind.spec in checked:
476        return True
477      checked.add(kind.spec)
478      if mojom.IsNullableKind(kind):
479        return False
480      elif mojom.IsStructKind(kind):
481        if kind.native_only:
482          return False
483        if (self._IsTypemappedKind(kind) and
484            not self.typemap[self._GetFullMojomNameForKind(kind)]["hashable"]):
485          return False
486        return all(Check(field.kind) for field in kind.fields)
487      elif mojom.IsEnumKind(kind):
488        return not self._IsTypemappedKind(kind) or self.typemap[
489            self._GetFullMojomNameForKind(kind)]["hashable"]
490      elif mojom.IsUnionKind(kind):
491        return all(Check(field.kind) for field in kind.fields)
492      elif mojom.IsAnyHandleKind(kind):
493        return False
494      elif mojom.IsAnyInterfaceKind(kind):
495        return False
496      # TODO(crbug.com/735301): Arrays and maps could be made hashable. We just
497      # don't have a use case yet.
498      elif mojom.IsArrayKind(kind):
499        return False
500      elif mojom.IsMapKind(kind):
501        return False
502      else:
503        return True
504    return Check(kind)
505
506  def _GetNativeTypeName(self, typemapped_kind):
507    return self.typemap[self._GetFullMojomNameForKind(typemapped_kind)][
508        "typename"]
509
510  def _FormatConstantDeclaration(self, constant, nested=False):
511    if mojom.IsStringKind(constant.kind):
512      if nested:
513        return "const char %s[]" % constant.name
514      return "%sextern const char %s[]" % \
515          ((self.export_attribute + " ") if self.export_attribute else "",
516           constant.name)
517    return "constexpr %s %s = %s" % (
518        GetCppPodType(constant.kind), constant.name,
519        self._ConstantValue(constant))
520
521  def _GetCppWrapperType(self, kind, add_same_module_namespaces=False):
522    def _AddOptional(type_name):
523      return "base::Optional<%s>" % type_name
524
525    if self._IsTypemappedKind(kind):
526      type_name = self._GetNativeTypeName(kind)
527      if (mojom.IsNullableKind(kind) and
528          not self.typemap[self._GetFullMojomNameForKind(kind)][
529             "nullable_is_same_type"]):
530        type_name = _AddOptional(type_name)
531      return type_name
532    if mojom.IsEnumKind(kind):
533      return self._GetNameForKind(
534          kind, add_same_module_namespaces=add_same_module_namespaces)
535    if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
536      return "%sPtr" % self._GetNameForKind(
537          kind, add_same_module_namespaces=add_same_module_namespaces)
538    if mojom.IsArrayKind(kind):
539      pattern = "WTF::Vector<%s>" if self.for_blink else "std::vector<%s>"
540      if mojom.IsNullableKind(kind):
541        pattern = _AddOptional(pattern)
542      return pattern % self._GetCppWrapperType(
543          kind.kind, add_same_module_namespaces=add_same_module_namespaces)
544    if mojom.IsMapKind(kind):
545      pattern = ("WTF::HashMap<%s, %s>" if self.for_blink else
546                 "base::flat_map<%s, %s>")
547      if mojom.IsNullableKind(kind):
548        pattern = _AddOptional(pattern)
549      return pattern % (
550          self._GetCppWrapperType(
551              kind.key_kind,
552              add_same_module_namespaces=add_same_module_namespaces),
553          self._GetCppWrapperType(
554              kind.value_kind,
555              add_same_module_namespaces=add_same_module_namespaces))
556    if mojom.IsInterfaceKind(kind):
557      return "%sPtrInfo" % self._GetNameForKind(
558          kind, add_same_module_namespaces=add_same_module_namespaces)
559    if mojom.IsInterfaceRequestKind(kind):
560      return "%sRequest" % self._GetNameForKind(
561          kind.kind, add_same_module_namespaces=add_same_module_namespaces)
562    if mojom.IsAssociatedInterfaceKind(kind):
563      return "%sAssociatedPtrInfo" % self._GetNameForKind(
564          kind.kind, add_same_module_namespaces=add_same_module_namespaces)
565    if mojom.IsAssociatedInterfaceRequestKind(kind):
566      return "%sAssociatedRequest" % self._GetNameForKind(
567          kind.kind, add_same_module_namespaces=add_same_module_namespaces)
568    if mojom.IsStringKind(kind):
569      if self.for_blink:
570        return "WTF::String"
571      type_name = "std::string"
572      return (_AddOptional(type_name) if mojom.IsNullableKind(kind)
573                                      else type_name)
574    if mojom.IsGenericHandleKind(kind):
575      return "mojo::ScopedHandle"
576    if mojom.IsDataPipeConsumerKind(kind):
577      return "mojo::ScopedDataPipeConsumerHandle"
578    if mojom.IsDataPipeProducerKind(kind):
579      return "mojo::ScopedDataPipeProducerHandle"
580    if mojom.IsMessagePipeKind(kind):
581      return "mojo::ScopedMessagePipeHandle"
582    if mojom.IsSharedBufferKind(kind):
583      return "mojo::ScopedSharedBufferHandle"
584    if not kind in _kind_to_cpp_type:
585      raise Exception("Unrecognized kind %s" % kind.spec)
586    return _kind_to_cpp_type[kind]
587
588  def _IsMoveOnlyKind(self, kind):
589    if self._IsTypemappedKind(kind):
590      if mojom.IsEnumKind(kind):
591        return False
592      return self.typemap[self._GetFullMojomNameForKind(kind)]["move_only"]
593    if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
594      return True
595    if mojom.IsArrayKind(kind):
596      return self._IsMoveOnlyKind(kind.kind)
597    if mojom.IsMapKind(kind):
598      return (self._IsMoveOnlyKind(kind.value_kind) or
599              self._IsMoveOnlyKind(kind.key_kind))
600    if mojom.IsAnyHandleOrInterfaceKind(kind):
601      return True
602    return False
603
604  def _IsCopyablePassByValue(self, kind):
605    if not self._IsTypemappedKind(kind):
606      return False
607    return self.typemap[self._GetFullMojomNameForKind(kind)][
608        "copyable_pass_by_value"]
609
610  def _ShouldPassParamByValue(self, kind):
611    return ((not mojom.IsReferenceKind(kind)) or self._IsMoveOnlyKind(kind) or
612        self._IsCopyablePassByValue(kind))
613
614  def _GetCppWrapperCallType(self, kind):
615    # TODO: Remove this once interfaces are always passed as PtrInfo.
616    if mojom.IsInterfaceKind(kind):
617      return "%sPtr" % self._GetNameForKind(kind)
618    return self._GetCppWrapperType(kind)
619
620  def _GetCppWrapperParamType(self, kind):
621    # TODO: Remove all usage of this method in favor of
622    # _GetCppWrapperParamTypeNew. This requires all generated code which passes
623    # interface handles to use PtrInfo instead of Ptr.
624    if mojom.IsInterfaceKind(kind):
625      return "%sPtr" % self._GetNameForKind(kind)
626    cpp_wrapper_type = self._GetCppWrapperType(kind)
627    return (cpp_wrapper_type if self._ShouldPassParamByValue(kind)
628                             else "const %s&" % cpp_wrapper_type)
629
630  def _GetCppWrapperParamTypeNew(self, kind):
631    cpp_wrapper_type = self._GetCppWrapperType(kind)
632    return (cpp_wrapper_type if self._ShouldPassParamByValue(kind)
633                             else "const %s&" % cpp_wrapper_type)
634
635  def _GetCppFieldType(self, kind):
636    if mojom.IsStructKind(kind):
637      return ("mojo::internal::Pointer<%s>" %
638          self._GetNameForKind(kind, internal=True))
639    if mojom.IsUnionKind(kind):
640      return "%s" % self._GetNameForKind(kind, internal=True)
641    if mojom.IsArrayKind(kind):
642      return ("mojo::internal::Pointer<mojo::internal::Array_Data<%s>>" %
643              self._GetCppFieldType(kind.kind))
644    if mojom.IsMapKind(kind):
645      return ("mojo::internal::Pointer<mojo::internal::Map_Data<%s, %s>>" %
646              (self._GetCppFieldType(kind.key_kind),
647               self._GetCppFieldType(kind.value_kind)))
648    if mojom.IsInterfaceKind(kind):
649      return "mojo::internal::Interface_Data"
650    if mojom.IsInterfaceRequestKind(kind):
651      return "mojo::internal::Handle_Data"
652    if mojom.IsAssociatedInterfaceKind(kind):
653      return "mojo::internal::AssociatedInterface_Data"
654    if mojom.IsAssociatedInterfaceRequestKind(kind):
655      return "mojo::internal::AssociatedEndpointHandle_Data"
656    if mojom.IsEnumKind(kind):
657      return "int32_t"
658    if mojom.IsStringKind(kind):
659      return "mojo::internal::Pointer<mojo::internal::String_Data>"
660    if mojom.IsAnyHandleKind(kind):
661      return "mojo::internal::Handle_Data"
662    return _kind_to_cpp_type[kind]
663
664  def _GetCppUnionFieldType(self, kind):
665    if mojom.IsUnionKind(kind):
666      return ("mojo::internal::Pointer<%s>" %
667                  self._GetNameForKind(kind, internal=True))
668    return self._GetCppFieldType(kind)
669
670  def _GetUnionGetterReturnType(self, kind):
671    if mojom.IsReferenceKind(kind):
672      return "%s&" % self._GetCppWrapperType(kind)
673    return self._GetCppWrapperType(kind)
674
675  def _GetUnionTraitGetterReturnType(self, kind):
676    """Get field type used in UnionTraits template specialization.
677
678    The type may be qualified as UnionTraits specializations live outside the
679    namespace where e.g. structs are defined.
680
681    Args:
682      kind: {Kind} The type of the field.
683
684    Returns:
685      {str} The C++ type to use for the field.
686    """
687    if mojom.IsReferenceKind(kind):
688      return "%s&" % self._GetCppWrapperType(kind,
689                                             add_same_module_namespaces=True)
690    return self._GetCppWrapperType(kind, add_same_module_namespaces=True)
691
692  def _KindMustBeSerialized(self, kind, processed_kinds=None):
693    if not processed_kinds:
694      processed_kinds = set()
695    if kind in processed_kinds:
696      return False
697
698    if (self._IsTypemappedKind(kind) and
699        self.typemap[self._GetFullMojomNameForKind(kind)]["force_serialize"]):
700      return True
701
702    processed_kinds.add(kind)
703
704    if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
705      return any(self._KindMustBeSerialized(field.kind,
706                                            processed_kinds=processed_kinds)
707                 for field in kind.fields)
708
709    return False
710
711  def _MethodSupportsLazySerialization(self, method):
712    if not self.support_lazy_serialization:
713      return False
714
715    # TODO(crbug.com/753433): Support lazy serialization for methods which pass
716    # associated handles.
717    if mojom.MethodPassesAssociatedKinds(method):
718      return False
719
720    return not any(self._KindMustBeSerialized(param.kind) for param in
721                   method.parameters + (method.response_parameters or []))
722
723  def _TranslateConstants(self, token, kind):
724    if isinstance(token, mojom.NamedValue):
725      return self._GetNameForKind(token, flatten_nested_kind=True)
726
727    if isinstance(token, mojom.BuiltinValue):
728      if token.value == "double.INFINITY":
729        return "std::numeric_limits<double>::infinity()"
730      if token.value == "float.INFINITY":
731        return "std::numeric_limits<float>::infinity()"
732      if token.value == "double.NEGATIVE_INFINITY":
733        return "-std::numeric_limits<double>::infinity()"
734      if token.value == "float.NEGATIVE_INFINITY":
735        return "-std::numeric_limits<float>::infinity()"
736      if token.value == "double.NAN":
737        return "std::numeric_limits<double>::quiet_NaN()"
738      if token.value == "float.NAN":
739        return "std::numeric_limits<float>::quiet_NaN()"
740
741    if (kind is not None and mojom.IsFloatKind(kind)):
742        return token if token.isdigit() else token + "f";
743
744    # Per C++11, 2.14.2, the type of an integer literal is the first of the
745    # corresponding list in Table 6 in which its value can be represented. In
746    # this case, the list for decimal constants with no suffix is:
747    #   int, long int, long long int
748    # The standard considers a program ill-formed if it contains an integer
749    # literal that cannot be represented by any of the allowed types.
750    #
751    # As it turns out, MSVC doesn't bother trying to fall back to long long int,
752    # so the integral constant -2147483648 causes it grief: it decides to
753    # represent 2147483648 as an unsigned integer, and then warns that the unary
754    # minus operator doesn't make sense on unsigned types. Doh!
755    if kind == mojom.INT32 and token == "-2147483648":
756      return "(-%d - 1) /* %s */" % (
757          2**31 - 1, "Workaround for MSVC bug; see https://crbug.com/445618")
758
759    return "%s%s" % (token, _kind_to_cpp_literal_suffix.get(kind, ""))
760
761  def _ExpressionToText(self, value, kind=None):
762    return self._TranslateConstants(value, kind)
763
764  def _ContainsMoveOnlyMembers(self, struct):
765    for field in struct.fields:
766      if self._IsMoveOnlyKind(field.kind):
767        return True
768    return False
769
770  def _GetStructConstructors(self, struct):
771    """Returns a list of constructors for a struct.
772
773    Params:
774      struct: {Struct} The struct to return constructors for.
775
776    Returns:
777      {[StructConstructor]} A list of StructConstructors that should be
778      generated for |struct|.
779    """
780    if not mojom.IsStructKind(struct):
781      raise TypeError
782    # Types that are neither copyable nor movable can't be passed to a struct
783    # constructor so only generate a default constructor.
784    if any(self._IsTypemappedKind(field.kind) and self.typemap[
785        self._GetFullMojomNameForKind(field.kind)]["non_copyable_non_movable"]
786           for field in struct.fields):
787      return [StructConstructor(struct.fields, [])]
788
789    param_counts = [0]
790    for version in struct.versions:
791      if param_counts[-1] != version.num_fields:
792        param_counts.append(version.num_fields)
793
794    ordinal_fields = sorted(struct.fields, key=lambda field: field.ordinal if field.ordinal != None else -1)
795    return (StructConstructor(struct.fields, ordinal_fields[:param_count])
796            for param_count in param_counts)
797
798  def _GetContainerValidateParamsCtorArgs(self, kind):
799    if mojom.IsStringKind(kind):
800      expected_num_elements = 0
801      element_is_nullable = False
802      key_validate_params = "nullptr"
803      element_validate_params = "nullptr"
804      enum_validate_func = "nullptr"
805    elif mojom.IsMapKind(kind):
806      expected_num_elements = 0
807      element_is_nullable = False
808      key_validate_params = self._GetNewContainerValidateParams(mojom.Array(
809          kind=kind.key_kind))
810      element_validate_params = self._GetNewContainerValidateParams(mojom.Array(
811          kind=kind.value_kind))
812      enum_validate_func = "nullptr"
813    else:  # mojom.IsArrayKind(kind)
814      expected_num_elements = generator.ExpectedArraySize(kind) or 0
815      element_is_nullable = mojom.IsNullableKind(kind.kind)
816      key_validate_params = "nullptr"
817      element_validate_params = self._GetNewContainerValidateParams(kind.kind)
818      if mojom.IsEnumKind(kind.kind):
819        enum_validate_func = ("%s::Validate" %
820            self._GetQualifiedNameForKind(kind.kind, internal=True,
821                                          flatten_nested_kind=True))
822      else:
823        enum_validate_func = "nullptr"
824
825    if enum_validate_func == "nullptr":
826      if key_validate_params == "nullptr":
827        return "%d, %s, %s" % (expected_num_elements,
828                               "true" if element_is_nullable else "false",
829                               element_validate_params)
830      else:
831        return "%s, %s" % (key_validate_params, element_validate_params)
832    else:
833      return "%d, %s" % (expected_num_elements, enum_validate_func)
834
835  def _GetNewContainerValidateParams(self, kind):
836    if (not mojom.IsArrayKind(kind) and not mojom.IsMapKind(kind) and
837        not mojom.IsStringKind(kind)):
838      return "nullptr"
839
840    return "new mojo::internal::ContainerValidateParams(%s)" % (
841        self._GetContainerValidateParamsCtorArgs(kind))
842
843  def _GetCppDataViewType(self, kind, qualified=False):
844    def _GetName(input_kind):
845      return _NameFormatter(input_kind, None).FormatForCpp(
846          omit_namespace_for_module=(None if qualified else self.module),
847          flatten_nested_kind=True)
848
849    if mojom.IsEnumKind(kind):
850      return _GetName(kind)
851    if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
852      return "%sDataView" % _GetName(kind)
853    if mojom.IsArrayKind(kind):
854      return "mojo::ArrayDataView<%s>" % (
855          self._GetCppDataViewType(kind.kind, qualified))
856    if mojom.IsMapKind(kind):
857      return ("mojo::MapDataView<%s, %s>" % (
858          self._GetCppDataViewType(kind.key_kind, qualified),
859          self._GetCppDataViewType(kind.value_kind, qualified)))
860    if mojom.IsStringKind(kind):
861      return "mojo::StringDataView"
862    if mojom.IsInterfaceKind(kind):
863      return "%sPtrDataView" % _GetName(kind)
864    if mojom.IsInterfaceRequestKind(kind):
865      return "%sRequestDataView" % _GetName(kind.kind)
866    if mojom.IsAssociatedInterfaceKind(kind):
867      return "%sAssociatedPtrInfoDataView" % _GetName(kind.kind)
868    if mojom.IsAssociatedInterfaceRequestKind(kind):
869      return "%sAssociatedRequestDataView" % _GetName(kind.kind)
870    if mojom.IsGenericHandleKind(kind):
871      return "mojo::ScopedHandle"
872    if mojom.IsDataPipeConsumerKind(kind):
873      return "mojo::ScopedDataPipeConsumerHandle"
874    if mojom.IsDataPipeProducerKind(kind):
875      return "mojo::ScopedDataPipeProducerHandle"
876    if mojom.IsMessagePipeKind(kind):
877      return "mojo::ScopedMessagePipeHandle"
878    if mojom.IsSharedBufferKind(kind):
879      return "mojo::ScopedSharedBufferHandle"
880    return _kind_to_cpp_type[kind]
881
882  def _GetUnmappedTypeForSerializer(self, kind):
883    return self._GetCppDataViewType(kind, qualified=True)
884