Mojom parser: Compute and validate struct field ordinals.

In mojom_types.mojom struct fields are supposed to be listed in ordinal order, and the
original lexical order is preserved in a field of DeclarationData called |declaration_order|.

Additionally there is a field of DeclarationData called |declared_ordinal| that records if an
explicit ordinal has been specified.

Previously only the |declared_ordinal| bit was implemented. This has worked so far because the
actual field ordinals are currently computed in the Python back-end using the |declared_ordinal| field.

This CL implements the missing bits which will allow us in a follow-up CL to eliminate the logic from the Python backend. Implementing the missing bits is also important because we are starting to re-write the backends in Go
and also because the runtime type information requires it.

This CL only deals with struct fields. There will be follow-up CLs for union fields and other things. Note that some
ordinals are already being fully handled by the parser, namely method ordinals.

BUG=696
R=azani@chromium.org

Review URL: https://codereview.chromium.org/1767033002 .
diff --git a/mojo/public/tools/bindings/mojom_tool/bin/linux64/mojom.sha1 b/mojo/public/tools/bindings/mojom_tool/bin/linux64/mojom.sha1
index 63f1960..346ce12 100644
--- a/mojo/public/tools/bindings/mojom_tool/bin/linux64/mojom.sha1
+++ b/mojo/public/tools/bindings/mojom_tool/bin/linux64/mojom.sha1
@@ -1 +1 @@
-52754acd9f19c091113ffd6a7cc15bdbd894ffec
\ No newline at end of file
+79987c1fd81b4941aee5c6ee08ee04d268ba64a3
\ No newline at end of file
diff --git a/mojo/public/tools/bindings/mojom_tool/bin/mac64/mojom.sha1 b/mojo/public/tools/bindings/mojom_tool/bin/mac64/mojom.sha1
index e829ce9..7939d8e 100644
--- a/mojo/public/tools/bindings/mojom_tool/bin/mac64/mojom.sha1
+++ b/mojo/public/tools/bindings/mojom_tool/bin/mac64/mojom.sha1
@@ -1 +1 @@
-5d974a5aae75a7a76ea34a4826c1372e409cb38e
\ No newline at end of file
+bb5eb7d890b76a48e2699ff5d03f153f4c3ec66f
\ No newline at end of file
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 2ae6060..23f59b1 100755
--- a/mojo/public/tools/bindings/pylib/mojom/generate/mojom_translator.py
+++ b/mojo/public/tools/bindings/pylib/mojom/generate/mojom_translator.py
@@ -190,7 +190,11 @@
     assert mojom_type.tag == mojom_types_mojom.UserDefinedType.Tags.struct_type
     mojom_struct = mojom_type.struct_type
     self.PopulateUserDefinedType(struct, mojom_struct)
-    struct.fields = [self.StructFieldFromMojom(f) for f in mojom_struct.fields]
+    # mojom_struct.fields is indexed by the field ordinals. We want
+    # to capture these ordinals but sort struct.fields by declaration_order.
+    struct.fields = [self.StructFieldFromMojom(ordinal, f) for (ordinal, f) in
+        enumerate(mojom_struct.fields)]
+    struct.fields.sort(key=lambda field: field.declaration_order)
     self.PopulateContainedDeclarationsFromMojom(
         struct, mojom_struct.decl_data.contained_declarations)
 
@@ -208,10 +212,13 @@
     union_field.ordinal = self.OrdinalFromMojom(mojom_field)
     return union_field
 
-  def StructFieldFromMojom(self, mojom_field):
+  def StructFieldFromMojom(self, ordinal, mojom_field):
     """Translates a mojom_types_mojom.StructField to a module.StructField.
 
     Args:
+      ordinal: {int} The 0-based ordinal position of the field within the
+               struct. Note that this is not necessarily the same as the lexical
+               order or the packing order.
       mojom_field: {mojom_types_mojom.StructField} to be translated.
 
     Returns:
@@ -219,7 +226,13 @@
     """
     struct_field = module.StructField()
     self.PopulateCommonFieldValues(struct_field, mojom_field)
+    # Note that the |ordinal| attribute of |struct_field| records only the
+    # *declared* ordinal and as such is not defined for every field whereas
+    # the |computed_ordinal| attribute is defined for every field. If
+    # |ordinal| is defined then it is equal to |computed_ordinal|.
     struct_field.ordinal = self.OrdinalFromMojom(mojom_field)
+    struct_field.computed_ordinal = ordinal
+    struct_field.declaration_order = mojom_field.decl_data.declaration_order
     if mojom_field.default_value:
       if (mojom_field.default_value.tag ==
           mojom_types_mojom.DefaultFieldValue.Tags.default_keyword):
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 6b177e3..ab96d64 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
@@ -243,21 +243,32 @@
     mojom_struct = mojom_types_mojom.MojomStruct(
         decl_data=mojom_types_mojom.DeclarationData(short_name='FirstStruct'))
     mojom_struct.fields = [
-        mojom_types_mojom.StructField(
+       mojom_types_mojom.StructField(
           decl_data=mojom_types_mojom.DeclarationData(
-            short_name='field01',
-            declared_ordinal=5),
+            short_name='field03',
+            declaration_order=2),
           type=mojom_types_mojom.Type(
             simple_type=mojom_types_mojom.SimpleType.BOOL)),
         mojom_types_mojom.StructField(
           decl_data=mojom_types_mojom.DeclarationData(
-            short_name='field02'),
+            short_name='field01',
+            declared_ordinal=1,
+            declaration_order=0),
+          type=mojom_types_mojom.Type(
+            simple_type=mojom_types_mojom.SimpleType.BOOL)),
+        mojom_types_mojom.StructField(
+          decl_data=mojom_types_mojom.DeclarationData(
+            short_name='field02',
+            declaration_order=1),
           type=mojom_types_mojom.Type(
             simple_type=mojom_types_mojom.SimpleType.DOUBLE),
           default_value=mojom_types_mojom.DefaultFieldValue(
             value=mojom_types_mojom.Value(
               literal_value=mojom_types_mojom.LiteralValue(double_value=15)))),
         ]
