From e955a4fea83c91094d7530f05383ddcf74d784ac Mon Sep 17 00:00:00 2001 From: Josh Humphries <2035234+jhump@users.noreply.github.com> Date: Wed, 7 Dec 2022 13:28:23 -0500 Subject: [PATCH 1/3] prune services and enclosing messages if they aren't directly referenced; don't include all custom options if only reason options type is in closure is implicitly via any custom option; make more DRY --- .../bufimage/bufimageutil/bufimageutil.go | 400 +++++++++--------- .../bufimageutil/bufimageutil_test.go | 6 + .../testdata/nesting/recursenested.txtar | 3 - .../testdata/nesting/usingother.txtar | 13 - .../bufimageutil/testdata/options/Files.txtar | 291 +++++++++++++ .../bufimageutil/testdata/options/a.proto | 5 + .../options/all-exclude-options.txtar | 1 + .../testdata/options/all-with-Files.txtar | 340 +++++++++++++++ .../bufimageutil/testdata/options/all.txtar | 4 + .../testdata/options/options.proto | 4 + .../testdata/options/pkg.FooService.txtar | 4 + 11 files changed, 860 insertions(+), 211 deletions(-) create mode 100644 private/bufpkg/bufimage/bufimageutil/testdata/options/Files.txtar create mode 100644 private/bufpkg/bufimage/bufimageutil/testdata/options/all-with-Files.txtar diff --git a/private/bufpkg/bufimage/bufimageutil/bufimageutil.go b/private/bufpkg/bufimage/bufimageutil/bufimageutil.go index 5d28958d27..4f46a3f679 100644 --- a/private/bufpkg/bufimage/bufimageutil/bufimageutil.go +++ b/private/bufpkg/bufimage/bufimageutil/bufimageutil.go @@ -206,10 +206,14 @@ func ImageFilteredByTypesWithOptions(image bufimage.Image, types []string, opts // Find all types to include in filtered image. closure := newTransitiveClosure() for _, startingDescriptor := range startingDescriptors { - if err := closure.addElement(startingDescriptor, "", imageIndex, options); err != nil { + if err := closure.addElement(startingDescriptor, "", false, imageIndex, options); err != nil { return nil, err } } + // After all typs are added, add their known extensions + if err := closure.addExtensions(imageIndex, options); err != nil { + return nil, err + } // Create a new image with only the required descriptors. var includedFiles []bufimage.ImageFile for _, imageFile := range image.Files() { @@ -255,29 +259,13 @@ func ImageFilteredByTypesWithOptions(image bufimage.Image, types []string, opts } imageFileDescriptor.WeakDependency = imageFileDescriptor.WeakDependency[:i] - trimMessages, err := trimMessageDescriptor(imageFileDescriptor.MessageType, closure.elements) - if err != nil { - return nil, err - } - imageFileDescriptor.MessageType = trimMessages - trimEnums, err := trimEnumDescriptor(imageFileDescriptor.EnumType, closure.elements) - if err != nil { - return nil, err - } - imageFileDescriptor.EnumType = trimEnums - trimExtensions, err := trimExtensionDescriptors(imageFileDescriptor.Extension, closure.elements) - if err != nil { - return nil, err - } - imageFileDescriptor.Extension = trimExtensions - i = 0 + imageFileDescriptor.MessageType = trimMessageDescriptors(imageFileDescriptor.MessageType, closure.elements) + imageFileDescriptor.EnumType = trimSlice(imageFileDescriptor.EnumType, closure.elements) + imageFileDescriptor.Extension = trimSlice(imageFileDescriptor.Extension, closure.elements) + imageFileDescriptor.Service = trimSlice(imageFileDescriptor.Service, closure.elements) for _, serviceDescriptor := range imageFileDescriptor.Service { - if _, ok := closure.elements[serviceDescriptor]; ok { - imageFileDescriptor.Service[i] = serviceDescriptor - i++ - } + serviceDescriptor.Method = trimSlice(serviceDescriptor.Method, closure.elements) } - imageFileDescriptor.Service = imageFileDescriptor.Service[:i] // TODO: With some from/to mappings, perhaps even sourcecodeinfo // isn't too bad. @@ -286,72 +274,73 @@ func ImageFilteredByTypesWithOptions(image bufimage.Image, types []string, opts return bufimage.NewImage(includedFiles) } -// trimMessageDescriptor removes (nested) messages and nested enums from a slice +// trimMessageDescriptors removes (nested) messages and nested enums from a slice // of message descriptors if their type names are not found in the toKeep map. -func trimMessageDescriptor(in []*descriptorpb.DescriptorProto, toKeep map[namedDescriptor]struct{}) ([]*descriptorpb.DescriptorProto, error) { - i := 0 +func trimMessageDescriptors(in []*descriptorpb.DescriptorProto, toKeep map[namedDescriptor]closureInclusionMode) []*descriptorpb.DescriptorProto { + in = trimSlice(in, toKeep) for _, messageDescriptor := range in { - if _, ok := toKeep[messageDescriptor]; ok { - trimMessages, err := trimMessageDescriptor(messageDescriptor.NestedType, toKeep) - if err != nil { - return nil, err - } - messageDescriptor.NestedType = trimMessages - trimEnums, err := trimEnumDescriptor(messageDescriptor.EnumType, toKeep) - if err != nil { - return nil, err - } - messageDescriptor.EnumType = trimEnums - trimExtensions, err := trimExtensionDescriptors(messageDescriptor.Extension, toKeep) - if err != nil { - return nil, err - } - messageDescriptor.Extension = trimExtensions - in[i] = messageDescriptor - i++ - } - } - return in[:i], nil -} - -// trimEnumDescriptor removes enums from a slice of enum descriptors if their -// type names are not found in the toKeep map. -func trimEnumDescriptor(in []*descriptorpb.EnumDescriptorProto, toKeep map[namedDescriptor]struct{}) ([]*descriptorpb.EnumDescriptorProto, error) { - i := 0 - for _, enumDescriptor := range in { - if _, ok := toKeep[enumDescriptor]; ok { - in[i] = enumDescriptor - i++ + mode, ok := toKeep[messageDescriptor] + if !ok { + continue } + if mode == inclusionModeEnclosing { + // if this is just an enclosing element, we only care about it as a namespace for + // other types and don't care about the rest of its contents + messageDescriptor.Field = nil + messageDescriptor.OneofDecl = nil + messageDescriptor.ExtensionRange = nil + messageDescriptor.ReservedRange = nil + messageDescriptor.ReservedName = nil + } + messageDescriptor.NestedType = trimMessageDescriptors(messageDescriptor.NestedType, toKeep) + messageDescriptor.EnumType = trimSlice(messageDescriptor.EnumType, toKeep) + messageDescriptor.Extension = trimSlice(messageDescriptor.Extension, toKeep) } - return in[:i], nil + return in } -// trimExtensionDescriptors removes fields from a slice of field descriptors if their -// type names are not found in the toKeep map. -func trimExtensionDescriptors(in []*descriptorpb.FieldDescriptorProto, toKeep map[namedDescriptor]struct{}) ([]*descriptorpb.FieldDescriptorProto, error) { +// trimSlice removes elements from a slice of descriptors if they are +// not present in the given map. +func trimSlice[T namedDescriptor](in []T, toKeep map[namedDescriptor]closureInclusionMode) []T { i := 0 - for _, fieldDescriptor := range in { - if _, ok := toKeep[fieldDescriptor]; ok { - in[i] = fieldDescriptor + for _, descriptor := range in { + if _, ok := toKeep[descriptor]; ok { + in[i] = descriptor i++ } } - return in[:i], nil + return in[:i] } // transitiveClosure accumulates the elements, files, and needed imports for a // subset of an image. When an element is added to the closure, all of its // dependencies are recursively added. type transitiveClosure struct { - elements map[namedDescriptor]struct{} + elements map[namedDescriptor]closureInclusionMode files map[string]struct{} imports map[string]map[string]struct{} } +type closureInclusionMode int + +const ( + // Element is included in closure because it is directly reachable from a root. + inclusionModeExplicit = closureInclusionMode(iota) + // Element is included in closure because it is a message or service that + // *contains* an explicitly included element but is not itself directly + // reachable. + inclusionModeEnclosing + // Element is included in closure because it is implied by the presence of a + // custom option. For example, a field element with a custom option implies + // the presence of google.protobuf.FieldOptions. An option type could instead be + // explicitly included if it is also directly reachable (i.e. some type in the + // graph explicitly refers to the option type). + inclusionModeImplicit +) + func newTransitiveClosure() *transitiveClosure { return &transitiveClosure{ - elements: map[namedDescriptor]struct{}{}, + elements: map[namedDescriptor]closureInclusionMode{}, files: map[string]struct{}{}, imports: map[string]map[string]struct{}{}, } @@ -380,6 +369,7 @@ func (t *transitiveClosure) addFile(file string, imageIndex *imageIndex, opts *i func (t *transitiveClosure) addElement( descriptor namedDescriptor, referrerFile string, + impliedByCustomOption bool, imageIndex *imageIndex, opts *imageFilterOptions, ) error { @@ -391,69 +381,36 @@ func (t *transitiveClosure) addElement( t.addImport(referrerFile, descriptorInfo.file) } - if _, ok := t.elements[descriptor]; ok { + if existingMode, ok := t.elements[descriptor]; ok && existingMode != inclusionModeEnclosing { + if existingMode == inclusionModeImplicit && !impliedByCustomOption { + // upgrade from implied to explicitly part of closure + t.elements[descriptor] = inclusionModeExplicit + } return nil // already added this element } - t.elements[descriptor] = struct{}{} + if impliedByCustomOption { + t.elements[descriptor] = inclusionModeImplicit + } else { + t.elements[descriptor] = inclusionModeExplicit + } + + // if this type is enclosed inside another, add enclosing types + if err := t.addEnclosing(descriptorInfo.parent, descriptorInfo.file, imageIndex, opts); err != nil { + return err + } + // add any custom options and their dependencies + if err := t.exploreCustomOptions(descriptor, descriptorInfo.file, imageIndex, opts); err != nil { + return err + } switch typedDescriptor := descriptor.(type) { case *descriptorpb.DescriptorProto: + // Options and types for all fields for _, field := range typedDescriptor.GetField() { - switch field.GetType() { - case descriptorpb.FieldDescriptorProto_TYPE_ENUM, - descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, - descriptorpb.FieldDescriptorProto_TYPE_GROUP: - typeName := strings.TrimPrefix(field.GetTypeName(), ".") - typeDescriptor, ok := imageIndex.ByName[typeName] - if !ok { - return fmt.Errorf("missing %q", typeName) - } - if err := t.addElement(typeDescriptor, descriptorInfo.file, imageIndex, opts); err != nil { - return err - } - case descriptorpb.FieldDescriptorProto_TYPE_DOUBLE, - descriptorpb.FieldDescriptorProto_TYPE_FLOAT, - descriptorpb.FieldDescriptorProto_TYPE_INT64, - descriptorpb.FieldDescriptorProto_TYPE_UINT64, - descriptorpb.FieldDescriptorProto_TYPE_INT32, - descriptorpb.FieldDescriptorProto_TYPE_FIXED64, - descriptorpb.FieldDescriptorProto_TYPE_FIXED32, - descriptorpb.FieldDescriptorProto_TYPE_BOOL, - descriptorpb.FieldDescriptorProto_TYPE_STRING, - descriptorpb.FieldDescriptorProto_TYPE_BYTES, - descriptorpb.FieldDescriptorProto_TYPE_UINT32, - descriptorpb.FieldDescriptorProto_TYPE_SFIXED32, - descriptorpb.FieldDescriptorProto_TYPE_SFIXED64, - descriptorpb.FieldDescriptorProto_TYPE_SINT32, - descriptorpb.FieldDescriptorProto_TYPE_SINT64: - // nothing to explore for the field type, but - // there might be custom field options - default: - return fmt.Errorf("unknown field type %d", field.GetType()) - } - // Field options - if err := t.exploreCustomOptions(field, descriptorInfo.file, imageIndex, opts); err != nil { + if err := t.addFieldType(field, descriptorInfo.file, imageIndex, opts); err != nil { return err } - } - // Extensions declared for this message. - // TODO: We currently exclude all extensions for descriptor options types (and instead - // only gather the ones used in relevant custom options). But if the descriptor option - // type were a named type for filtering, we SHOULD include all of them. - if opts.includeKnownExtensions && !isOptionsTypeName(descriptorInfo.fullName) { - for _, extendsDescriptor := range imageIndex.NameToExtensions[descriptorInfo.fullName] { - if err := t.addElement(extendsDescriptor, "", imageIndex, opts); err != nil { - return err - } - } - } - // Messages in which this message is nested - if _, ok := descriptorInfo.parent.(*descriptorpb.DescriptorProto); ok { - // TODO: we don't actually want or need the entire parent message unless it is actually - // referenced by other parts of the schema. As a reference from a nested message, we - // only care about it as a namespace (so all of its other elements, aside from needed - // nested types, could be omitted). - if err := t.addElement(descriptorInfo.parent, "", imageIndex, opts); err != nil { + if err := t.exploreCustomOptions(field, referrerFile, imageIndex, opts); err != nil { return err } } @@ -469,52 +426,28 @@ func (t *transitiveClosure) addElement( return err } } - // Message options - if err := t.exploreCustomOptions(typedDescriptor, descriptorInfo.file, imageIndex, opts); err != nil { - return err - } + case *descriptorpb.EnumDescriptorProto: - // Parent messages - if _, ok := descriptorInfo.parent.(*descriptorpb.DescriptorProto); ok { - // TODO: ditto above: unless the parent message is used elsewhere, we don't need the - // entire message; we only need it as a placeholder for namespacing. - if err := t.addElement(descriptorInfo.parent, "", imageIndex, opts); err != nil { - return err - } - } for _, enumValue := range typedDescriptor.GetValue() { if err := t.exploreCustomOptions(enumValue, descriptorInfo.file, imageIndex, opts); err != nil { return err } } - // Enum options - if err := t.exploreCustomOptions(typedDescriptor, descriptorInfo.file, imageIndex, opts); err != nil { - return err - } + case *descriptorpb.ServiceDescriptorProto: for _, method := range typedDescriptor.GetMethod() { - if err := t.addElement(method, "", imageIndex, opts); err != nil { + if err := t.addElement(method, "", false, imageIndex, opts); err != nil { return err } } - // Service options - if err := t.exploreCustomOptions(typedDescriptor, descriptorInfo.file, imageIndex, opts); err != nil { - return err - } - case *descriptorpb.MethodDescriptorProto: - // in case method was directly named as a filter type, make sure we include parent service - // TODO: if the service is not also named as a filter type, we could prune the service down - // to only the named methods and shrink the size of the filtered image further. - if err := t.addElement(descriptorInfo.parent, "", imageIndex, opts); err != nil { - return err - } + case *descriptorpb.MethodDescriptorProto: inputName := strings.TrimPrefix(typedDescriptor.GetInputType(), ".") inputDescriptor, ok := imageIndex.ByName[inputName] if !ok { return fmt.Errorf("missing %q", inputName) } - if err := t.addElement(inputDescriptor, descriptorInfo.file, imageIndex, opts); err != nil { + if err := t.addElement(inputDescriptor, descriptorInfo.file, false, imageIndex, opts); err != nil { return err } @@ -523,19 +456,16 @@ func (t *transitiveClosure) addElement( if !ok { return fmt.Errorf("missing %q", outputName) } - if err := t.addElement(outputDescriptor, descriptorInfo.file, imageIndex, opts); err != nil { - return err - } - - // Method options - if err := t.exploreCustomOptions(typedDescriptor, descriptorInfo.file, imageIndex, opts); err != nil { + if err := t.addElement(outputDescriptor, descriptorInfo.file, false, imageIndex, opts); err != nil { return err } case *descriptorpb.FieldDescriptorProto: - // Regular fields get handled by protosource.Message, only - // protosource.Fields's for extends definitions should reach - // here. + // Regular fields are handled above in message descriptor case. + // We should only find our way here for extensions. + if typedDescriptor.Extendee == nil { + return errorUnsupportedFilterType(descriptor, descriptorInfo.fullName) + } if typedDescriptor.GetExtendee() == "" { return fmt.Errorf("expected extendee for field %q to not be empty", descriptorInfo.fullName) } @@ -544,49 +474,129 @@ func (t *transitiveClosure) addElement( if !ok { return fmt.Errorf("missing %q", extendeeName) } - if err := t.addElement(extendeeDescriptor, descriptorInfo.file, imageIndex, opts); err != nil { + if err := t.addElement(extendeeDescriptor, descriptorInfo.file, impliedByCustomOption, imageIndex, opts); err != nil { + return err + } + if err := t.addFieldType(typedDescriptor, descriptorInfo.file, imageIndex, opts); err != nil { return err } - switch typedDescriptor.GetType() { - case descriptorpb.FieldDescriptorProto_TYPE_ENUM, - descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, - descriptorpb.FieldDescriptorProto_TYPE_GROUP: - typeName := strings.TrimPrefix(typedDescriptor.GetTypeName(), ".") - typeDescriptor, ok := imageIndex.ByName[typeName] - if !ok { - return fmt.Errorf("missing %q", typeName) - } - err := t.addElement(typeDescriptor, descriptorInfo.file, imageIndex, opts) - if err != nil { - return err - } - case descriptorpb.FieldDescriptorProto_TYPE_DOUBLE, - descriptorpb.FieldDescriptorProto_TYPE_FLOAT, - descriptorpb.FieldDescriptorProto_TYPE_INT64, - descriptorpb.FieldDescriptorProto_TYPE_UINT64, - descriptorpb.FieldDescriptorProto_TYPE_INT32, - descriptorpb.FieldDescriptorProto_TYPE_FIXED64, - descriptorpb.FieldDescriptorProto_TYPE_FIXED32, - descriptorpb.FieldDescriptorProto_TYPE_BOOL, - descriptorpb.FieldDescriptorProto_TYPE_STRING, - descriptorpb.FieldDescriptorProto_TYPE_BYTES, - descriptorpb.FieldDescriptorProto_TYPE_UINT32, - descriptorpb.FieldDescriptorProto_TYPE_SFIXED32, - descriptorpb.FieldDescriptorProto_TYPE_SFIXED64, - descriptorpb.FieldDescriptorProto_TYPE_SINT32, - descriptorpb.FieldDescriptorProto_TYPE_SINT64: - // nothing to follow, custom options handled below. - default: - return fmt.Errorf("unknown field type %d", typedDescriptor.GetType()) - } - if err := t.exploreCustomOptions(typedDescriptor, descriptorInfo.file, imageIndex, opts); err != nil { + default: + return errorUnsupportedFilterType(descriptor, descriptorInfo.fullName) + } + + return nil +} + +func errorUnsupportedFilterType(descriptor namedDescriptor, fullName string) error { + var descriptorType string + switch d := descriptor.(type) { + case *descriptorpb.FileDescriptorProto: + descriptorType = "file" + case *descriptorpb.DescriptorProto: + descriptorType = "message" + case *descriptorpb.FieldDescriptorProto: + if d.Extendee != nil { + descriptorType = "extension field" + } else { + descriptorType = "non-extension field" + } + case *descriptorpb.OneofDescriptorProto: + descriptorType = "oneof" + case *descriptorpb.EnumDescriptorProto: + descriptorType = "enum" + case *descriptorpb.EnumValueDescriptorProto: + descriptorType = "enum value" + case *descriptorpb.ServiceDescriptorProto: + descriptorType = "service" + case *descriptorpb.MethodDescriptorProto: + descriptorType = "method" + default: + descriptorType = fmt.Sprintf("%T", d) + } + return fmt.Errorf("%s is unsupported filter type: %s", fullName, descriptorType) +} + +func (t *transitiveClosure) addEnclosing(descriptor namedDescriptor, enclosingFile string, imageIndex *imageIndex, opts *imageFilterOptions) error { + for descriptor != nil { + _, isMsg := descriptor.(*descriptorpb.DescriptorProto) + _, isSvc := descriptor.(*descriptorpb.ServiceDescriptorProto) + if !isMsg && !isSvc { + break // not an enclosing type + } + if _, ok := t.elements[descriptor]; ok { + break // already in closure + } + t.elements[descriptor] = inclusionModeEnclosing + if err := t.exploreCustomOptions(descriptor, enclosingFile, imageIndex, opts); err != nil { + return err + } + // now move into this element's parent + descriptor = imageIndex.ByDescriptor[descriptor].parent + } + return nil +} + +func (t *transitiveClosure) addFieldType(field *descriptorpb.FieldDescriptorProto, referrerFile string, imageIndex *imageIndex, opts *imageFilterOptions) error { + switch field.GetType() { + case descriptorpb.FieldDescriptorProto_TYPE_ENUM, + descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, + descriptorpb.FieldDescriptorProto_TYPE_GROUP: + typeName := strings.TrimPrefix(field.GetTypeName(), ".") + typeDescriptor, ok := imageIndex.ByName[typeName] + if !ok { + return fmt.Errorf("missing %q", typeName) + } + err := t.addElement(typeDescriptor, referrerFile, false, imageIndex, opts) + if err != nil { return err } + case descriptorpb.FieldDescriptorProto_TYPE_DOUBLE, + descriptorpb.FieldDescriptorProto_TYPE_FLOAT, + descriptorpb.FieldDescriptorProto_TYPE_INT64, + descriptorpb.FieldDescriptorProto_TYPE_UINT64, + descriptorpb.FieldDescriptorProto_TYPE_INT32, + descriptorpb.FieldDescriptorProto_TYPE_FIXED64, + descriptorpb.FieldDescriptorProto_TYPE_FIXED32, + descriptorpb.FieldDescriptorProto_TYPE_BOOL, + descriptorpb.FieldDescriptorProto_TYPE_STRING, + descriptorpb.FieldDescriptorProto_TYPE_BYTES, + descriptorpb.FieldDescriptorProto_TYPE_UINT32, + descriptorpb.FieldDescriptorProto_TYPE_SFIXED32, + descriptorpb.FieldDescriptorProto_TYPE_SFIXED64, + descriptorpb.FieldDescriptorProto_TYPE_SINT32, + descriptorpb.FieldDescriptorProto_TYPE_SINT64: + // nothing to follow, custom options handled below. default: - return fmt.Errorf("unexpected protosource type %T", typedDescriptor) + return fmt.Errorf("unknown field type %d", field.GetType()) } + return nil +} +func (t *transitiveClosure) addExtensions( + imageIndex *imageIndex, + opts *imageFilterOptions, +) error { + if !opts.includeKnownExtensions { + return nil // nothing to do + } + for e, mode := range t.elements { + if mode != inclusionModeExplicit { + // we only collect extensions for messages that are directly reachable/referenced. + continue + } + msgDescriptor, ok := e.(*descriptorpb.DescriptorProto) + if !ok { + // not a message, nothing to do + continue + } + descriptorInfo := imageIndex.ByDescriptor[msgDescriptor] + for _, extendsDescriptor := range imageIndex.NameToExtensions[descriptorInfo.fullName] { + if err := t.addElement(extendsDescriptor, "", false, imageIndex, opts); err != nil { + return err + } + } + } return nil } @@ -636,7 +646,7 @@ func (t *transitiveClosure) exploreCustomOptions( err = fmt.Errorf("cannot find ext no %d on %s", fd.Number(), optionsName) return false } - err = t.addElement(field, referrerFile, imageIndex, opts) + err = t.addElement(field, referrerFile, true, imageIndex, opts) return err == nil }) return err diff --git a/private/bufpkg/bufimage/bufimageutil/bufimageutil_test.go b/private/bufpkg/bufimage/bufimageutil/bufimageutil_test.go index 4f0a071791..2d5f7cac38 100644 --- a/private/bufpkg/bufimage/bufimageutil/bufimageutil_test.go +++ b/private/bufpkg/bufimage/bufimageutil/bufimageutil_test.go @@ -62,6 +62,12 @@ func TestOptions(t *testing.T) { t.Run("exclude-options", func(t *testing.T) { runDiffTest(t, "testdata/options", []string{"pkg.Foo", "pkg.FooEnum", "pkg.FooService"}, "all-exclude-options.txtar", WithExcludeCustomOptions()) }) + t.Run("files", func(t *testing.T) { + runDiffTest(t, "testdata/options", []string{"Files"}, "Files.txtar") + }) + t.Run("all-with-files", func(t *testing.T) { + runDiffTest(t, "testdata/options", []string{"pkg.Foo", "pkg.FooEnum", "pkg.FooService", "Files"}, "all-with-Files.txtar") + }) } func TestNesting(t *testing.T) { diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/nesting/recursenested.txtar b/private/bufpkg/bufimage/bufimageutil/testdata/nesting/recursenested.txtar index 50f1fb5bcb..4fe6961c8b 100644 --- a/private/bufpkg/bufimage/bufimageutil/testdata/nesting/recursenested.txtar +++ b/private/bufpkg/bufimage/bufimageutil/testdata/nesting/recursenested.txtar @@ -2,10 +2,7 @@ syntax = "proto3"; package pkg; message Foo { - string x = 1; - NestedFoo nested_foo = 2; message NestedFoo { - string nested_x = 1; message NestedNestedFoo { string nested_nested_x = 1; } diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/nesting/usingother.txtar b/private/bufpkg/bufimage/bufimageutil/testdata/nesting/usingother.txtar index 6f6fe75964..83eada7dac 100644 --- a/private/bufpkg/bufimage/bufimageutil/testdata/nesting/usingother.txtar +++ b/private/bufpkg/bufimage/bufimageutil/testdata/nesting/usingother.txtar @@ -2,8 +2,6 @@ syntax = "proto3"; package pkg; message Bar { - FooEnum foo_enum = 1; - Foo.NestedFoo nested_foo = 2; enum NestedBarEnum { NESTED_BAR_ENUM_X = 0; NESTED_BAR_ENUM_Y = 1; @@ -12,14 +10,3 @@ message Bar { message Baz { Bar.NestedBarEnum nested_bar_enum = 1; } -message Foo { - string x = 1; - NestedFoo nested_foo = 2; - message NestedFoo { - string nested_x = 1; - } -} -enum FooEnum { - FOO_ENUM_X = 0; - FOO_ENUM_Y = 1; -} diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/options/Files.txtar b/private/bufpkg/bufimage/bufimageutil/testdata/options/Files.txtar new file mode 100644 index 0000000000..ef2a3614a3 --- /dev/null +++ b/private/bufpkg/bufimage/bufimageutil/testdata/options/Files.txtar @@ -0,0 +1,291 @@ +-- google/protobuf/descriptor.proto -- +syntax = "proto2"; +package google.protobuf; +option cc_enable_arenas = true; +option csharp_namespace = "Google.Protobuf.Reflection"; +option go_package = "google.golang.org/protobuf/types/descriptorpb"; +option java_outer_classname = "DescriptorProtos"; +option java_package = "com.google.protobuf"; +option objc_class_prefix = "GPB"; +option optimize_for = SPEED; +message DescriptorProto { + optional string name = 1; + repeated FieldDescriptorProto field = 2; + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + repeated ExtensionRange extension_range = 5; + repeated FieldDescriptorProto extension = 6; + optional MessageOptions options = 7; + repeated OneofDescriptorProto oneof_decl = 8; + repeated ReservedRange reserved_range = 9; + repeated string reserved_name = 10; + message ExtensionRange { + optional int32 start = 1; + optional int32 end = 2; + optional ExtensionRangeOptions options = 3; + } + message ReservedRange { + optional int32 start = 1; + optional int32 end = 2; + } +} +message EnumDescriptorProto { + optional string name = 1; + repeated EnumValueDescriptorProto value = 2; + optional EnumOptions options = 3; + repeated EnumReservedRange reserved_range = 4; + repeated string reserved_name = 5; + message EnumReservedRange { + optional int32 start = 1; + optional int32 end = 2; + } +} +message EnumOptions { + optional bool allow_alias = 2; + optional bool deprecated = 3 [default = false]; + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; + reserved 5; +} +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + optional EnumValueOptions options = 3; +} +message EnumValueOptions { + optional bool deprecated = 1 [default = false]; + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; +} +message ExtensionRangeOptions { + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; +} +message FieldDescriptorProto { + optional string name = 1; + optional string extendee = 2; + optional int32 number = 3; + optional Label label = 4; + optional Type type = 5; + optional string type_name = 6; + optional string default_value = 7; + optional FieldOptions options = 8; + optional int32 oneof_index = 9; + optional string json_name = 10; + optional bool proto3_optional = 17; + enum Label { + LABEL_OPTIONAL = 1; + LABEL_REQUIRED = 2; + LABEL_REPEATED = 3; + } + enum Type { + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + TYPE_INT64 = 3; + TYPE_UINT64 = 4; + TYPE_INT32 = 5; + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + TYPE_GROUP = 10; + TYPE_MESSAGE = 11; + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; + TYPE_SINT64 = 18; + } +} +message FieldOptions { + optional CType ctype = 1 [default = STRING]; + optional bool packed = 2; + optional bool deprecated = 3 [default = false]; + optional bool lazy = 5 [default = false]; + optional JSType jstype = 6 [default = JS_NORMAL]; + optional bool weak = 10 [default = false]; + optional bool unverified_lazy = 15 [default = false]; + repeated UninterpretedOption uninterpreted_option = 999; + enum CType { + STRING = 0; + CORD = 1; + STRING_PIECE = 2; + } + enum JSType { + JS_NORMAL = 0; + JS_STRING = 1; + JS_NUMBER = 2; + } + extensions 1000 to max; + reserved 4; +} +message FileDescriptorProto { + optional string name = 1; + optional string package = 2; + repeated string dependency = 3; + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + optional FileOptions options = 8; + optional SourceCodeInfo source_code_info = 9; + repeated int32 public_dependency = 10; + repeated int32 weak_dependency = 11; + optional string syntax = 12; +} +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} +message FileOptions { + optional string java_package = 1; + optional string java_outer_classname = 8; + optional OptimizeMode optimize_for = 9 [default = SPEED]; + optional bool java_multiple_files = 10 [default = false]; + optional string go_package = 11; + optional bool cc_generic_services = 16 [default = false]; + optional bool java_generic_services = 17 [default = false]; + optional bool py_generic_services = 18 [default = false]; + optional bool java_generate_equals_and_hash = 20 [deprecated = true]; + optional bool deprecated = 23 [default = false]; + optional bool java_string_check_utf8 = 27 [default = false]; + optional bool cc_enable_arenas = 31 [default = true]; + optional string objc_class_prefix = 36; + optional string csharp_namespace = 37; + optional string swift_prefix = 39; + optional string php_class_prefix = 40; + optional string php_namespace = 41; + optional bool php_generic_services = 42 [default = false]; + optional string php_metadata_namespace = 44; + optional string ruby_package = 45; + repeated UninterpretedOption uninterpreted_option = 999; + enum OptimizeMode { + SPEED = 1; + CODE_SIZE = 2; + LITE_RUNTIME = 3; + } + extensions 1000 to max; + reserved 38; +} +message MessageOptions { + optional bool message_set_wire_format = 1 [default = false]; + optional bool no_standard_descriptor_accessor = 2 [default = false]; + optional bool deprecated = 3 [default = false]; + optional bool map_entry = 7; + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; + reserved 4, 5, 6, 8, 9; +} +message MethodDescriptorProto { + optional string name = 1; + optional string input_type = 2; + optional string output_type = 3; + optional MethodOptions options = 4; + optional bool client_streaming = 5 [default = false]; + optional bool server_streaming = 6 [default = false]; +} +message MethodOptions { + optional bool deprecated = 33 [default = false]; + optional IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN]; + repeated UninterpretedOption uninterpreted_option = 999; + enum IdempotencyLevel { + IDEMPOTENCY_UNKNOWN = 0; + NO_SIDE_EFFECTS = 1; + IDEMPOTENT = 2; + } + extensions 1000 to max; +} +message OneofDescriptorProto { + optional string name = 1; + optional OneofOptions options = 2; +} +message OneofOptions { + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; +} +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + optional ServiceOptions options = 3; +} +message ServiceOptions { + optional bool deprecated = 33 [default = false]; + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; +} +message SourceCodeInfo { + repeated Location location = 1; + message Location { + repeated int32 path = 1 [packed = true]; + repeated int32 span = 2 [packed = true]; + optional string leading_comments = 3; + optional string trailing_comments = 4; + repeated string leading_detached_comments = 6; + } +} +message UninterpretedOption { + repeated NamePart name = 2; + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } +} +-- options.proto -- +syntax = "proto3"; +import "google/protobuf/descriptor.proto"; +message Files { + google.protobuf.FileDescriptorSet files = 1; +} +message UnusedOption { + string foo = 1; +} +message UsedOption { + string foo = 1; + extend google.protobuf.FileOptions { + optional UsedOption file_foo = 50000; + optional UnusedOption file_bar = 50001; + optional string file_baz = 50002; + } +} +extend google.protobuf.EnumOptions { + optional UsedOption enum_foo = 50000; + optional UnusedOption enum_bar = 50001; + optional string enum_baz = 50002; +} +extend google.protobuf.EnumValueOptions { + optional UsedOption enum_value_foo = 50000; + optional UnusedOption enum_value_bar = 50001; + optional string enum_value_baz = 50002; +} +extend google.protobuf.FieldOptions { + optional UsedOption field_foo = 50000; + optional UnusedOption field_bar = 50001; + optional string field_baz = 50002; +} +extend google.protobuf.MessageOptions { + optional UsedOption message_foo = 50000; + optional UnusedOption message_bar = 50001; + optional string message_baz = 50002; +} +extend google.protobuf.MethodOptions { + optional UsedOption method_foo = 50000; + optional UnusedOption method_bar = 50001; + optional string method_baz = 50002; +} +extend google.protobuf.OneofOptions { + optional UsedOption oneof_foo = 50000; + optional UnusedOption oneof_bar = 50001; + optional string oneof_baz = 50002; +} +extend google.protobuf.ServiceOptions { + optional UsedOption service_foo = 50000; + optional UnusedOption service_bar = 50001; + optional string service_baz = 50002; +} diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/options/a.proto b/private/bufpkg/bufimage/bufimageutil/testdata/options/a.proto index 596948b47c..d731f15faa 100644 --- a/private/bufpkg/bufimage/bufimageutil/testdata/options/a.proto +++ b/private/bufpkg/bufimage/bufimageutil/testdata/options/a.proto @@ -48,6 +48,11 @@ service FooService { option (method_foo).foo = "str"; option (method_baz) = "str"; }; + + rpc DoNot(Empty) returns (Empty) { + option (method_foo).foo = "str"; + option (method_baz) = "str"; + }; } extend Foo { diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/options/all-exclude-options.txtar b/private/bufpkg/bufimage/bufimageutil/testdata/options/all-exclude-options.txtar index c90d82e9a1..052623406f 100644 --- a/private/bufpkg/bufimage/bufimageutil/testdata/options/all-exclude-options.txtar +++ b/private/bufpkg/bufimage/bufimageutil/testdata/options/all-exclude-options.txtar @@ -18,6 +18,7 @@ enum FooEnum { } service FooService { rpc Do ( Empty ) returns ( Empty ); + rpc DoNot ( Empty ) returns ( Empty ); } extend Foo { optional string extension = 11; diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/options/all-with-Files.txtar b/private/bufpkg/bufimage/bufimageutil/testdata/options/all-with-Files.txtar new file mode 100644 index 0000000000..9335278450 --- /dev/null +++ b/private/bufpkg/bufimage/bufimageutil/testdata/options/all-with-Files.txtar @@ -0,0 +1,340 @@ +-- a.proto -- +syntax = "proto2"; +package pkg; +import "options.proto"; +option (UsedOption.file_baz) = "str"; +option (UsedOption.file_foo) = { foo:"str" }; +message Empty { +} +message Foo { + option (message_baz) = "str"; + option (message_foo) = { foo:"str" }; + optional string foo = 1 [ + jstype = JS_STRING, + (field_baz) = "str", + (field_foo) = { foo:"str" } + ]; + oneof testOneof { + option (oneof_baz) = "str"; + option (oneof_foo) = { foo:"str" }; + string bar = 2; + bytes baz = 3; + } + extensions 10 to max; +} +enum FooEnum { + option deprecated = true; + option (enum_baz) = "str"; + option (enum_foo) = { foo:"str" }; + FOO_ENUM_X = 0; + FOO_ENUM_Y = 1 [ + (enum_value_baz) = "str", + (enum_value_foo) = { foo:"str" } + ]; +} +service FooService { + option (service_baz) = "str"; + option (service_foo) = { foo:"str" }; + rpc Do ( Empty ) returns ( Empty ) { + option (method_baz) = "str"; + option (method_foo) = { foo:"str" }; + } + rpc DoNot ( Empty ) returns ( Empty ) { + option (method_baz) = "str"; + option (method_foo) = { foo:"str" }; + } +} +extend Foo { + optional string extension = 11 [(field_baz) = "str", (field_foo) = { foo:"str" }]; +} +-- google/protobuf/descriptor.proto -- +syntax = "proto2"; +package google.protobuf; +option cc_enable_arenas = true; +option csharp_namespace = "Google.Protobuf.Reflection"; +option go_package = "google.golang.org/protobuf/types/descriptorpb"; +option java_outer_classname = "DescriptorProtos"; +option java_package = "com.google.protobuf"; +option objc_class_prefix = "GPB"; +option optimize_for = SPEED; +message DescriptorProto { + optional string name = 1; + repeated FieldDescriptorProto field = 2; + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + repeated ExtensionRange extension_range = 5; + repeated FieldDescriptorProto extension = 6; + optional MessageOptions options = 7; + repeated OneofDescriptorProto oneof_decl = 8; + repeated ReservedRange reserved_range = 9; + repeated string reserved_name = 10; + message ExtensionRange { + optional int32 start = 1; + optional int32 end = 2; + optional ExtensionRangeOptions options = 3; + } + message ReservedRange { + optional int32 start = 1; + optional int32 end = 2; + } +} +message EnumDescriptorProto { + optional string name = 1; + repeated EnumValueDescriptorProto value = 2; + optional EnumOptions options = 3; + repeated EnumReservedRange reserved_range = 4; + repeated string reserved_name = 5; + message EnumReservedRange { + optional int32 start = 1; + optional int32 end = 2; + } +} +message EnumOptions { + optional bool allow_alias = 2; + optional bool deprecated = 3 [default = false]; + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; + reserved 5; +} +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + optional EnumValueOptions options = 3; +} +message EnumValueOptions { + optional bool deprecated = 1 [default = false]; + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; +} +message ExtensionRangeOptions { + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; +} +message FieldDescriptorProto { + optional string name = 1; + optional string extendee = 2; + optional int32 number = 3; + optional Label label = 4; + optional Type type = 5; + optional string type_name = 6; + optional string default_value = 7; + optional FieldOptions options = 8; + optional int32 oneof_index = 9; + optional string json_name = 10; + optional bool proto3_optional = 17; + enum Label { + LABEL_OPTIONAL = 1; + LABEL_REQUIRED = 2; + LABEL_REPEATED = 3; + } + enum Type { + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + TYPE_INT64 = 3; + TYPE_UINT64 = 4; + TYPE_INT32 = 5; + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + TYPE_GROUP = 10; + TYPE_MESSAGE = 11; + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; + TYPE_SINT64 = 18; + } +} +message FieldOptions { + optional CType ctype = 1 [default = STRING]; + optional bool packed = 2; + optional bool deprecated = 3 [default = false]; + optional bool lazy = 5 [default = false]; + optional JSType jstype = 6 [default = JS_NORMAL]; + optional bool weak = 10 [default = false]; + optional bool unverified_lazy = 15 [default = false]; + repeated UninterpretedOption uninterpreted_option = 999; + enum CType { + STRING = 0; + CORD = 1; + STRING_PIECE = 2; + } + enum JSType { + JS_NORMAL = 0; + JS_STRING = 1; + JS_NUMBER = 2; + } + extensions 1000 to max; + reserved 4; +} +message FileDescriptorProto { + optional string name = 1; + optional string package = 2; + repeated string dependency = 3; + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + optional FileOptions options = 8; + optional SourceCodeInfo source_code_info = 9; + repeated int32 public_dependency = 10; + repeated int32 weak_dependency = 11; + optional string syntax = 12; +} +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} +message FileOptions { + optional string java_package = 1; + optional string java_outer_classname = 8; + optional OptimizeMode optimize_for = 9 [default = SPEED]; + optional bool java_multiple_files = 10 [default = false]; + optional string go_package = 11; + optional bool cc_generic_services = 16 [default = false]; + optional bool java_generic_services = 17 [default = false]; + optional bool py_generic_services = 18 [default = false]; + optional bool java_generate_equals_and_hash = 20 [deprecated = true]; + optional bool deprecated = 23 [default = false]; + optional bool java_string_check_utf8 = 27 [default = false]; + optional bool cc_enable_arenas = 31 [default = true]; + optional string objc_class_prefix = 36; + optional string csharp_namespace = 37; + optional string swift_prefix = 39; + optional string php_class_prefix = 40; + optional string php_namespace = 41; + optional bool php_generic_services = 42 [default = false]; + optional string php_metadata_namespace = 44; + optional string ruby_package = 45; + repeated UninterpretedOption uninterpreted_option = 999; + enum OptimizeMode { + SPEED = 1; + CODE_SIZE = 2; + LITE_RUNTIME = 3; + } + extensions 1000 to max; + reserved 38; +} +message MessageOptions { + optional bool message_set_wire_format = 1 [default = false]; + optional bool no_standard_descriptor_accessor = 2 [default = false]; + optional bool deprecated = 3 [default = false]; + optional bool map_entry = 7; + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; + reserved 4, 5, 6, 8, 9; +} +message MethodDescriptorProto { + optional string name = 1; + optional string input_type = 2; + optional string output_type = 3; + optional MethodOptions options = 4; + optional bool client_streaming = 5 [default = false]; + optional bool server_streaming = 6 [default = false]; +} +message MethodOptions { + optional bool deprecated = 33 [default = false]; + optional IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN]; + repeated UninterpretedOption uninterpreted_option = 999; + enum IdempotencyLevel { + IDEMPOTENCY_UNKNOWN = 0; + NO_SIDE_EFFECTS = 1; + IDEMPOTENT = 2; + } + extensions 1000 to max; +} +message OneofDescriptorProto { + optional string name = 1; + optional OneofOptions options = 2; +} +message OneofOptions { + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; +} +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + optional ServiceOptions options = 3; +} +message ServiceOptions { + optional bool deprecated = 33 [default = false]; + repeated UninterpretedOption uninterpreted_option = 999; + extensions 1000 to max; +} +message SourceCodeInfo { + repeated Location location = 1; + message Location { + repeated int32 path = 1 [packed = true]; + repeated int32 span = 2 [packed = true]; + optional string leading_comments = 3; + optional string trailing_comments = 4; + repeated string leading_detached_comments = 6; + } +} +message UninterpretedOption { + repeated NamePart name = 2; + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } +} +-- options.proto -- +syntax = "proto3"; +import "google/protobuf/descriptor.proto"; +message Files { + google.protobuf.FileDescriptorSet files = 1; +} +message UnusedOption { + string foo = 1; +} +message UsedOption { + string foo = 1; + extend google.protobuf.FileOptions { + optional UsedOption file_foo = 50000; + optional UnusedOption file_bar = 50001; + optional string file_baz = 50002; + } +} +extend google.protobuf.EnumOptions { + optional UsedOption enum_foo = 50000; + optional UnusedOption enum_bar = 50001; + optional string enum_baz = 50002; +} +extend google.protobuf.EnumValueOptions { + optional UsedOption enum_value_foo = 50000; + optional UnusedOption enum_value_bar = 50001; + optional string enum_value_baz = 50002; +} +extend google.protobuf.FieldOptions { + optional UsedOption field_foo = 50000; + optional UnusedOption field_bar = 50001; + optional string field_baz = 50002; +} +extend google.protobuf.MessageOptions { + optional UsedOption message_foo = 50000; + optional UnusedOption message_bar = 50001; + optional string message_baz = 50002; +} +extend google.protobuf.MethodOptions { + optional UsedOption method_foo = 50000; + optional UnusedOption method_bar = 50001; + optional string method_baz = 50002; +} +extend google.protobuf.OneofOptions { + optional UsedOption oneof_foo = 50000; + optional UnusedOption oneof_bar = 50001; + optional string oneof_baz = 50002; +} +extend google.protobuf.ServiceOptions { + optional UsedOption service_foo = 50000; + optional UnusedOption service_bar = 50001; + optional string service_baz = 50002; +} diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/options/all.txtar b/private/bufpkg/bufimage/bufimageutil/testdata/options/all.txtar index 4f99d691a3..34f74d17a6 100644 --- a/private/bufpkg/bufimage/bufimageutil/testdata/options/all.txtar +++ b/private/bufpkg/bufimage/bufimageutil/testdata/options/all.txtar @@ -39,6 +39,10 @@ service FooService { option (method_baz) = "str"; option (method_foo) = { foo:"str" }; } + rpc DoNot ( Empty ) returns ( Empty ) { + option (method_baz) = "str"; + option (method_foo) = { foo:"str" }; + } } extend Foo { optional string extension = 11 [(field_baz) = "str", (field_foo) = { foo:"str" }]; diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/options/options.proto b/private/bufpkg/bufimage/bufimageutil/testdata/options/options.proto index 25d96f8852..3230a54adc 100644 --- a/private/bufpkg/bufimage/bufimageutil/testdata/options/options.proto +++ b/private/bufpkg/bufimage/bufimageutil/testdata/options/options.proto @@ -50,3 +50,7 @@ extend google.protobuf.MethodOptions { optional UnusedOption method_bar = 50001; optional string method_baz = 50002; } + +message Files { + google.protobuf.FileDescriptorSet files = 1; +} \ No newline at end of file diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/options/pkg.FooService.txtar b/private/bufpkg/bufimage/bufimageutil/testdata/options/pkg.FooService.txtar index 4f6c8675af..616441e671 100644 --- a/private/bufpkg/bufimage/bufimageutil/testdata/options/pkg.FooService.txtar +++ b/private/bufpkg/bufimage/bufimageutil/testdata/options/pkg.FooService.txtar @@ -13,6 +13,10 @@ service FooService { option (method_baz) = "str"; option (method_foo) = { foo:"str" }; } + rpc DoNot ( Empty ) returns ( Empty ) { + option (method_baz) = "str"; + option (method_foo) = { foo:"str" }; + } } -- google/protobuf/descriptor.proto -- syntax = "proto2"; From c0717c186424db2503c8108ccac160f7ae0d14d6 Mon Sep 17 00:00:00 2001 From: Josh Humphries <2035234+jhump@users.noreply.github.com> Date: Thu, 8 Dec 2022 08:35:29 -0500 Subject: [PATCH 2/3] add missing trailing newline --- .../bufpkg/bufimage/bufimageutil/testdata/options/options.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/private/bufpkg/bufimage/bufimageutil/testdata/options/options.proto b/private/bufpkg/bufimage/bufimageutil/testdata/options/options.proto index 3230a54adc..57676254cb 100644 --- a/private/bufpkg/bufimage/bufimageutil/testdata/options/options.proto +++ b/private/bufpkg/bufimage/bufimageutil/testdata/options/options.proto @@ -53,4 +53,4 @@ extend google.protobuf.MethodOptions { message Files { google.protobuf.FileDescriptorSet files = 1; -} \ No newline at end of file +} From c30208450d618e33645b3da09ded55e959505004 Mon Sep 17 00:00:00 2001 From: Joshua Humphries <2035234+jhump@users.noreply.github.com> Date: Tue, 13 Dec 2022 15:32:26 -0500 Subject: [PATCH 3/3] clarify loop with a comment --- private/bufpkg/bufimage/bufimageutil/bufimageutil.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/private/bufpkg/bufimage/bufimageutil/bufimageutil.go b/private/bufpkg/bufimage/bufimageutil/bufimageutil.go index 4f46a3f679..b4901ae5cb 100644 --- a/private/bufpkg/bufimage/bufimageutil/bufimageutil.go +++ b/private/bufpkg/bufimage/bufimageutil/bufimageutil.go @@ -518,6 +518,8 @@ func errorUnsupportedFilterType(descriptor namedDescriptor, fullName string) err } func (t *transitiveClosure) addEnclosing(descriptor namedDescriptor, enclosingFile string, imageIndex *imageIndex, opts *imageFilterOptions) error { + // loop through all enclosing parents since nesting level + // could be arbitrarily deep for descriptor != nil { _, isMsg := descriptor.(*descriptorpb.DescriptorProto) _, isSvc := descriptor.(*descriptorpb.ServiceDescriptorProto)