Handle contained declarations for interfaces and structs.

R=rudominer@chromium.org, rudominer
BUG= #461

Review URL: https://codereview.chromium.org/1427893002 .
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
index 1433030..86c71ce 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/module.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
@@ -365,6 +365,8 @@
   ReferenceKind.AddSharedProperty('imported_from')
   ReferenceKind.AddSharedProperty('methods')
   ReferenceKind.AddSharedProperty('attributes')
+  ReferenceKind.AddSharedProperty('constants')
+  ReferenceKind.AddSharedProperty('enums')
 
   def __init__(self, name=None, module=None, attributes=None):
     if name is not None:
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/mojom_translator.py b/mojo/public/tools/bindings/pylib/mojom/generate/mojom_translator.py
index 69a364d..25334c6 100755
--- a/mojo/public/tools/bindings/pylib/mojom/generate/mojom_translator.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/mojom_translator.py
@@ -145,7 +145,8 @@
     mojom_struct = mojom_type.struct_type
     self.PopulateUserDefinedType(struct, mojom_struct)
     struct.fields = [self.StructFieldFromMojom(f) for f in mojom_struct.fields]
-    # TODO(azani): Handle mojom_struct.decl_data.contained_declarations.
+    self.PopulateContainedDeclarationsFromMojom(
+        struct, mojom_struct.decl_data.contained_declarations)
 
   def UnionFieldFromMojom(self, mojom_field):
     """Translates a mojom_types_mojom.UnionField to a module.UnionField.
@@ -211,18 +212,42 @@
     field.kind = self.KindFromMojom(mojom_field.type)
     field.attributes = self.AttributesFromMojom(mojom_field)
 
-  def EnumFromMojom(self, enum, mojom_type, parent_kind=None):
+  def PopulateContainedDeclarationsFromMojom(
+      self, parent_kind, contained_declarations):
+    """Populates a module.Struct|module.Interface with contained declarations.
+
+    Args:
+      parent_kind: {module.Struct|module.Interface} to be populated.
+      contained_declarations: {mojom_types_mojom.ContainedDeclarations} from
+        which the contained types need to be extracted.
+    """
+    if not contained_declarations:
+      return
+
+    if contained_declarations.enums:
+      for enum_key in contained_declarations.enums:
+        enum = self.UserDefinedFromTypeKey(enum_key)
+        enum.name = '%s.%s' % (parent_kind.name, enum.name)
+        enum.parent_kind = parent_kind
+        parent_kind.enums.append(enum)
+
+    if contained_declarations.constants:
+      for const_key in contained_declarations.constants:
+        const = self.ConstFromMojom(
+            self._graph.resolved_values[const_key].declared_constant,
+            parent_kind)
+        parent_kind.constants.append(const)
+
+  def EnumFromMojom(self, enum, mojom_type):
     """Populates a module.Enum based on a MojomEnum.
 
     Args:
       enum: {module.Enum} to be populated.
       mojom_type: {mojom_types_mojom.Type} referring to the MojomEnum to be
         translated.
-      parent_kind: {MojomStruct|MojomInterface} in which the enum is nested.
     """
     assert mojom_type.tag == mojom_types_mojom.UserDefinedType.Tags.enum_type
     mojom_enum = mojom_type.enum_type
-    enum.parent_kind = parent_kind
     self.PopulateUserDefinedType(enum, mojom_enum)
     enum.fields = [self.EnumFieldFromMojom(value)
         for value in mojom_enum.values]
@@ -315,6 +340,8 @@
     interface.name = mojom_interface.interface_name
     interface.methods = [self.MethodFromMojom(mojom_method, interface)
         for mojom_method in mojom_interface.methods.itervalues()]
+    self.PopulateContainedDeclarationsFromMojom(
+        interface, mojom_interface.decl_data.contained_declarations)
 
   def MethodFromMojom(self, mojom_method, interface):
     """Translates a mojom_types_mojom.MojomMethod to a module.Method.
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/mojom_translator_unittest.py b/mojo/public/tools/bindings/pylib/mojom/generate/mojom_translator_unittest.py
index 1784049..b4c8001 100644
--- a/mojo/public/tools/bindings/pylib/mojom/generate/mojom_translator_unittest.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/mojom_translator_unittest.py
@@ -238,7 +238,7 @@
     enum = module.Enum()
     translator = mojom_translator.FileTranslator(graph, file_name)
     translator.EnumFromMojom(
-        enum, mojom_types_mojom.UserDefinedType(enum_type=mojom_enum), None)
+        enum, mojom_types_mojom.UserDefinedType(enum_type=mojom_enum))
 
     self.assertEquals(translator._module, enum.module)
     self.assertEquals(mojom_enum.decl_data.short_name, enum.name)
@@ -448,6 +448,45 @@
     self.assertEquals(module.UINT64, param.kind)
     self.assertEquals(mojom_param.decl_data.declared_ordinal, param.ordinal)
 
+  def test_contained_declarations(self):
+    graph = mojom_files_mojom.MojomFileGraph()
+    file_name = 'root/f.mojom'
+
+    mojom_enum = mojom_types_mojom.MojomEnum(
+        values=[],
+        decl_data=mojom_types_mojom.DeclarationData(
+          short_name='AnEnum',
+          source_file_info=mojom_types_mojom.SourceFileInfo(
+            file_name=file_name)))
+    graph.resolved_types = {
+        'enum_key': mojom_types_mojom.UserDefinedType(enum_type=mojom_enum)}
+
+    mojom_const = mojom_types_mojom.DeclaredConstant(
+        decl_data=mojom_types_mojom.DeclarationData(short_name='AConst'),
+        type=mojom_types_mojom.Type(
+          simple_type=mojom_types_mojom.SimpleType.INT64),
+        value=mojom_types_mojom.Value(
+          literal_value=mojom_types_mojom.LiteralValue(
+            int64_value=30)))
+    user_defined_value = mojom_types_mojom.UserDefinedValue()
+    user_defined_value.declared_constant = mojom_const
+    graph.resolved_values = {'value_key': user_defined_value}
+
+    contained_declarations = mojom_types_mojom.ContainedDeclarations(
+        enums=['enum_key'], constants=['value_key'])
+
+    translator = mojom_translator.FileTranslator(graph, file_name)
+    struct = module.Struct(name='parent')
+    translator.PopulateContainedDeclarationsFromMojom(
+        struct, contained_declarations)
+
+    self.assertEquals(
+        'parent.' + mojom_enum.decl_data.short_name, struct.enums[0].name)
+    self.assertEquals(struct, struct.enums[0].parent_kind)
+    self.assertEquals(
+        mojom_const.decl_data.short_name, struct.constants[0].name)
+    self.assertEquals(struct, struct.constants[0].parent_kind)
+
 
 @unittest.skipUnless(bindings_imported, 'Could not import python bindings.')
 class TestEvalValue(unittest.TestCase):