+    # mojom_fields_declaration_order lists, in declaration order, the indices
+    # of the fields in mojom_types_mojom.StructField.
+    mojom_fields_declaration_order = [1, 2, 0]
     mojom_struct.decl_data.source_file_info = mojom_types_mojom.SourceFileInfo(
         file_name=mojom_file.file_name)
 
@@ -270,14 +281,19 @@
     self.assertEquals(translator._module, struct.module)
 
     self.assertEquals(len(mojom_struct.fields), len(struct.fields))
-    for gold, f in zip(mojom_struct.fields, struct.fields):
+    for index, gold_index in enumerate(mojom_fields_declaration_order):
+      gold = mojom_struct.fields[gold_index]
+      f = struct.fields[index]
       self.assertEquals(f.name, gold.decl_data.short_name)
+      if gold.decl_data.declared_ordinal >= 0:
+        self.assertEquals(gold.decl_data.declared_ordinal, f.ordinal)
+      else:
+        self.assertEquals(None, f.ordinal)
+      self.assertEquals(gold_index, f.computed_ordinal)
 
     self.assertEquals(module.BOOL, struct.fields[0].kind)
-    self.assertEquals(5, struct.fields[0].ordinal)
-
     self.assertEquals(module.DOUBLE, struct.fields[1].kind)
-    self.assertEquals(None, struct.fields[1].ordinal)
+
     self.assertEquals('15.0', struct.fields[1].default)
 
   def test_constant(self):
diff --git a/mojom/mojom_parser/mojom/user_defined_types.go b/mojom/mojom_parser/mojom/user_defined_types.go
index 6fb8064..4f1f798 100644
--- a/mojom/mojom_parser/mojom/user_defined_types.go
+++ b/mojom/mojom_parser/mojom/user_defined_types.go
@@ -331,8 +331,9 @@
 
 	structType StructType
 
-	fieldsByName map[string]*StructField
-	Fields       []*StructField
+	fieldsByName         map[string]*StructField
+	FieldsInLexicalOrder []*StructField
+	fieldsInOrdinalOrder []*StructField
 
 	// Used to form an error message in case of a duplicate field name.
 	userFacingName string
@@ -341,7 +342,7 @@
 func NewMojomStruct(declData DeclarationData) *MojomStruct {
 	mojomStruct := new(MojomStruct)
 	mojomStruct.fieldsByName = make(map[string]*StructField)
-	mojomStruct.Fields = make([]*StructField, 0)
+	mojomStruct.FieldsInLexicalOrder = make([]*StructField, 0)
 	mojomStruct.Init(declData, mojomStruct)
 	mojomStruct.userFacingName = mojomStruct.simpleName
 	return mojomStruct
@@ -409,11 +410,19 @@
 		}
 	}
 	s.fieldsByName[field.simpleName] = field
-	s.Fields = append(s.Fields, field)
+	field.lexicalPosition = int32(len(s.FieldsInLexicalOrder))
+	s.FieldsInLexicalOrder = append(s.FieldsInLexicalOrder, field)
 	s.DeclaredObjects = append(s.DeclaredObjects, field)
 	return nil
 }
 
+func (s *MojomStruct) FieldsInOrdinalOrder() []*StructField {
+	if s.fieldsInOrdinalOrder == nil {
+		panic("The method ComputeFieldOrdinals() must be invoked first.")
+	}
+	return s.fieldsInOrdinalOrder
+}
+
 func (*MojomStruct) Kind() UserDefinedTypeKind {
 	return UserDefinedTypeKindStruct
 }
@@ -426,10 +435,67 @@
 	return value.IsDefault()
 }
 
+var ErrOrdinalRange = errors.New("ordinal value out of range")
+var ErrOrdinalDuplicate = errors.New("duplicate ordinal value")
+
+type StructFieldOrdinalError struct {
+	Ord           int64        // The attemted ordinal
+	StructName    string       // The name of the struct in which the problem occurs.
+	Field         *StructField // The field with the attempted ordinal
+	ExistingField *StructField // Used if Err == ErrOrdinalDuplicate
+	Err           error        // the type of error (ErrOrdinalRange, ErrOrdinalDuplicate)
+}
+
+// StructFieldOrdinalError implements error.
+func (e *StructFieldOrdinalError) Error() string {
+	var message string
+	switch e.Err {
+	case ErrOrdinalRange:
+		message = fmt.Sprintf("Invalid ordinal for field %s: %d. "+
+			"A struct field ordinal must be a non-negative integer value "+
+			"less than the number of fields in the struct.",
+			e.Field.SimpleName(), e.Ord)
+	case ErrOrdinalDuplicate:
+		message = fmt.Sprintf("Invalid ordinal for field %s: %d. "+
+			"There is already a field in struct %s with that ordinal: %s.",
+			e.Field.SimpleName(), e.Ord, e.StructName,
+			e.ExistingField.SimpleName())
+	default:
+		panic(fmt.Sprintf("Unrecognized type of MethodOrdinalError %v", e.Err))
+	}
+	return UserErrorMessage(e.Field.OwningFile(), e.Field.NameToken(), message)
+}
+
 // This should be invoked some time after all of the fields have been added
 // to the struct.
