Repository: jhump/protoreflect (go)
Issue: protoparse: ParseFiles allows reserved and extensions to have 0 value
`protoc` requires that field numbers for `reserved` and `extensions` be positive integers, but protoparse allows 0 values.

```protobuf
syntax = "proto3";
message t{
  reserved 0 to 10;
}
```

protoc result:
```
0.proto: Reserved numbers must be positive integers.
```

```protobuf
syntax = "proto2";
message t{
  extensions 0 to 10;
}
```

protoc result:
```
0.proto:3:14: Extension numbers must be positive integers.
```

Pull request description: Make 1 the lower limit of reserved and extensions ranges
Make 1 the lower limit of reserved and extensions ranges to match protoc's behavior.

fixes #440


Patch:
diff --git a/desc/protoparse/ast/ranges.go b/desc/protoparse/ast/ranges.go
index 341676f..77d3e8d 100644
--- a/desc/protoparse/ast/ranges.go
+++ b/desc/protoparse/ast/ranges.go
@@ -188,7 +188,7 @@ func (n *RangeNode) EndValueAsInt32(min, max int32) (int32, bool) {
 	return AsInt32(n.EndVal, min, max)
 }
 
-// ReservedNode represents reserved declaration, whic can be used to reserve
+// ReservedNode represents reserved declaration, which can be used to reserve
 // either names or numbers. Examples:
 //
 //   reserved 1, 10-12, 15;
diff --git a/desc/protoparse/descriptor_protos.go b/desc/protoparse/descriptor_protos.go
index 4113454..eee8cb6 100644
--- a/desc/protoparse/descriptor_protos.go
+++ b/desc/protoparse/descriptor_protos.go
@@ -279,7 +279,7 @@ func (r *parseResult) asExtensionRanges(node *ast.ExtensionRangeNode, maxTag int
 	opts := r.asUninterpretedOptions(node.Options.GetElements())
 	ers := make([]*dpb.DescriptorProto_ExtensionRange, len(node.Ranges))
 	for i, rng := range node.Ranges {
-		start, end := getRangeBounds(r, rng, 0, maxTag)
+		start, end := getRangeBounds(r, rng, 1, maxTag)
 		er := &dpb.DescriptorProto_ExtensionRange{
 			Start: proto.Int32(start),
 			End:   proto.Int32(end + 1),
@@ -506,7 +506,7 @@ func isMessageSetWireFormat(res *parseResult, scope string, md *dpb.DescriptorPr
 }
 
 func (r *parseResult) asMessageReservedRange(rng *ast.RangeNode, maxTag int32) *dpb.DescriptorProto_ReservedRange {
-	start, end := getRangeBounds(r, rng, 0, maxTag)
+	start, end := getRangeBounds(r, rng, 1, maxTag)
 	rr := &dpb.DescriptorProto_ReservedRange{
 		Start: proto.Int32(start),
 		End:   proto.Int32(end + 1),


Test patch:
diff --git a/desc/protoparse/validate_test.go b/desc/protoparse/validate_test.go
index be014c8..f7e28dc 100644
--- a/desc/protoparse/validate_test.go
+++ b/desc/protoparse/validate_test.go
@@ -224,19 +224,27 @@ func TestBasicValidation(t *testing.T) {
 		},
 		{
 			contents: `message Foo { reserved 1 to 5000000000; }`,
-			errMsg:   `test.proto:1:29: range end 5000000000 is out of range: should be between 0 and 536870911`,
+			errMsg:   `test.proto:1:29: range end 5000000000 is out of range: should be between 1 and 536870911`,
+		},
+		{
+			contents: `message Foo { reserved 0 to 10; }`,
+			errMsg:   `test.proto:1:24: range start 0 is out of range: should be between 1 and 536870911`,
 		},
 		{
 			contents: `message Foo { extensions 3000000000; }`,
-			errMsg:   `test.proto:1:26: range start 3000000000 is out of range: should be between 0 and 536870911`,
+			errMsg:   `test.proto:1:26: range start 3000000000 is out of range: should be between 1 and 536870911`,
 		},
 		{
 			contents: `message Foo { extensions 3000000000 to 3000000001; }`,
-			errMsg:   `test.proto:1:26: range start 3000000000 is out of range: should be between 0 and 536870911`,
+			errMsg:   `test.proto:1:26: range start 3000000000 is out of range: should be between 1 and 536870911`,
+		},
+		{
+			contents: `message Foo { extensions 0 to 10; }`,
+			errMsg:   `test.proto:1:26: range start 0 is out of range: should be between 1 and 536870911`,
 		},
 		{
 			contents: `message Foo { extensions 100 to 3000000000; }`,
-			errMsg:   `test.proto:1:33: range end 3000000000 is out of range: should be between 0 and 536870911`,
+			errMsg:   `test.proto:1:33: range end 3000000000 is out of range: should be between 1 and 536870911`,
 		},
 		{
 			contents: `message Foo { reserved "foo", "foo"; }`,