15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from code import Code
658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)from model import PropertyType
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import cpp_util
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from json_parse import OrderedDict
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import schema_util
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class _TypeDependency(object):
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Contains information about a dependency a namespace has on a type: the
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  type's model, and whether that dependency is "hard" meaning that it cannot be
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  forward declared.
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __init__(self, type_, hard=False):
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.type_ = type_
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.hard = hard
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetSortKey(self):
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return '%s.%s' % (self.type_.namespace.name, self.type_.name)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CppTypeGenerator(object):
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Manages the types of properties and provides utilities for getting the
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  C++ type out of a model.Property
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __init__(self, model, schema_loader, default_namespace=None):
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Creates a cpp_type_generator. The given root_namespace should be of the
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    format extensions::api::sub. The generator will generate code suitable for
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    use in the given model's namespace.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._default_namespace = default_namespace
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._default_namespace is None:
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._default_namespace = model.namespaces.values()[0]
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._schema_loader = schema_loader
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetEnumNoneValue(self, type_):
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the enum value in the given model.Property indicating no value has
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    been set.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return '%s_NONE' % self.FollowRef(type_).unix_name.upper()
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def GetEnumLastValue(self, type_):
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Gets the enum value in the given model.Property indicating the last value
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for the type.
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return '%s_LAST' % self.FollowRef(type_).unix_name.upper()
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetEnumValue(self, type_, enum_value):
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Gets the enum value of the given model.Property of the given type.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    e.g VAR_STRING
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    value = cpp_util.Classname(enum_value.name.upper())
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    prefix = (type_.cpp_enum_prefix_override or
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              self.FollowRef(type_).unix_name)
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    value = '%s_%s' % (prefix.upper(), value)
59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # To avoid collisions with built-in OS_* preprocessor definitions, we add a
60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # trailing slash to enum names that start with OS_.
61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if value.startswith("OS_"):
62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      value += "_"
63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return value
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetCppType(self, type_, is_ptr=False, is_in_container=False):
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Translates a model.Property or model.Type into its C++ type.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If REF types from different namespaces are referenced, will resolve
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    using self._schema_loader.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Use |is_ptr| if the type is optional. This will wrap the type in a
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr if possible (it is not possible to wrap an enum).
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Use |is_in_container| if the type is appearing in a collection, e.g. a
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector or std::map. This will wrap it in the correct type with spacing.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cpp_type = None
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type == PropertyType.REF:
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ref_type = self._FindType(type_.ref_type)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if ref_type is None:
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        raise KeyError('Cannot find referenced type: %s' % type_.ref_type)
82c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      cpp_type = self.GetCppType(ref_type)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.BOOLEAN:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'bool'
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.INTEGER:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'int'
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.INT64:
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'int64'
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.DOUBLE:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'double'
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.STRING:
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'std::string'
93c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    elif type_.property_type in (PropertyType.ENUM,
94c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                 PropertyType.OBJECT,
95c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                 PropertyType.CHOICES):
96c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if self._default_namespace is type_.namespace:
97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        cpp_type = cpp_util.Classname(type_.name)
98c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      else:
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        cpp_namespace = cpp_util.GetCppNamespace(
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            type_.namespace.environment.namespace_pattern,
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            type_.namespace.unix_name)
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        cpp_type = '%s::%s' % (cpp_namespace,
103c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                               cpp_util.Classname(type_.name))
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.ANY:
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cpp_type = 'base::Value'
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.FUNCTION:
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Functions come into the json schema compiler as empty objects. We can
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # record these as empty DictionaryValues so that we know if the function
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # was passed in or not.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'base::DictionaryValue'
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.ARRAY:
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item_cpp_type = self.GetCppType(type_.item_type, is_in_container=True)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cpp_type = 'std::vector<%s>' % cpp_util.PadForGenerics(item_cpp_type)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.BINARY:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cpp_type = 'std::string'
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise NotImplementedError('Cannot get type of %s' % type_.property_type)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # HACK: optional ENUM is represented elsewhere with a _NONE value, so it
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # never needs to be wrapped in pointer shenanigans.
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # TODO(kalman): change this - but it's an exceedingly far-reaching change.
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not self.FollowRef(type_).property_type == PropertyType.ENUM:
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if is_in_container and (is_ptr or not self.IsCopyable(type_)):
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        cpp_type = 'linked_ptr<%s>' % cpp_util.PadForGenerics(cpp_type)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      elif is_ptr:
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        cpp_type = 'scoped_ptr<%s>' % cpp_util.PadForGenerics(cpp_type)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return cpp_type
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def IsCopyable(self, type_):
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return not (self.FollowRef(type_).property_type in (PropertyType.ANY,
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                        PropertyType.ARRAY,
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                        PropertyType.OBJECT,
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                        PropertyType.CHOICES))
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def GenerateForwardDeclarations(self):
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Returns the forward declarations for self._default_namespace.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for namespace, deps in self._NamespaceTypeDependencies().iteritems():
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      filtered_deps = [
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        dep for dep in deps
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # Add more ways to forward declare things as necessary.
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (not dep.hard and
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            dep.type_.property_type in (PropertyType.CHOICES,
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                        PropertyType.OBJECT))]
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if not filtered_deps:
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        continue
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      cpp_namespace = cpp_util.GetCppNamespace(
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          namespace.environment.namespace_pattern,
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          namespace.unix_name)
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      c.Concat(cpp_util.OpenNamespace(cpp_namespace))
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      for dep in filtered_deps:
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        c.Append('struct %s;' % dep.type_.name)
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      c.Concat(cpp_util.CloseNamespace(cpp_namespace))
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GenerateIncludes(self, include_soft=False):
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Returns the #include lines for self._default_namespace.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for namespace, dependencies in self._NamespaceTypeDependencies().items():
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for dependency in dependencies:
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if dependency.hard or include_soft:
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          c.Append('#include "%s/%s.h"' % (namespace.source_file_dir,
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           namespace.unix_name))
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _FindType(self, full_name):
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Finds the model.Type with name |qualified_name|. If it's not from
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    |self._default_namespace| then it needs to be qualified.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    namespace = self._schema_loader.ResolveType(full_name,
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                self._default_namespace)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if namespace is None:
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise KeyError('Cannot resolve type %s. Maybe it needs a prefix '
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     'if it comes from another namespace?' % full_name)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return namespace.types[schema_util.StripNamespace(full_name)]
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def FollowRef(self, type_):
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Follows $ref link of types to resolve the concrete type a ref refers to.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    If the property passed in is not of type PropertyType.REF, it will be
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    returned unchanged.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type != PropertyType.REF:
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return type_
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self.FollowRef(self._FindType(type_.ref_type))
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _NamespaceTypeDependencies(self):
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Returns a dict ordered by namespace name containing a mapping of
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    model.Namespace to every _TypeDependency for |self._default_namespace|,
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sorted by the type's name.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dependencies = set()
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for function in self._default_namespace.functions.values():
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for param in function.params:
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        dependencies |= self._TypeDependencies(param.type_,
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               hard=not param.optional)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if function.callback:
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for param in function.callback.params:
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          dependencies |= self._TypeDependencies(param.type_,
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 hard=not param.optional)
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for type_ in self._default_namespace.types.values():
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for prop in type_.properties.values():
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        dependencies |= self._TypeDependencies(prop.type_,
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               hard=not prop.optional)
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for event in self._default_namespace.events.values():
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for param in event.params:
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        dependencies |= self._TypeDependencies(param.type_,
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               hard=not param.optional)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Make sure that the dependencies are returned in alphabetical order.
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dependency_namespaces = OrderedDict()
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for dependency in sorted(dependencies, key=_TypeDependency.GetSortKey):
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      namespace = dependency.type_.namespace
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if namespace is self._default_namespace:
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if namespace not in dependency_namespaces:
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        dependency_namespaces[namespace] = []
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dependency_namespaces[namespace].append(dependency)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return dependency_namespaces
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _TypeDependencies(self, type_, hard=False):
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Gets all the type dependencies of a property.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    deps = set()
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type == PropertyType.REF:
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      deps.add(_TypeDependency(self._FindType(type_.ref_type), hard=hard))
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.ARRAY:
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # Non-copyable types are not hard because they are wrapped in linked_ptrs
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # when generated. Otherwise they're typedefs, so they're hard (though we
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # could generate those typedefs in every dependent namespace, but that
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # seems weird).
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      deps = self._TypeDependencies(type_.item_type,
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    hard=self.IsCopyable(type_.item_type))
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.CHOICES:
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for type_ in type_.choices:
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        deps |= self._TypeDependencies(type_, hard=self.IsCopyable(type_))
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif type_.property_type == PropertyType.OBJECT:
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for p in type_.properties.values():
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        deps |= self._TypeDependencies(p.type_, hard=not p.optional)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return deps
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GeneratePropertyValues(self, property, line, nodoc=False):
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Generates the Code to display all value-containing properties.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = Code()
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not nodoc:
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Comment(property.description)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if property.value is not None:
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Append(line % {
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "type": self.GetCppType(property.type_),
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "name": property.name,
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "value": property.value
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        })
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_child_code = False
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Sblock('namespace %s {' % property.name)
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for child_property in property.type_.properties.values():
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        child_code = self.GeneratePropertyValues(child_property,
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 line,
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 nodoc=nodoc)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if child_code:
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          has_child_code = True
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          c.Concat(child_code)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      c.Eblock('}  // namespace %s' % property.name)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not has_child_code:
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        c = None
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return c
274