diff --git a/private/pkg/protosource/option_extension_descriptor.go b/private/pkg/protosource/option_extension_descriptor.go index 1b5ab51911..d16d8c3fac 100644 --- a/private/pkg/protosource/option_extension_descriptor.go +++ b/private/pkg/protosource/option_extension_descriptor.go @@ -126,3 +126,10 @@ func isDescendantPath(descendant, ancestor []int32) bool { } return true } + +func (o *optionExtensionDescriptor) ForEachPresentOption(fn func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + // Note: This does not bother to handle unrecognized fields. + // Should not be a problem since descriptors models in the buf CLI codebase should have them + // all correctly parsed and known. + o.message.ProtoReflect().Range(fn) +} diff --git a/private/pkg/protosource/protosource.go b/private/pkg/protosource/protosource.go index 2736b6b13e..e58c3ced10 100644 --- a/private/pkg/protosource/protosource.go +++ b/private/pkg/protosource/protosource.go @@ -148,9 +148,16 @@ type OptionExtensionDescriptor interface { // If no relevant location is found in source code info, this returns nil. OptionExtensionLocation(extensionType protoreflect.ExtensionType, extraPath ...int32) Location - // PresentExtensionNumbers returns field numbers for all options that - // have a set value on this descriptor. + // PresentExtensionNumbers returns field numbers for all extensions/custom options + // that have a set value on this descriptor. PresentExtensionNumbers() []int32 + + // ForEachPresentOption iterates through all options that have a set value on this + // descriptor, invoking fn for each present option. + // + // If fn returns false, the iteration is terminated and ForEachPresentOption + // immediately returns. + ForEachPresentOption(fn func(protoreflect.FieldDescriptor, protoreflect.Value) bool) } // Location defines source code info location information.