Skip to content

Commit b383639

Browse files
authored
fix(AIP-4232): correct repeated field check (#1337)
1 parent d617cc1 commit b383639

File tree

3 files changed

+32
-17
lines changed

3 files changed

+32
-17
lines changed

rules/aip4232/repeated_fields.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,21 @@ var repeatedFields = &lint.MethodRule{
3333
in := m.GetInputType()
3434

3535
for _, sig := range sigs {
36-
for i, name := range sig {
37-
// Skip the last field in the signature, it can be repeated.
38-
if i == len(sig)-1 {
39-
break
36+
for _, name := range sig {
37+
if !strings.Contains(name, ".") {
38+
continue
4039
}
40+
chain := strings.Split(name, ".")
4141

42-
if f := in.FindFieldByName(name); f != nil && f.IsRepeated() {
43-
problems = append(problems, lint.Problem{
44-
Message: fmt.Sprintf("Field %q in method_signature %q: only the last field can be repeated.", name, strings.Join(sig, ",")),
45-
Descriptor: m,
46-
})
42+
// Exclude the last one from the look up since it can be repeated.
43+
for i := range chain[:len(chain)-1] {
44+
n := strings.Join(chain[:i+1], ".")
45+
if f := utils.FindFieldDotNotation(in, n); f != nil && f.IsRepeated() {
46+
problems = append(problems, lint.Problem{
47+
Message: fmt.Sprintf("Field %q in method_signature %q: only the last field in a signature argument can be repeated.", name, strings.Join(sig, ",")),
48+
Descriptor: m,
49+
})
50+
}
4751
}
4852
}
4953
}

rules/aip4232/repeated_fields_test.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ func TestRepeatedFields(t *testing.T) {
2727
SecondSig string
2828
problems testutils.Problems
2929
}{
30-
{"Valid", "name,paperback_only,editions", "name,editions", nil},
31-
{"InvalidFirstSignature", "name,editions,paperback_only", "name,editions", testutils.Problems{{Message: "only the last"}}},
32-
{"InvalidSecondSignature", "name,editions", "name,editions,paperback_only", testutils.Problems{{Message: "only the last"}}},
33-
{"BothInvalid", "name,editions,paperback_only", "editions,name", testutils.Problems{{Message: "only the last"}, {Message: "only the last"}}},
30+
{"Valid", "name,paperback_only,book.editions", "name,editions", nil},
31+
{"InvalidFirstSignature", "name,book.shelves.shelf,paperback_only", "name,editions", testutils.Problems{{Message: "only the last"}}},
32+
{"InvalidSecondSignature", "name,book.editions", "name,book.shelves.shelf,paperback_only", testutils.Problems{{Message: "only the last"}}},
33+
{"BothInvalid", "name,book.shelves.shelf,paperback_only", "name,book.shelves.shelf,paperback_only", testutils.Problems{{Message: "only the last"}, {Message: "only the last"}}},
3434
}
3535

3636
for _, test := range tests {
@@ -47,8 +47,18 @@ func TestRepeatedFields(t *testing.T) {
4747
string name = 1;
4848
4949
bool paperback_only = 2;
50-
51-
repeated int32 editions = 3;
50+
51+
Book book = 3;
52+
}
53+
message Book {
54+
string name = 1;
55+
56+
repeated int32 editions = 2;
57+
58+
repeated Shelf shelves = 3;
59+
}
60+
message Shelf {
61+
string shelf = 1;
5262
}
5363
message ArchiveBookResponse {}
5464
`, test)

rules/internal/utils/find.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,14 @@ func GetRepeatedMessageFields(m *desc.MessageDescriptor) []*desc.FieldDescriptor
134134
// google.api.method_signature annotations.
135135
func FindFieldDotNotation(msg *desc.MessageDescriptor, ref string) *desc.FieldDescriptor {
136136
path := strings.Split(ref, ".")
137-
for _, seg := range path {
137+
end := len(path) - 1
138+
for i, seg := range path {
138139
field := msg.FindFieldByName(seg)
139140
if field == nil {
140141
return nil
141142
}
142143

143-
if m := field.GetMessageType(); m != nil {
144+
if m := field.GetMessageType(); m != nil && i != end {
144145
msg = m
145146
continue
146147
}

0 commit comments

Comments
 (0)