-func (s *MojomStruct) ComputeFieldOrdinals() {
-	// TODO(rudominer) Implement MojomStruct.ComputeFieldOrdinals()
+func (s *MojomStruct) ComputeFieldOrdinals() error {
+	numFields := uint32(len(s.FieldsInLexicalOrder))
+	s.fieldsInOrdinalOrder = make([]*StructField, numFields)
+	nextOrdinal := uint32(0)
+	for _, field := range s.FieldsInLexicalOrder {
+		fieldOrdinal := nextOrdinal
+		if field.declaredOrdinal >= 0 {
+			if field.declaredOrdinal >= math.MaxUint32 {
+				return &StructFieldOrdinalError{Ord: field.declaredOrdinal,
+					StructName: s.SimpleName(), Field: field,
+					Err: ErrOrdinalRange}
+			}
+			fieldOrdinal = uint32(field.declaredOrdinal)
+		}
+		if fieldOrdinal >= numFields {
+			return &StructFieldOrdinalError{Ord: int64(fieldOrdinal),
+				StructName: s.SimpleName(), Field: field,
+				Err: ErrOrdinalRange}
+		}
+		if existingField := s.fieldsInOrdinalOrder[fieldOrdinal]; existingField != nil {
+			return &StructFieldOrdinalError{Ord: int64(fieldOrdinal),
+				StructName: s.SimpleName(), Field: field,
+				ExistingField: existingField, Err: ErrOrdinalDuplicate}
+		}
+		s.fieldsInOrdinalOrder[fieldOrdinal] = field
+		nextOrdinal = fieldOrdinal + 1
+	}
+	return nil
 }
 
 func (m MojomStruct) String() string {
@@ -437,7 +503,7 @@
 	s += fmt.Sprintf("%s\n", m.UserDefinedTypeBase)
 	s += "     Fields\n"
 	s += "     ------\n"
-	for _, field := range m.Fields {
+	for _, field := range m.FieldsInLexicalOrder {
 		s += fmt.Sprintf("     %s\n", field)
 	}
 	s += "     Enums\n"
@@ -457,7 +523,7 @@
 // is being used to represent the parameters to a method.
 func (s MojomStruct) ParameterString() string {
 	str := ""
-	for i, f := range s.Fields {
+	for i, f := range s.FieldsInLexicalOrder {
 		if i > 0 {
 			str += ", "
 		}
@@ -613,9 +679,6 @@
 	return false
 }
 
-var ErrOrdinalRange = errors.New("ordinal value out of range")
-var ErrOrdinalDuplicate = errors.New("duplicate ordinal value")
-
 type MethodOrdinalError struct {
 	Ord            int64        // The attemted ordinal
 	InterfaceName  string       // The name of the interface in which the problem occurs.
@@ -1210,6 +1273,11 @@
 	// We use int64 here because valid ordinals are uint32 and we want to
 	// be able to represent an unset value as -1.
 	declaredOrdinal int64
+
+	// The zero-based  position of this element within its containing
+	// lexical scope as it appears in the Mojom declaration, or -1
+	// if this is not set.
+	lexicalPosition int32
 }
 
 func DeclData(name string, owningFile *MojomFile, nameToken lexer.Token, attributes *Attributes) DeclarationData {
@@ -1219,7 +1287,7 @@
 func DeclDataWithOrdinal(name string, owningFile *MojomFile, nameToken lexer.Token,
 	attributes *Attributes, declaredOrdinal int64) DeclarationData {
 	return DeclarationData{simpleName: name, owningFile: owningFile, nameToken: nameToken,
-		attributes: attributes, declaredOrdinal: declaredOrdinal}
+		attributes: attributes, declaredOrdinal: declaredOrdinal, lexicalPosition: -1}
 }
 
 func (d *DeclarationData) SimpleName() string {
@@ -1254,6 +1322,10 @@
 	return d.declaredOrdinal
 }
 
+func (d *DeclarationData) LexicalPosition() int32 {
+	return d.lexicalPosition
+}
+
 func (d *DeclarationData) OwningFile() *MojomFile {
 	return d.owningFile
 }
diff --git a/mojom/mojom_parser/parser/comment_merger_test.go b/mojom/mojom_parser/parser/comment_merger_test.go
index fdce0c0..45c75b3 100644
--- a/mojom/mojom_parser/parser/comment_merger_test.go
+++ b/mojom/mojom_parser/parser/comment_merger_test.go
@@ -66,7 +66,7 @@
 	// Sanity-check that we got the right method.
 	checkEq("Method1", method1.SimpleName())
 
-	inParam1 := method1.Parameters.Fields[0]
+	inParam1 := method1.Parameters.FieldsInLexicalOrder[0]
 	// Sanity-check that we got the right field.
 	checkEq("in_param1", inParam1.SimpleName())
 
diff --git a/mojom/mojom_parser/parser/parser_test.go b/mojom/mojom_parser/parser/parser_test.go
index 54cc3da..c0fc317 100644
--- a/mojom/mojom_parser/parser/parser_test.go
+++ b/mojom/mojom_parser/parser/parser_test.go
@@ -198,7 +198,7 @@
 	import "and.another.file";
 
 	struct Foo{
-		[happy=true] int32 x@4;
+		[happy=true] int32 x@0;
 	};`
 	{
 		expectedFile.AddImport(mojom.NewImportedFile("another.file", nil))
@@ -208,7 +208,7 @@
 		structFoo.InitAsScope(mojom.NewTestFileScope("test.scope"))
 		attributes := mojom.NewAttributes(lexer.Token{})
 		attributes.List = append(attributes.List, mojom.NewMojomAttribute("happy", nil, mojom.MakeBoolLiteralValue(true, nil)))
-		structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataAWithOrdinal("x", attributes, 4), mojom.SimpleTypeInt32, nil))
+		structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataAWithOrdinal("x", attributes, 0), mojom.SimpleTypeInt32, nil))
 		expectedFile.AddStruct(structFoo)
 	}
 	endTestCase()
@@ -224,10 +224,10 @@
 	import "and.another.file";
 
 	struct Foo{
-		int32 x@4 = 42;
+		int32 x@0 = 42;
 		[age=7, level="high"] string  y = "Howdy!";
 		string? z;
-		bool w@6 = false;
+		bool w@3 = false;
 	};`
 	{
 		expectedFile.AddImport(mojom.NewImportedFile("another.file", nil))
@@ -235,13 +235,13 @@
 
 		structFoo := mojom.NewMojomStruct(mojom.DeclTestData("Foo"))
 		structFoo.InitAsScope(mojom.NewTestFileScope("test.scope"))
-		structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataWithOrdinal("x", 4), mojom.SimpleTypeInt32, mojom.MakeInt8LiteralValue(42, nil)))
+		structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataWithOrdinal("x", 0), mojom.SimpleTypeInt32, mojom.MakeInt8LiteralValue(42, nil)))
 		attributes := mojom.NewAttributes(lexer.Token{})
 		attributes.List = append(attributes.List, mojom.NewMojomAttribute("age", nil, mojom.MakeInt8LiteralValue(7, nil)))
 		attributes.List = append(attributes.List, mojom.NewMojomAttribute("level", nil, mojom.MakeStringLiteralValue("high", nil)))
 		structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataA("y", attributes), mojom.BuiltInType("string"), mojom.MakeStringLiteralValue("Howdy!", nil)))
 		structFoo.AddField(mojom.NewStructField(mojom.DeclTestData("z"), mojom.BuiltInType("string?"), nil))
-		structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataWithOrdinal("w", 6), mojom.BuiltInType("bool"), mojom.MakeBoolLiteralValue(false, nil)))
+		structFoo.AddField(mojom.NewStructField(mojom.DeclTestDataWithOrdinal("w", 3), mojom.BuiltInType("bool"), mojom.MakeBoolLiteralValue(false, nil)))
 		expectedFile.AddStruct(structFoo)
 	}
 	endTestCase()
@@ -515,6 +515,141 @@
 	endTestCase()
 
 	////////////////////////////////////////////////////////////
+	// Test Case (Invalid struct field ordinal: empty string
+	////////////////////////////////////////////////////////////
+	startTestCase("")
+	cases[testCaseNum].mojomContents = `
+	struct MyStruct {
+		int32 x@;
+	};
+
+	`
+	expectError("field \"x\": Invalid ordinal string following '@'")
+	expectError("Ordinals must be decimal integers between 0 and 4294967294")
+	endTestCase()
+
+	////////////////////////////////////////////////////////////
+	// Test Case (Invalid struct field ordinal: Not a number
+	////////////////////////////////////////////////////////////
+	startTestCase("")
+	cases[testCaseNum].mojomContents = `
+	struct MyStruct {
+		int32 x@happy;
+	};
+
+	`
+	expectError("field \"x\": Invalid ordinal string following '@'")
+	expectError("Ordinals must be decimal integers between 0 and 4294967294")
+	endTestCase()
+
+	////////////////////////////////////////////////////////////
+	// Test Case (Invalid struct field ordinal: Negative
+	////////////////////////////////////////////////////////////
+	startTestCase("")
+	cases[testCaseNum].mojomContents = `
+	struct MyStruct {
+		int32 x@-500;
+	};
+
+	`
+	expectError("field \"x\": Invalid ordinal string following '@'")
+	expectError("Ordinals must be decimal integers between 0 and 4294967294")
+	endTestCase()
+
+	////////////////////////////////////////////////////////////
+	// Test Case (Invalid struct field ordinal: too big for uint32)
+	////////////////////////////////////////////////////////////
+	startTestCase("")
+	cases[testCaseNum].mojomContents = `
+	struct MyStruct {
+		int32 x@4294967295;
+	};
+
+	`
+	expectError("field \"x\": Invalid ordinal string following '@'")
+	expectError("4294967295")
+	expectError("Ordinals must be decimal integers between 0 and 4294967294")
+	endTestCase()
+
+	////////////////////////////////////////////////////////////
+	// Test Case (Invalid struct field ordinal: too big for uint64)
+	////////////////////////////////////////////////////////////
+	startTestCase("")
+	cases[testCaseNum].mojomContents = `
+	struct MyStruct {
+		int32 x@999999999999999999999999999999999999999;
+	};
+
+	`
+	expectError("field \"x\": Invalid ordinal string following '@'")
+	expectError("999999999999999999999999999999999999999")
+	expectError("Ordinals must be decimal integers between 0 and 4294967294")
+	endTestCase()
+
+	////////////////////////////////////////////////////////////
+	// Test Case (Invalid struct field ordinal: too big for size of struct)
+	////////////////////////////////////////////////////////////
+	startTestCase("")
+	cases[testCaseNum].mojomContents = `
+	struct MyStruct {
+		int32 x;
+		int32 y@2;
+	};
+
+	`
+	expectError("Invalid ordinal for field y: 2.")
+	expectError("A struct field ordinal must be a non-negative integer value less than the number of fields in the struct.")
+	endTestCase()
+
+	////////////////////////////////////////////////////////////
+	// Test Case (Invalid struct field ordinal: implicit next value too big for size of struct)
+	////////////////////////////////////////////////////////////
+	startTestCase("")
+	cases[testCaseNum].mojomContents = `
+	struct MyStruct {
+		int32 x;
+		int32 y@2;
+		int32 z;
+	};
+
+	`
+	expectError("Invalid ordinal for field z: 3.")
+	expectError("A struct field ordinal must be a non-negative integer value less than the number of fields in the struct.")
+	endTestCase()
+
+	////////////////////////////////////////////////////////////
+	// Test Case (Invalid struct field ordinal: Duplicate explicit)
+	////////////////////////////////////////////////////////////
+	startTestCase("")
+	cases[testCaseNum].mojomContents = `
+	struct MyStruct {
+		int32 x@0;
+		int32 y;
+		int32 z@0;
+	};
+
+	`
+	expectError("Invalid ordinal for field z: 0.")
+	expectError("There is already a field in struct MyStruct with that ordinal: x")
+	endTestCase()
+
+	////////////////////////////////////////////////////////////
+	// Test Case (Invalid struct field ordinal: Duplicate implicit)
+	////////////////////////////////////////////////////////////
+	startTestCase("")
+	cases[testCaseNum].mojomContents = `
+	struct MyStruct {
+		int32 x;
+		int32 y;
+		int32 z@1;
+	};
+
+	`
+	expectError("Invalid ordinal for field z: 1.")
+	expectError("There is already a field in struct MyStruct with that ordinal: y")
+	endTestCase()
+
+	////////////////////////////////////////////////////////////
 	// Test Case (Invalid method ordinal: too big for uint32)
 	////////////////////////////////////////////////////////////
 	startTestCase("")
diff --git a/mojom/mojom_parser/parser/parsing.go b/mojom/mojom_parser/parser/parsing.go
index a8b1128..2fa321a 100644
--- a/mojom/mojom_parser/parser/parsing.go
+++ b/mojom/mojom_parser/parser/parsing.go
@@ -654,7 +654,10 @@
 	}
 
 	if p.OK() {
-		paramStruct.ComputeFieldOrdinals()
+		if err := paramStruct.ComputeFieldOrdinals(); err != nil {
+			p.err = err
+			return nil
+		}
 	}
 	return
 }
@@ -750,8 +753,12 @@
 		}
 	}
 	if p.OK() {
-		mojomStruct.ComputeFieldOrdinals()
+		if err := mojomStruct.ComputeFieldOrdinals(); err != nil {
+			p.err = err
+			return false
+		}
 	}
+
 	return p.OK()
 }
 
diff --git a/mojom/mojom_parser/parser/resolution_test.go b/mojom/mojom_parser/parser/resolution_test.go
index 789374b..8bd7323 100644
--- a/mojom/mojom_parser/parser/resolution_test.go
+++ b/mojom/mojom_parser/parser/resolution_test.go
@@ -1045,7 +1045,7 @@
 
 		testFunc := func(descriptor *mojom.MojomDescriptor) error {
 			myStructType := descriptor.TypesByKey["TYPE_KEY:MyStruct"].(*mojom.MojomStruct)
-			aColorField := myStructType.Fields[0]
+			aColorField := myStructType.FieldsInLexicalOrder[0]
 			concreteValue := aColorField.DefaultValue.ResolvedConcreteValue().(*mojom.EnumValue)
 			key := concreteValue.ValueKey()
 			if key != "TYPE_KEY:Color.BLUE" {
diff --git a/mojom/mojom_parser/serialization/serialization.go b/mojom/mojom_parser/serialization/serialization.go
index d4ddff3..502dea4 100644
--- a/mojom/mojom_parser/serialization/serialization.go
+++ b/mojom/mojom_parser/serialization/serialization.go
@@ -256,7 +256,7 @@
 	mojomStruct.DeclData = translateDeclarationData(&s.DeclarationData)
 	mojomStruct.DeclData.ContainedDeclarations = translateContainedDeclarations(&s.NestedDeclarations)
 
-	for _, field := range s.Fields {
+	for _, field := range s.FieldsInOrdinalOrder() {
 		mojomStruct.Fields = append(mojomStruct.Fields, translateStructField(field))
 	}
 
@@ -611,8 +611,11 @@
 	}
 
 	// declaration_order
-	// TODO(rudominer) DeclarationOrder is currently not populated.
-	declData.DeclarationOrder = -1
+	if d.LexicalPosition() < 0 {
+		declData.DeclarationOrder = -1
+	} else {
+		declData.DeclarationOrder = d.LexicalPosition()
+	}
 
 	// container_type_key
 	containingType := d.ContainingType()
diff --git a/mojom/mojom_parser/serialization/serialization_test.go b/mojom/mojom_parser/serialization/serialization_test.go
index 3c543f5..9723a2e 100644
--- a/mojom/mojom_parser/serialization/serialization_test.go
+++ b/mojom/mojom_parser/serialization/serialization_test.go
@@ -71,41 +71,61 @@
 	test.testCaseNum += 1
 }
 
-// newShortDeclData constructs a new DeclarationData with the given data.
+// newShortDeclDataO constructs a new DeclarationData with the given data.
 func (test *singleFileTest) newShortDeclData(shortName string) *mojom_types.DeclarationData {
 	declData := test.newContainedDeclData(shortName, "", nil)
 	declData.FullIdentifier = nil
 	return declData
 }
 
+// newShortDeclDataO constructs a new DeclarationData with the given data.
+func (test *singleFileTest) newShortDeclDataO(declarationOrder, declaredOrdinal int32, shortName string) *mojom_types.DeclarationData {
+	declData := test.newContainedDeclDataA(declarationOrder, declaredOrdinal, shortName, "", nil, nil)
+	declData.FullIdentifier = nil
+	return declData
+}
+
 // newDeclData constructs a new DeclarationData with the given data.
 func (test *singleFileTest) newDeclData(shortName, fullIdentifier string) *mojom_types.DeclarationData {
 	return test.newContainedDeclData(shortName, fullIdentifier, nil)
 }
 
+// newDeclData constructs a new DeclarationData with the given data.
+func (test *singleFileTest) newDeclDataO(declarationOrder, declaredOrdinal int32, shortName, fullIdentifier string) *mojom_types.DeclarationData {
+	return test.newContainedDeclDataA(declarationOrder, declaredOrdinal, shortName, fullIdentifier, nil, nil)
+}
+
 // newDeclDataA constructs a new DeclarationData with the given data, including attributes.
 func (test *singleFileTest) newDeclDataA(shortName, fullIdentifier string,
 	attributes *[]mojom_types.Attribute) *mojom_types.DeclarationData {
-	return test.newContainedDeclDataA(shortName, fullIdentifier, nil, attributes)
+	return test.newContainedDeclDataA(-1, -1, shortName, fullIdentifier, nil, attributes)
 }
 
 // newShortDeclDataA constructs a new DeclarationData with the given data, including attributes.
 func (test *singleFileTest) newShortDeclDataA(shortName string,
 	attributes *[]mojom_types.Attribute) *mojom_types.DeclarationData {
-	declData := test.newContainedDeclDataA(shortName, "", nil, attributes)
+	declData := test.newContainedDeclDataA(-1, -1, shortName, "", nil, attributes)
+	declData.FullIdentifier = nil
+	return declData
+}
+
+// newShortDeclDataA constructs a new DeclarationData with the given data, including attributes.
+func (test *singleFileTest) newShortDeclDataAO(declarationOrder, declaredOrdinal int32, shortName string,
+	attributes *[]mojom_types.Attribute) *mojom_types.DeclarationData {
+	declData := test.newContainedDeclDataA(declarationOrder, declaredOrdinal, shortName, "", nil, attributes)
 	declData.FullIdentifier = nil
 	return declData
 }
 
 // newContainedDeclData constructs a new DeclarationData with the given data.
 func (test *singleFileTest) newContainedDeclData(shortName, fullIdentifier string, containerTypeKey *string) *mojom_types.DeclarationData {
-	return test.newContainedDeclDataA(shortName, fullIdentifier, containerTypeKey, nil)
+	return test.newContainedDeclDataA(-1, -1, shortName, fullIdentifier, containerTypeKey, nil)
 }
 
 // newContainedDeclDataA constructs a new DeclarationData with the given data, including attributes.
-func (test *singleFileTest) newContainedDeclDataA(shortName, fullIdentifier string,
+func (test *singleFileTest) newContainedDeclDataA(declarationOrder, declaredOrdinal int32, shortName, fullIdentifier string,
 	containerTypeKey *string, attributes *[]mojom_types.Attribute) *mojom_types.DeclarationData {
-	return newContainedDeclDataA(test.fileName(), shortName, fullIdentifier, containerTypeKey, attributes)
+	return newContainedDeclDataA(declarationOrder, declaredOrdinal, test.fileName(), shortName, fullIdentifier, containerTypeKey, attributes)
 }
 
 // newDeclData constructs a new DeclarationData with the given data.
@@ -113,19 +133,24 @@
 	return newContainedDeclData(fileName, shortName, fullIdentifier, nil)
 }
 
+// newDeclData constructs a new DeclarationData with the given data.
+func newDeclDataO(declarationOrder, declaredOrdinal int32, fileName, shortName, fullIdentifier string) *mojom_types.DeclarationData {
+	return newContainedDeclDataA(declarationOrder, declaredOrdinal, fileName, shortName, fullIdentifier, nil, nil)
+}
+
 // newDeclDataA constructs a new DeclarationData with the given data, including attributes.
 func newDeclDataA(fileName, shortName, fullIdentifier string,
 	attributes *[]mojom_types.Attribute) *mojom_types.DeclarationData {
-	return newContainedDeclDataA(fileName, shortName, fullIdentifier, nil, attributes)
+	return newContainedDeclDataA(-1, -1, fileName, shortName, fullIdentifier, nil, attributes)
 }
 
 // newContainedDeclData constructs a new DeclarationData with the given data.
 func newContainedDeclData(fileName, shortName, fullIdentifier string, containerTypeKey *string) *mojom_types.DeclarationData {
-	return newContainedDeclDataA(fileName, shortName, fullIdentifier, containerTypeKey, nil)
+	return newContainedDeclDataA(-1, -1, fileName, shortName, fullIdentifier, containerTypeKey, nil)
 }
 
 // newContainedDeclDataA constructs a new DeclarationData with the given data, including attributes.
-func newContainedDeclDataA(fileName, shortName, fullIdentifier string,
+func newContainedDeclDataA(declarationOrder, declaredOrdinal int32, fileName, shortName, fullIdentifier string,
 	containerTypeKey *string, attributes *[]mojom_types.Attribute) *mojom_types.DeclarationData {
 	var fullyQualifiedName *string
 	if fullIdentifier != "" {
@@ -135,8 +160,8 @@
 		Attributes:       attributes,
 		ShortName:        &shortName,
 		FullIdentifier:   fullyQualifiedName,
-		DeclaredOrdinal:  -1,
-		DeclarationOrder: -1,
+		DeclaredOrdinal:  declaredOrdinal,
+		DeclarationOrder: declarationOrder,
 		ContainerTypeKey: containerTypeKey,
 		SourceFileInfo: &mojom_types.SourceFileInfo{
 			FileName: fileName,
@@ -149,6 +174,112 @@
 	test := singleFileTest{}
 
 	////////////////////////////////////////////////////////////
+	// Test Case: struct field ordinals
+	////////////////////////////////////////////////////////////
+	{
+
+		contents := `
+	struct Foo{
+	  int32 x@2;
+	  int32 y@3;
+	  int32 z@0;
+	  int32 w@1;
+	};`
+
+		test.addTestCase("", contents)
+
+		// DeclaredMojomObjects
+		test.expectedFile().DeclaredMojomObjects.Structs = &[]string{"TYPE_KEY:Foo"}
+
+		// ResolvedTypes
+
+		// struct Foo
+		test.expectedGraph().ResolvedTypes["TYPE_KEY:Foo"] = &mojom_types.UserDefinedTypeStructType{mojom_types.MojomStruct{
+			DeclData: test.newDeclData("Foo", "Foo"),
+			Fields: []mojom_types.StructField{
+				// The fields are in ordinal order and the first two arguments to newShortDeclDataO() are
+				// declarationOrder and declaredOrdinal.
+
+				// field z
+				{
+					DeclData: test.newShortDeclDataO(2, 0, "z"),
+					Type:     &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
+				},
+				// field w
+				{
+					DeclData: test.newShortDeclDataO(3, 1, "w"),
+					Type:     &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
+				},
+				// field x
+				{
+					DeclData: test.newShortDeclDataO(0, 2, "x"),
+					Type:     &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
+				},
+				// field y
+				{
+					DeclData: test.newShortDeclDataO(1, 3, "y"),
+					Type:     &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
+				},
+			},
+		}}
+
+		test.endTestCase()
+	}
+
+	////////////////////////////////////////////////////////////
+	// Test Case: struct field ordinals, some implicit
+	////////////////////////////////////////////////////////////
+	{
+
+		contents := `
+	struct Foo{
+	  int32 x@2;
+	  int32 y;
+	  int32 z@0;
+	  int32 w;
+	};`
+
+		test.addTestCase("", contents)
+
+		// DeclaredMojomObjects
+		test.expectedFile().DeclaredMojomObjects.Structs = &[]string{"TYPE_KEY:Foo"}
+
+		// ResolvedTypes
+
+		// struct Foo
+		test.expectedGraph().ResolvedTypes["TYPE_KEY:Foo"] = &mojom_types.UserDefinedTypeStructType{mojom_types.MojomStruct{
+			DeclData: test.newDeclData("Foo", "Foo"),
+			Fields: []mojom_types.StructField{
+				// The fields are in ordinal order and the first two arguments to newShortDeclDataO() are
+				// declarationOrder and declaredOrdinal.
+
+				// field z
+				{
+					DeclData: test.newShortDeclDataO(2, 0, "z"),
+					Type:     &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
+				},
+				// field w
+				{
+					DeclData: test.newShortDeclDataO(3, -1, "w"),
+					Type:     &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
+				},
+				// field x
+				{
+					DeclData: test.newShortDeclDataO(0, 2, "x"),
+					Type:     &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
+				},
+				// field y
+				{
+					DeclData: test.newShortDeclDataO(1, -1, "y"),
+					Type:     &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
+				},
+			},
+		}}
+
+		test.endTestCase()
+	}
+
+	////////////////////////////////////////////////////////////
 	// Test Case: array of int32
 	////////////////////////////////////////////////////////////
 	{
@@ -174,25 +305,25 @@
 			Fields: []mojom_types.StructField{
 				// field bar1 is not nullable and not fixed length
 				{
-					DeclData: test.newShortDeclData("bar1"),
+					DeclData: test.newShortDeclDataO(0, -1, "bar1"),
 					Type: &mojom_types.TypeArrayType{mojom_types.ArrayType{
 						false, -1, &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32}}},
 				},
 				// field bar2 is not nullable and fixed length of 7
 				{
-					DeclData: test.newShortDeclData("bar2"),
+					DeclData: test.newShortDeclDataO(1, -1, "bar2"),
 					Type: &mojom_types.TypeArrayType{mojom_types.ArrayType{
 						false, 7, &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32}}},
 				},
 				// field bar3 is nullable and not fixed length
 				{
-					DeclData: test.newShortDeclData("bar3"),
+					DeclData: test.newShortDeclDataO(2, -1, "bar3"),
 					Type: &mojom_types.TypeArrayType{mojom_types.ArrayType{
 						true, -1, &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32}}},
 				},
 				// field bar4 is nullable and fixed length of 8
 				{
-					DeclData: test.newShortDeclData("bar4"),
+					DeclData: test.newShortDeclDataO(3, -1, "bar4"),
 					Type: &mojom_types.TypeArrayType{mojom_types.ArrayType{
 						true, 8, &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32}}},
 				},
@@ -228,7 +359,7 @@
 			Fields: []mojom_types.StructField{
 				// field bar1 is non-nullable with a non-nullable key.
 				{
-					DeclData: test.newShortDeclData("bar1"),
+					DeclData: test.newShortDeclDataO(0, -1, "bar1"),
 					Type: &mojom_types.TypeMapType{mojom_types.MapType{
 						false,
 						&mojom_types.TypeStringType{mojom_types.StringType{false}},
@@ -236,7 +367,7 @@
 				},
 				// field bar2 is non-nullable with a nullable key.
 				{
-					DeclData: test.newShortDeclData("bar2"),
+					DeclData: test.newShortDeclDataO(1, -1, "bar2"),
 					Type: &mojom_types.TypeMapType{mojom_types.MapType{
 						false,
 						&mojom_types.TypeStringType{mojom_types.StringType{true}},
@@ -244,7 +375,7 @@
 				},
 				// field bar3 is nullable with a non-nullable key.
 				{
-					DeclData: test.newShortDeclData("bar3"),
+					DeclData: test.newShortDeclDataO(2, -1, "bar3"),
 					Type: &mojom_types.TypeMapType{mojom_types.MapType{
 						true,
 						&mojom_types.TypeStringType{mojom_types.StringType{false}},
@@ -252,7 +383,7 @@
 				},
 				// field bar4 is nullable with a nullable key.
 				{
-					DeclData: test.newShortDeclData("bar4"),
+					DeclData: test.newShortDeclDataO(3, -1, "bar4"),
 					Type: &mojom_types.TypeMapType{mojom_types.MapType{
 						true,
 						&mojom_types.TypeStringType{mojom_types.StringType{true}},
@@ -409,7 +540,7 @@
 			Fields: []mojom_types.StructField{
 				// field a_color
 				{
-					DeclData: test.newShortDeclData("a_color"),
+					DeclData: test.newShortDeclDataO(0, -1, "a_color"),
 					Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 						false, false, stringPointer("Color"), stringPointer("TYPE_KEY:Color")}},
 					DefaultValue: &mojom_types.DefaultFieldValueValue{&mojom_types.ValueUserValueReference{
@@ -453,7 +584,7 @@
 						DeclData: test.newDeclData("EchoString-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: test.newDeclData("value", ""),
+								DeclData: test.newDeclDataO(0, -1, "value", ""),
 								Type:     &mojom_types.TypeStringType{mojom_types.StringType{true}},
 							},
 						},
@@ -462,7 +593,7 @@
 						DeclData: test.newDeclData("EchoString-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: test.newDeclData("value", ""),
+								DeclData: test.newDeclDataO(0, -1, "value", ""),
 								Type:     &mojom_types.TypeStringType{mojom_types.StringType{true}},
 							},
 						},
@@ -474,11 +605,11 @@
 						DeclData: test.newDeclData("DelayedEchoString-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: test.newDeclData("value", ""),
+								DeclData: test.newDeclDataO(0, -1, "value", ""),
 								Type:     &mojom_types.TypeStringType{mojom_types.StringType{true}},
 							},
 							mojom_types.StructField{
-								DeclData: test.newDeclData("millis", ""),
+								DeclData: test.newDeclDataO(1, -1, "millis", ""),
 								Type:     &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
 							},
 						},
@@ -487,7 +618,7 @@
 						DeclData: test.newDeclData("DelayedEchoString-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: test.newDeclData("value", ""),
+								DeclData: test.newDeclDataO(0, -1, "value", ""),
 								Type:     &mojom_types.TypeStringType{mojom_types.StringType{true}},
 							},
 						},
@@ -531,7 +662,7 @@
 						DeclData: test.newDeclData("EchoString-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: test.newDeclData("value", ""),
+								DeclData: test.newDeclDataO(0, -1, "value", ""),
 								Type:     &mojom_types.TypeStringType{mojom_types.StringType{true}},
 							},
 						},
@@ -540,7 +671,7 @@
 						DeclData: test.newDeclData("EchoString-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: test.newDeclData("value", ""),
+								DeclData: test.newDeclDataO(0, -1, "value", ""),
 								Type:     &mojom_types.TypeStringType{mojom_types.StringType{true}},
 							},
 						},
@@ -802,18 +933,18 @@
 			Fields: []mojom_types.StructField{
 				// field x
 				{
-					DeclData: test.newShortDeclData("x"),
+					DeclData: test.newShortDeclDataO(0, -1, "x"),
 					Type:     &mojom_types.TypeSimpleType{mojom_types.SimpleType_InT32},
 				},
 				// field y
 				{
-					DeclData:     test.newShortDeclDataA("y", &[]mojom_types.Attribute{{"min_version", &mojom_types.LiteralValueInt8Value{2}}}),
+					DeclData:     test.newShortDeclDataAO(1, -1, "y", &[]mojom_types.Attribute{{"min_version", &mojom_types.LiteralValueInt8Value{2}}}),
 					Type:         &mojom_types.TypeStringType{mojom_types.StringType{false}},
 					DefaultValue: &mojom_types.DefaultFieldValueValue{&mojom_types.ValueLiteralValue{&mojom_types.LiteralValueStringValue{"hello"}}},
 				},
 				// field z
 				{
-					DeclData: test.newShortDeclData("z"),
+					DeclData: test.newShortDeclDataO(2, -1, "z"),
 					Type:     &mojom_types.TypeStringType{mojom_types.StringType{true}},
 				},
 			},
@@ -1385,7 +1516,7 @@
 						DeclData: newDeclData(test.fileNameA(), "DoIt-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameA(), "x", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameA(), "x", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									false, false, stringPointer("FooA"), stringPointer("TYPE_KEY:a.b.c.FooA")}},
 							},
@@ -1395,7 +1526,7 @@
 						DeclData: newDeclData(test.fileNameA(), "DoIt-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameA(), "y", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameA(), "y", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									true, false, stringPointer("b.c.d.FooB"), stringPointer("TYPE_KEY:b.c.d.FooB")}},
 							},
@@ -1424,7 +1555,7 @@
 						DeclData: newDeclData(test.fileNameB(), "DoIt-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameB(), "x", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameB(), "x", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									false, false, stringPointer("a.b.c.FooA"), stringPointer("TYPE_KEY:a.b.c.FooA")}},
 							},
@@ -1434,7 +1565,7 @@
 						DeclData: newDeclData(test.fileNameB(), "DoIt-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameB(), "y", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameB(), "y", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									true, false, stringPointer("FooB"), stringPointer("TYPE_KEY:b.c.d.FooB")}},
 							},
@@ -1500,7 +1631,7 @@
 						DeclData: newDeclData(test.fileNameA(), "DoIt-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameA(), "x", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameA(), "x", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									false, false, stringPointer("FooA"), stringPointer("TYPE_KEY:a.b.c.FooA")}},
 							},
@@ -1510,7 +1641,7 @@
 						DeclData: newDeclData(test.fileNameA(), "DoIt-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameA(), "y", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameA(), "y", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									true, false, stringPointer("b.c.d.FooB"), stringPointer("TYPE_KEY:b.c.d.FooB")}},
 							},
@@ -1539,7 +1670,7 @@
 						DeclData: newDeclData(test.fileNameB(), "DoIt-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameB(), "x", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameB(), "x", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									false, false, stringPointer("a.b.c.FooA"), stringPointer("TYPE_KEY:a.b.c.FooA")}},
 							},
@@ -1549,7 +1680,7 @@
 						DeclData: newDeclData(test.fileNameB(), "DoIt-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameB(), "y", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameB(), "y", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									true, false, stringPointer("FooB"), stringPointer("TYPE_KEY:b.c.d.FooB")}},
 							},
@@ -1620,7 +1751,7 @@
 						DeclData: newDeclData(test.fileNameA(), "DoIt-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameA(), "x", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameA(), "x", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									false, false, stringPointer("FooA"), stringPointer("TYPE_KEY:a.b.c.FooA")}},
 							},
@@ -1630,7 +1761,7 @@
 						DeclData: newDeclData(test.fileNameA(), "DoIt-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameA(), "y", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameA(), "y", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									true, false, stringPointer("b.c.d.FooB"), stringPointer("TYPE_KEY:b.c.d.FooB")}},
 							},
@@ -1660,7 +1791,7 @@
 						DeclData: newDeclData(test.fileNameB(), "DoIt-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameB(), "x", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameB(), "x", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									false, false, stringPointer("a.b.c.FooA"), stringPointer("TYPE_KEY:a.b.c.FooA")}},
 							},
@@ -1670,7 +1801,7 @@
 						DeclData: newDeclData(test.fileNameB(), "DoIt-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameB(), "y", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameB(), "y", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									true, false, stringPointer("FooB"), stringPointer("TYPE_KEY:b.c.d.FooB")}},
 							},
@@ -1741,7 +1872,7 @@
 						DeclData: newDeclData(test.fileNameA(), "DoIt-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameA(), "x", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameA(), "x", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									false, false, stringPointer("FooA"), stringPointer("TYPE_KEY:a.b.c.FooA")}},
 							},
@@ -1751,7 +1882,7 @@
 						DeclData: newDeclData(test.fileNameA(), "DoIt-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameA(), "y", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameA(), "y", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									true, false, stringPointer("b.c.d.FooB"), stringPointer("TYPE_KEY:b.c.d.FooB")}},
 							},
@@ -1782,7 +1913,7 @@
 			DeclData: newDeclData(test.fileNameB(), "FooB", "b.c.d.FooB"),
 			Fields: []mojom_types.StructField{
 				mojom_types.StructField{
-					DeclData: newDeclData(test.fileNameB(), "x", ""),
+					DeclData: newDeclDataO(0, -1, test.fileNameB(), "x", ""),
 					Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 						false, false, stringPointer("Enum1"), stringPointer("TYPE_KEY:b.c.d.Enum1")}},
 				},
@@ -1799,7 +1930,7 @@
 						DeclData: newDeclData(test.fileNameB(), "DoIt-request", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameB(), "x", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameB(), "x", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									false, false, stringPointer("a.b.c.FooA"), stringPointer("TYPE_KEY:a.b.c.FooA")}},
 							},
@@ -1809,12 +1940,12 @@
 						DeclData: newDeclData(test.fileNameB(), "DoIt-response", ""),
 						Fields: []mojom_types.StructField{
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameB(), "y", ""),
+								DeclData: newDeclDataO(0, -1, test.fileNameB(), "y", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									true, false, stringPointer("FooB"), stringPointer("TYPE_KEY:b.c.d.FooB")}},
 							},
 							mojom_types.StructField{
-								DeclData: newDeclData(test.fileNameB(), "z", ""),
+								DeclData: newDeclDataO(1, -1, test.fileNameB(), "z", ""),
 								Type: &mojom_types.TypeTypeReference{mojom_types.TypeReference{
 									false, false, stringPointer("Enum2"), stringPointer("TYPE_KEY:b.c.d.Enum2")}},
 							},