From 901e73ef08921b0b6277f784846f92c62a2d11c9 Mon Sep 17 00:00:00 2001 From: Josh Humphries Date: Wed, 28 Sep 2022 15:14:05 -0400 Subject: [PATCH 1/3] support for v2 messages w/ unrecognized extensions in *dynamic.Message --- dynamic/dynamic_message.go | 74 +++++++++++++++++++++++++++++--------- internal/unrecognized.go | 57 ++++------------------------- 2 files changed, 63 insertions(+), 68 deletions(-) diff --git a/dynamic/dynamic_message.go b/dynamic/dynamic_message.go index de13b923..9b049193 100644 --- a/dynamic/dynamic_message.go +++ b/dynamic/dynamic_message.go @@ -11,6 +11,8 @@ import ( "github.com/golang/protobuf/proto" "github.com/golang/protobuf/protoc-gen-go/descriptor" + protov2 "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" "github.com/jhump/protoreflect/codec" "github.com/jhump/protoreflect/desc" @@ -411,19 +413,20 @@ func (m *Message) GetField(fd *desc.FieldDescriptor) interface{} { // The Go type of the returned value, for scalar fields, is the same as protoc // would generate for the field (in a non-dynamic message). The table below // lists the scalar types and the corresponding Go types. -// +-------------------------+-----------+ -// | Declared Type | Go Type | -// +-------------------------+-----------+ -// | int32, sint32, sfixed32 | int32 | -// | int64, sint64, sfixed64 | int64 | -// | uint32, fixed32 | uint32 | -// | uint64, fixed64 | uint64 | -// | float | float32 | -// | double | double32 | -// | bool | bool | -// | string | string | -// | bytes | []byte | -// +-------------------------+-----------+ +// +// +-------------------------+-----------+ +// | Declared Type | Go Type | +// +-------------------------+-----------+ +// | int32, sint32, sfixed32 | int32 | +// | int64, sint64, sfixed64 | int64 | +// | uint32, fixed32 | uint32 | +// | uint64, fixed64 | uint64 | +// | float | float32 | +// | double | double32 | +// | bool | bool | +// | string | string | +// | bytes | []byte | +// +-------------------------+-----------+ // // Values for enum fields will always be int32 values. You can use the enum // descriptor associated with the field to lookup value names with those values. @@ -2053,8 +2056,9 @@ func (m *Message) ProtoMessage() { // ConvertTo converts this dynamic message into the given message. This is // shorthand for resetting then merging: -// target.Reset() -// m.MergeInto(target) +// +// target.Reset() +// m.MergeInto(target) func (m *Message) ConvertTo(target proto.Message) error { if err := m.checkType(target); err != nil { return err @@ -2081,8 +2085,9 @@ func (m *Message) ConvertToDeterministic(target proto.Message) error { // ConvertFrom converts the given message into this dynamic message. This is // shorthand for resetting then merging: -// m.Reset() -// m.MergeFrom(target) +// +// m.Reset() +// m.MergeFrom(target) func (m *Message) ConvertFrom(target proto.Message) error { if err := m.checkType(target); err != nil { return err @@ -2553,6 +2558,35 @@ func (m *Message) mergeFrom(pm proto.Message) error { } } + // unrecognized extensions fields: + // In API v2 of proto, some extensions may NEITHER be included in ExtensionDescs + // above NOR included in unrecognized fields below. These are extensions that use + // a custom extension type (not a generated one -- i.e. not a linked in extension). + mr := proto.MessageReflect(pm) + var extBytes []byte + var retErr error + mr.Range(func(fld protoreflect.FieldDescriptor, val protoreflect.Value) bool { + if !fld.IsExtension() { + // normal field, already processed above + return true + } + if extd, ok := fld.(protoreflect.ExtensionTypeDescriptor); ok { + if _, ok := extd.Type().(*proto.ExtensionDesc); ok { + // normal known extension, already processed above + return true + } + } + + // marshal the extension to bytes and then handle as unknown field below + mr.New() + mr.Set(fld, val) + extBytes, retErr = protov2.MarshalOptions{}.MarshalAppend(extBytes, mr.Interface()) + return retErr == nil + }) + if retErr != nil { + return retErr + } + // now actually perform the merge for fd, v := range values { if err := mergeField(m, fd, v); err != nil { @@ -2560,6 +2594,12 @@ func (m *Message) mergeFrom(pm proto.Message) error { } } + if len(extBytes) > 0 { + // treating unrecognized extensions like unknown fields: best-effort + // ignore any error returned: pulling in unknown fields is best-effort + _ = m.UnmarshalMerge(extBytes) + } + data := internal.GetUnrecognized(pm) if len(data) > 0 { // ignore any error returned: pulling in unknown fields is best-effort diff --git a/internal/unrecognized.go b/internal/unrecognized.go index c903d4b2..e4cda555 100644 --- a/internal/unrecognized.go +++ b/internal/unrecognized.go @@ -15,14 +15,8 @@ func GetUnrecognized(msg proto.Message) []byte { if u.IsValid() && u.Type() == typeOfBytes { return u.Interface().([]byte) } - - // Fallback to reflection for API v2 messages - get, _, _, ok := unrecognizedGetSetMethods(val) - if !ok { - return nil - } - - return get.Call([]reflect.Value(nil))[0].Convert(typeOfBytes).Interface().([]byte) + // if we didn't get it from the field, try using V2 API to get it + return proto.MessageReflect(msg).GetUnknown() } // SetUnrecognized adds the given bytes to the unrecognized fields for the given message. @@ -37,50 +31,11 @@ func SetUnrecognized(msg proto.Message, data []byte) { return } - // Fallback to reflection for API v2 messages - get, set, argType, ok := unrecognizedGetSetMethods(val) - if !ok { - return - } - - existing := get.Call([]reflect.Value(nil))[0].Convert(typeOfBytes).Interface().([]byte) + // if we can't set the field, try using V2 API to get it + mr := proto.MessageReflect(msg) + existing := mr.GetUnknown() if len(existing) > 0 { data = append(existing, data...) } - set.Call([]reflect.Value{reflect.ValueOf(data).Convert(argType)}) -} - -func unrecognizedGetSetMethods(val reflect.Value) (get reflect.Value, set reflect.Value, argType reflect.Type, ok bool) { - // val could be an APIv2 message. We use reflection to interact with - // this message so that we don't have a hard dependency on the new - // version of the protobuf package. - refMethod := val.MethodByName("ProtoReflect") - if !refMethod.IsValid() { - if val.CanAddr() { - refMethod = val.Addr().MethodByName("ProtoReflect") - } - if !refMethod.IsValid() { - return - } - } - refType := refMethod.Type() - if refType.NumIn() != 0 || refType.NumOut() != 1 { - return - } - ref := refMethod.Call([]reflect.Value(nil)) - getMethod, setMethod := ref[0].MethodByName("GetUnknown"), ref[0].MethodByName("SetUnknown") - if !getMethod.IsValid() || !setMethod.IsValid() { - return - } - getType := getMethod.Type() - setType := setMethod.Type() - if getType.NumIn() != 0 || getType.NumOut() != 1 || setType.NumIn() != 1 || setType.NumOut() != 0 { - return - } - arg := setType.In(0) - if !arg.ConvertibleTo(typeOfBytes) || getType.Out(0) != arg { - return - } - - return getMethod, setMethod, arg, true + mr.SetUnknown(data) } From c8957c4274840287053163691d8d3ba00f058f84 Mon Sep 17 00:00:00 2001 From: Josh Humphries Date: Wed, 28 Sep 2022 16:27:24 -0400 Subject: [PATCH 2/3] some more cleanup: removing reflective code paths that can now safely directly access newer fields --- desc/builder/field.go | 27 ++++++------ desc/descriptor.go | 29 ++++++------- desc/internal/proto3_optional.go | 62 +--------------------------- desc/protoparse/descriptor_protos.go | 2 +- 4 files changed, 32 insertions(+), 88 deletions(-) diff --git a/desc/builder/field.go b/desc/builder/field.go index f3b5b453..5f6ff670 100644 --- a/desc/builder/field.go +++ b/desc/builder/field.go @@ -538,19 +538,22 @@ func (flb *FieldBuilder) buildProto(path []int32, sourceInfo *dpb.SourceCodeInfo return nil, fmt.Errorf("tag for field %s cannot be above max %d", GetFullyQualifiedName(flb), maxTag) } - fd := &dpb.FieldDescriptorProto{ - Name: proto.String(flb.name), - Number: proto.Int32(flb.number), - Options: flb.Options, - Label: lbl, - Type: flb.fieldType.fieldType.Enum(), - TypeName: typeName, - JsonName: proto.String(jsName), - DefaultValue: def, - Extendee: extendee, - } + var proto3Optional *bool if flb.Proto3Optional { - internal.SetProto3Optional(fd) + proto3Optional = proto.Bool(true) + } + + fd := &dpb.FieldDescriptorProto{ + Name: proto.String(flb.name), + Number: proto.Int32(flb.number), + Options: flb.Options, + Label: lbl, + Type: flb.fieldType.fieldType.Enum(), + TypeName: typeName, + JsonName: proto.String(jsName), + DefaultValue: def, + Extendee: extendee, + Proto3Optional: proto3Optional, } return fd, nil } diff --git a/desc/descriptor.go b/desc/descriptor.go index a6eb0950..ff6910da 100644 --- a/desc/descriptor.go +++ b/desc/descriptor.go @@ -1040,7 +1040,7 @@ func (fd *FieldDescriptor) IsRepeated() bool { // extensions), will be nested in synthetic oneofs that contain only the single // field. func (fd *FieldDescriptor) IsProto3Optional() bool { - return internal.GetProto3Optional(fd.proto) + return fd.proto.GetProto3Optional() } // HasPresence returns true if this field can distinguish when a value is @@ -1101,19 +1101,20 @@ func (fd *FieldDescriptor) GetEnumType() *EnumDescriptor { // Otherwise, it returns the declared default value for the field or a zero value, if no // default is declared or if the file is proto3. The type of said return value corresponds // to the type of the field: -// +-------------------------+-----------+ -// | Declared Type | Go Type | -// +-------------------------+-----------+ -// | int32, sint32, sfixed32 | int32 | -// | int64, sint64, sfixed64 | int64 | -// | uint32, fixed32 | uint32 | -// | uint64, fixed64 | uint64 | -// | float | float32 | -// | double | double32 | -// | bool | bool | -// | string | string | -// | bytes | []byte | -// +-------------------------+-----------+ +// +// +-------------------------+-----------+ +// | Declared Type | Go Type | +// +-------------------------+-----------+ +// | int32, sint32, sfixed32 | int32 | +// | int64, sint64, sfixed64 | int64 | +// | uint32, fixed32 | uint32 | +// | uint64, fixed64 | uint64 | +// | float | float32 | +// | double | double32 | +// | bool | bool | +// | string | string | +// | bytes | []byte | +// +-------------------------+-----------+ func (fd *FieldDescriptor) GetDefaultValue() interface{} { return fd.getDefaultValue() } diff --git a/desc/internal/proto3_optional.go b/desc/internal/proto3_optional.go index ef35cdd7..2d499752 100644 --- a/desc/internal/proto3_optional.go +++ b/desc/internal/proto3_optional.go @@ -3,69 +3,9 @@ package internal import ( "github.com/golang/protobuf/proto" dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" - "github.com/jhump/protoreflect/internal/codec" - "reflect" "strings" - - "github.com/jhump/protoreflect/internal" ) -// NB: We use reflection or unknown fields in case we are linked against an older -// version of the proto runtime which does not know about the proto3_optional field. -// We don't require linking with newer version (which would greatly simplify this) -// because that means pulling in v1.4+ of the protobuf runtime, which has some -// compatibility issues. (We'll be nice to users and not require they upgrade to -// that latest runtime to upgrade to newer protoreflect.) - -func GetProto3Optional(fd *dpb.FieldDescriptorProto) bool { - type newerFieldDesc interface { - GetProto3Optional() bool - } - var pm proto.Message = fd - if fd, ok := pm.(newerFieldDesc); ok { - return fd.GetProto3Optional() - } - - // Field does not exist, so we have to examine unknown fields - // (we just silently bail if we have problems parsing them) - unk := internal.GetUnrecognized(pm) - buf := codec.NewBuffer(unk) - for { - tag, wt, err := buf.DecodeTagAndWireType() - if err != nil { - return false - } - if tag == Field_proto3OptionalTag && wt == proto.WireVarint { - v, _ := buf.DecodeVarint() - return v != 0 - } - if err := buf.SkipField(wt); err != nil { - return false - } - } -} - -func SetProto3Optional(fd *dpb.FieldDescriptorProto) { - rv := reflect.ValueOf(fd).Elem() - fld := rv.FieldByName("Proto3Optional") - if fld.IsValid() { - fld.Set(reflect.ValueOf(proto.Bool(true))) - return - } - - // Field does not exist, so we have to store as unknown field. - var buf codec.Buffer - if err := buf.EncodeTagAndWireType(Field_proto3OptionalTag, proto.WireVarint); err != nil { - // TODO: panic? log? - return - } - if err := buf.EncodeVarint(1); err != nil { - // TODO: panic? log? - return - } - internal.SetUnrecognized(fd, buf.Bytes()) -} - // ProcessProto3OptionalFields adds synthetic oneofs to the given message descriptor // for each proto3 optional field. It also updates the fields to have the correct // oneof index reference. The given callback, if not nil, is called for each synthetic @@ -73,7 +13,7 @@ func SetProto3Optional(fd *dpb.FieldDescriptorProto) { func ProcessProto3OptionalFields(msgd *dpb.DescriptorProto, callback func(*dpb.FieldDescriptorProto, *dpb.OneofDescriptorProto)) { var allNames map[string]struct{} for _, fd := range msgd.Field { - if GetProto3Optional(fd) { + if fd.GetProto3Optional() { // lazy init the set of all names if allNames == nil { allNames = map[string]struct{}{} diff --git a/desc/protoparse/descriptor_protos.go b/desc/protoparse/descriptor_protos.go index 993ef253..afff8d6c 100644 --- a/desc/protoparse/descriptor_protos.go +++ b/desc/protoparse/descriptor_protos.go @@ -203,7 +203,7 @@ func (r *parseResult) asFieldDescriptor(node *ast.FieldNode, maxTag int32, isPro fd.Options = &dpb.FieldOptions{UninterpretedOption: r.asUninterpretedOptions(opts)} } if isProto3 && fd.Label != nil && fd.GetLabel() == dpb.FieldDescriptorProto_LABEL_OPTIONAL { - internal.SetProto3Optional(fd) + fd.Proto3Optional = proto.Bool(true) } return fd } From 79fe7c3acb7b81705629073eecbd73722f24793e Mon Sep 17 00:00:00 2001 From: Josh Humphries Date: Wed, 28 Sep 2022 16:27:37 -0400 Subject: [PATCH 3/3] gofmt --- desc/builder/doc.go | 100 ++++++++++++-------------- desc/convert.go | 6 +- desc/doc.go | 7 +- desc/imports.go | 26 ++++--- desc/internal/util.go | 6 +- desc/protoparse/ast/enum.go | 24 +++---- desc/protoparse/ast/field.go | 110 +++++++++++++++-------------- desc/protoparse/ast/file.go | 30 ++++---- desc/protoparse/ast/identifiers.go | 6 +- desc/protoparse/ast/message.go | 43 +++++------ desc/protoparse/ast/options.go | 30 ++++---- desc/protoparse/ast/ranges.go | 40 +++++------ desc/protoparse/ast/service.go | 58 +++++++-------- desc/protoparse/ast/values.go | 10 +-- desc/protoparse/linker.go | 6 +- desc/protoparse/parser.go | 28 ++++---- desc/sourceinfo/registry.go | 13 ++-- dynamic/doc.go | 38 +++++----- dynamic/json.go | 6 +- dynamic/message_factory.go | 7 +- 20 files changed, 298 insertions(+), 296 deletions(-) diff --git a/desc/builder/doc.go b/desc/builder/doc.go index f5fd4c24..9c52ef4f 100644 --- a/desc/builder/doc.go +++ b/desc/builder/doc.go @@ -3,8 +3,7 @@ // new descriptors as are there methods for converting existing descriptors into // builders, for modification. // -// -// Factory Functions +// # Factory Functions // // Builders are created using the numerous factory functions. Each type of // descriptor has two kinds of factory functions for the corresponding type of @@ -26,8 +25,7 @@ // nil values for required fields (such as field types, RPC method types, and // extendee type for extensions). // -// -// Auto-Assigning Tag Numbers and File Names +// # Auto-Assigning Tag Numbers and File Names // // The factory function for fields does not accept a tag number. This is because // tags, for fields where none is set or is explicitly set to zero, are @@ -48,8 +46,7 @@ // can have their tags auto-assigned. If an extension is constructed with a zero // tag (which is not valid), the factory function will panic. // -// -// Descriptor Hierarchy +// # Descriptor Hierarchy // // The hierarchy for builders is mutable. A descriptor builder, such as a field, // can be moved from one message to another. When this is done, the field is @@ -59,10 +56,10 @@ // can simply be copied. This allows for copying a descriptor from one parent to // another, like so: // -// msg := builder.FromMessage(someMsgDesc) -// field1 := msg.GetField("foo") -// field2 := *field1 // field2 is now a copy -// otherMsg.AddField(&field2) +// msg := builder.FromMessage(someMsgDesc) +// field1 := msg.GetField("foo") +// field2 := *field1 // field2 is now a copy +// otherMsg.AddField(&field2) // // All descriptors have a link up the hierarchy to the file in which they were // declared. However, it is *not* necessary to construct this full hierarchy @@ -80,8 +77,7 @@ // unnamed) package. In order to put descriptors into a proper package // namespace, they must be added to a file that has the right package name. // -// -// Builder Pattern and Method Chaining +// # Builder Pattern and Method Chaining // // Each descriptor has some special fields that can only be updated via a Set* // method. They also all have some exported fields that can be updated by just @@ -89,13 +85,13 @@ // methods in order to support a typical method-chaining flow when building // objects: // -// msg, err := builder.NewMessage("MyMessage"). -// AddField(NewField("foo", FieldTypeScalar(descriptor.FieldDescriptorProto_TYPE_STRING)). -// SetDefaultValue("bar")). -// AddField(NewField("baz", FieldTypeScalar(descriptor.FieldDescriptorProto_TYPE_INT64)). -// SetLabel(descriptor.FieldDescriptorProto_LABEL_REPEATED). -// SetOptions(&descriptor.FieldOptions{Packed: proto.Bool(true)})). -// Build() +// msg, err := builder.NewMessage("MyMessage"). +// AddField(NewField("foo", FieldTypeScalar(descriptor.FieldDescriptorProto_TYPE_STRING)). +// SetDefaultValue("bar")). +// AddField(NewField("baz", FieldTypeScalar(descriptor.FieldDescriptorProto_TYPE_INT64)). +// SetLabel(descriptor.FieldDescriptorProto_LABEL_REPEATED). +// SetOptions(&descriptor.FieldOptions{Packed: proto.Bool(true)})). +// Build() // // So the various Set* methods all return the builder itself so that multiple // fields may be set in a single invocation chain. @@ -104,8 +100,7 @@ // can return an error if validation fails. If the method-chaining Set* form is // used with inputs that fail validation, the Set* method will panic. // -// -// Type References and Imported Types +// # Type References and Imported Types // // When defining fields whose type is a message or enum and when defining // methods (whose request and response type are a message), the type can be set @@ -128,8 +123,7 @@ // imports the other). And the same would be true if one or both files were // explicitly assigned to a file, but not both to the same file. // -// -// Validations and Caveats +// # Validations and Caveats // // Descriptors that are attained from a builder do not necessarily represent a // valid construct in the proto source language. There are some validations @@ -153,40 +147,40 @@ // in errors (or panics for factory functions and methods that do not return // errors). These are the rules that are currently enforced: // -// 1. Import cycles are not allowed. (See above for more details.) -// 2. Within a single file, symbols are not allowed to have naming conflicts. -// This means that is not legal to create a message and an extension with -// the same name in the same file. -// 3. Messages are not allowed to have multiple fields with the same tag. Note -// that only non-extension fields are checked when using builders. So -// builders will allow tag collisions for extensions. (Use caution.) -// 4. Map keys can only be integer types, booleans, and strings. -// 5. Fields cannot have tags in the special reserved range 19000-19999. Also -// the maximum allowed tag value is 536870911 (2^29 - 1). Finally, fields -// cannot have negative values. -// 6. Element names should include only underscore, letters, and numbers, and -// must begin with an underscore or letter. +// 1. Import cycles are not allowed. (See above for more details.) +// 2. Within a single file, symbols are not allowed to have naming conflicts. +// This means that is not legal to create a message and an extension with +// the same name in the same file. +// 3. Messages are not allowed to have multiple fields with the same tag. Note +// that only non-extension fields are checked when using builders. So +// builders will allow tag collisions for extensions. (Use caution.) +// 4. Map keys can only be integer types, booleans, and strings. +// 5. Fields cannot have tags in the special reserved range 19000-19999. Also +// the maximum allowed tag value is 536870911 (2^29 - 1). Finally, fields +// cannot have negative values. +// 6. Element names should include only underscore, letters, and numbers, and +// must begin with an underscore or letter. // // Validation rules that are *not* enforced by builders, and thus would be // allowed and result in illegal constructs, include the following: // -// 1. Files with a syntax of proto3 are not allowed to have required fields. -// 2. Files with a syntax of proto3 are not allowed to have messages that -// define extension ranges. -// 3. Files with a syntax of proto3 are not allowed to use groups. -// 4. Files with a syntax of proto3 are not allowed to declare default values -// for fields. -// 5. Names are supposed to be globally unique, even across multiple files -// if multiple files are defined in the same package. -// 6. Extension fields must use tag numbers that are in an extension range -// defined on the extended message. -// 7. Multiple extensions for the same message cannot re-use tag numbers, even -// across multiple files. -// 8. Non-extension fields are not allowed to use tags that lie in a message's -// extension ranges or reserved ranges. -// 9. Non-extension fields are not allowed to use names that the message has -// marked as reserved. -// 10. Extension ranges and reserved ranges must not overlap. +// 1. Files with a syntax of proto3 are not allowed to have required fields. +// 2. Files with a syntax of proto3 are not allowed to have messages that +// define extension ranges. +// 3. Files with a syntax of proto3 are not allowed to use groups. +// 4. Files with a syntax of proto3 are not allowed to declare default values +// for fields. +// 5. Names are supposed to be globally unique, even across multiple files +// if multiple files are defined in the same package. +// 6. Extension fields must use tag numbers that are in an extension range +// defined on the extended message. +// 7. Multiple extensions for the same message cannot re-use tag numbers, even +// across multiple files. +// 8. Non-extension fields are not allowed to use tags that lie in a message's +// extension ranges or reserved ranges. +// 9. Non-extension fields are not allowed to use names that the message has +// marked as reserved. +// 10. Extension ranges and reserved ranges must not overlap. // // This list may change in the future, as more validation rules may be // implemented in the builders. diff --git a/desc/convert.go b/desc/convert.go index 538820c3..60999421 100644 --- a/desc/convert.go +++ b/desc/convert.go @@ -160,7 +160,8 @@ func addAllFiles(src []*FileDescriptor, results *[]*dpb.FileDescriptorProto, see // set's *last* file will be the returned descriptor. The set's remaining files must comprise // the full set of transitive dependencies of that last file. This is the same format and // order used by protoc when emitting a FileDescriptorSet file with an invocation like so: -// protoc --descriptor_set_out=./test.protoset --include_imports -I. test.proto +// +// protoc --descriptor_set_out=./test.protoset --include_imports -I. test.proto func CreateFileDescriptorFromSet(fds *dpb.FileDescriptorSet) (*FileDescriptor, error) { return createFileDescriptorFromSet(fds, nil) } @@ -180,7 +181,8 @@ func createFileDescriptorFromSet(fds *dpb.FileDescriptorSet, r *ImportResolver) // full set of transitive dependencies for all files therein or else a link error will occur // and be returned instead of the slice of descriptors. This is the same format used by // protoc when a FileDescriptorSet file with an invocation like so: -// protoc --descriptor_set_out=./test.protoset --include_imports -I. test.proto +// +// protoc --descriptor_set_out=./test.protoset --include_imports -I. test.proto func CreateFileDescriptorsFromSet(fds *dpb.FileDescriptorSet) (map[string]*FileDescriptor, error) { return createFileDescriptorsFromSet(fds, nil) } diff --git a/desc/doc.go b/desc/doc.go index 642f125e..dfac5c72 100644 --- a/desc/doc.go +++ b/desc/doc.go @@ -27,8 +27,7 @@ // Also see the grpcreflect, dynamic, and grpcdynamic packages in this same // repo to see just how useful rich descriptors really are. // -// -// Loading Descriptors +// # Loading Descriptors // // Rich descriptors can be accessed in similar ways as their "poor" cousins // (descriptor protos). Instead of using proto.FileDescriptor, use @@ -40,8 +39,7 @@ // the descriptors returned from these Load* functions will include source code // information, and thus include comments for elements. // -// -// Creating Descriptors +// # Creating Descriptors // // It is also possible create rich descriptors for proto messages that a given // Go program doesn't even know about. For example, they could be loaded from a @@ -61,5 +59,4 @@ // // Also see the desc/builder sub-package, for another API that makes it easier // to synthesize descriptors programmatically. -// package desc diff --git a/desc/imports.go b/desc/imports.go index fc03c746..0cace1f4 100644 --- a/desc/imports.go +++ b/desc/imports.go @@ -76,25 +76,31 @@ func ResolveImport(importPath string) string { // // For example, let's say we have two proto source files: "foo/bar.proto" and // "fubar/baz.proto". The latter imports the former using a line like so: -// import "foo/bar.proto"; +// +// import "foo/bar.proto"; +// // However, when protoc is invoked, the command-line args looks like so: -// protoc -Ifoo/ --go_out=foo/ bar.proto -// protoc -I./ -Ifubar/ --go_out=fubar/ baz.proto +// +// protoc -Ifoo/ --go_out=foo/ bar.proto +// protoc -I./ -Ifubar/ --go_out=fubar/ baz.proto +// // Because the path given to protoc is just "bar.proto" and "baz.proto", this is // how they are registered in the Go protobuf runtime. So, when loading the // descriptor for "fubar/baz.proto", we'll see an import path of "foo/bar.proto" // but will find no file registered with that path: -// fd, err := desc.LoadFileDescriptor("baz.proto") -// // err will be non-nil, complaining that there is no such file -// // found named "foo/bar.proto" +// +// fd, err := desc.LoadFileDescriptor("baz.proto") +// // err will be non-nil, complaining that there is no such file +// // found named "foo/bar.proto" // // This can be remedied by registering alternate import paths using an // ImportResolver. Continuing with the example above, the code below would fix // any link issue: -// var r desc.ImportResolver -// r.RegisterImportPath("bar.proto", "foo/bar.proto") -// fd, err := r.LoadFileDescriptor("baz.proto") -// // err will be nil; descriptor successfully loaded! +// +// var r desc.ImportResolver +// r.RegisterImportPath("bar.proto", "foo/bar.proto") +// fd, err := r.LoadFileDescriptor("baz.proto") +// // err will be nil; descriptor successfully loaded! // // If there are files that are *always* imported using a different relative // path then how they are registered, consider using the global diff --git a/desc/internal/util.go b/desc/internal/util.go index 95013a7d..fcadbd1f 100644 --- a/desc/internal/util.go +++ b/desc/internal/util.go @@ -220,7 +220,8 @@ const ( // JsonName returns the default JSON name for a field with the given name. // This mirrors the algorithm in protoc: -// https://github.com/protocolbuffers/protobuf/blob/v21.3/src/google/protobuf/descriptor.cc#L95 +// +// https://github.com/protocolbuffers/protobuf/blob/v21.3/src/google/protobuf/descriptor.cc#L95 func JsonName(name string) string { var js []rune nextUpper := false @@ -251,7 +252,8 @@ func InitCap(name string) string { // that token and the empty string, e.g. ["foo", ""]. Otherwise, it returns // successively shorter prefixes of the package and then the empty string. For // example, for a package named "foo.bar.baz" it will return the following list: -// ["foo.bar.baz", "foo.bar", "foo", ""] +// +// ["foo.bar.baz", "foo.bar", "foo", ""] func CreatePrefixList(pkg string) []string { if pkg == "" { return []string{""} diff --git a/desc/protoparse/ast/enum.go b/desc/protoparse/ast/enum.go index 769e056e..446a6a01 100644 --- a/desc/protoparse/ast/enum.go +++ b/desc/protoparse/ast/enum.go @@ -4,7 +4,7 @@ import "fmt" // EnumNode represents an enum declaration. Example: // -// enum Foo { BAR = 0; BAZ = 1 } +// enum Foo { BAR = 0; BAZ = 1 } type EnumNode struct { compositeNode Keyword *KeywordNode @@ -20,11 +20,11 @@ func (*EnumNode) msgElement() {} // NewEnumNode creates a new *EnumNode. All arguments must be non-nil. While // it is technically allowed for decls to be nil or empty, the resulting node // will not be a valid enum, which must have at least one value. -// - keyword: The token corresponding to the "enum" keyword. -// - name: The token corresponding to the enum's name. -// - openBrace: The token corresponding to the "{" rune that starts the body. -// - decls: All declarations inside the enum body. -// - closeBrace: The token corresponding to the "}" rune that ends the body. +// - keyword: The token corresponding to the "enum" keyword. +// - name: The token corresponding to the enum's name. +// - openBrace: The token corresponding to the "{" rune that starts the body. +// - decls: All declarations inside the enum body. +// - closeBrace: The token corresponding to the "}" rune that ends the body. func NewEnumNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []EnumElement, closeBrace *RuneNode) *EnumNode { if keyword == nil { panic("keyword is nil") @@ -91,7 +91,7 @@ var _ EnumValueDeclNode = NoSourceNode{} // EnumNode represents an enum declaration. Example: // -// UNSET = 0 [deprecated = true]; +// UNSET = 0 [deprecated = true]; type EnumValueNode struct { compositeNode Name *IdentNode @@ -105,11 +105,11 @@ func (*EnumValueNode) enumElement() {} // NewEnumValueNode creates a new *EnumValueNode. All arguments must be non-nil // except opts which is only non-nil if the declaration included options. -// - name: The token corresponding to the enum value's name. -// - equals: The token corresponding to the '=' rune after the name. -// - number: The token corresponding to the enum value's number. -// - opts: Optional set of enum value options. -// - semicolon: The token corresponding to the ";" rune that ends the declaration. +// - name: The token corresponding to the enum value's name. +// - equals: The token corresponding to the '=' rune after the name. +// - number: The token corresponding to the enum value's number. +// - opts: Optional set of enum value options. +// - semicolon: The token corresponding to the ";" rune that ends the declaration. func NewEnumValueNode(name *IdentNode, equals *RuneNode, number IntValueNode, opts *CompactOptionsNode, semicolon *RuneNode) *EnumValueNode { if name == nil { panic("name is nil") diff --git a/desc/protoparse/ast/field.go b/desc/protoparse/ast/field.go index 0d77f27a..7ec9391b 100644 --- a/desc/protoparse/ast/field.go +++ b/desc/protoparse/ast/field.go @@ -5,10 +5,11 @@ import "fmt" // FieldDeclNode is a node in the AST that defines a field. This includes // normal message fields as well as extensions. There are multiple types // of AST nodes that declare fields: -// - *FieldNode -// - *GroupNode -// - *MapFieldNode -// - *SyntheticMapField +// - *FieldNode +// - *GroupNode +// - *MapFieldNode +// - *SyntheticMapField +// // This also allows NoSourceNode to be used in place of one of the above // for some usages. type FieldDeclNode interface { @@ -32,7 +33,7 @@ var _ FieldDeclNode = NoSourceNode{} // can represent extension fields as well as non-extension fields (both inside // of messages and inside of one-ofs). Example: // -// optional string foo = 1; +// optional string foo = 1; type FieldNode struct { compositeNode Label FieldLabel @@ -54,14 +55,14 @@ func (*FieldNode) extendElement() {} // NewFieldNode creates a new *FieldNode. The label and options arguments may be // nil but the others must be non-nil. -// - label: The token corresponding to the label keyword if present ("optional", -// "required", or "repeated"). -// - fieldType: The token corresponding to the field's type. -// - name: The token corresponding to the field's name. -// - equals: The token corresponding to the '=' rune after the name. -// - tag: The token corresponding to the field's tag number. -// - opts: Optional set of field options. -// - semicolon: The token corresponding to the ";" rune that ends the declaration. +// - label: The token corresponding to the label keyword if present ("optional", +// "required", or "repeated"). +// - fieldType: The token corresponding to the field's type. +// - name: The token corresponding to the field's name. +// - equals: The token corresponding to the '=' rune after the name. +// - tag: The token corresponding to the field's tag number. +// - opts: Optional set of field options. +// - semicolon: The token corresponding to the ";" rune that ends the declaration. func NewFieldNode(label *KeywordNode, fieldType IdentValueNode, name *IdentNode, equals *RuneNode, tag *UintLiteralNode, opts *CompactOptionsNode, semicolon *RuneNode) *FieldNode { if fieldType == nil { panic("fieldType is nil") @@ -178,10 +179,10 @@ func (f *FieldLabel) IsPresent() bool { // non-extension fields (both inside of messages and inside of one-ofs). // Example: // -// optional group Key = 4 { -// optional uint64 id = 1; -// optional string name = 2; -// } +// optional group Key = 4 { +// optional uint64 id = 1; +// optional string name = 2; +// } type GroupNode struct { compositeNode Label FieldLabel @@ -203,16 +204,16 @@ func (*GroupNode) extendElement() {} // NewGroupNode creates a new *GroupNode. The label and options arguments may be // nil but the others must be non-nil. -// - label: The token corresponding to the label keyword if present ("optional", -// "required", or "repeated"). -// - keyword: The token corresponding to the "group" keyword. -// - name: The token corresponding to the field's name. -// - equals: The token corresponding to the '=' rune after the name. -// - tag: The token corresponding to the field's tag number. -// - opts: Optional set of field options. -// - openBrace: The token corresponding to the "{" rune that starts the body. -// - decls: All declarations inside the group body. -// - closeBrace: The token corresponding to the "}" rune that ends the body. +// - label: The token corresponding to the label keyword if present ("optional", +// "required", or "repeated"). +// - keyword: The token corresponding to the "group" keyword. +// - name: The token corresponding to the field's name. +// - equals: The token corresponding to the '=' rune after the name. +// - tag: The token corresponding to the field's tag number. +// - opts: Optional set of field options. +// - openBrace: The token corresponding to the "{" rune that starts the body. +// - decls: All declarations inside the group body. +// - closeBrace: The token corresponding to the "}" rune that ends the body. func NewGroupNode(label *KeywordNode, keyword *KeywordNode, name *IdentNode, equals *RuneNode, tag *UintLiteralNode, opts *CompactOptionsNode, openBrace *RuneNode, decls []MessageElement, closeBrace *RuneNode) *GroupNode { if keyword == nil { panic("fieldType is nil") @@ -309,8 +310,9 @@ func (n *GroupNode) MessageName() Node { // OneOfDeclNode is a node in the AST that defines a oneof. There are // multiple types of AST nodes that declare oneofs: -// - *OneOfNode -// - *SyntheticOneOf +// - *OneOfNode +// - *SyntheticOneOf +// // This also allows NoSourceNode to be used in place of one of the above // for some usages. type OneOfDeclNode interface { @@ -320,12 +322,12 @@ type OneOfDeclNode interface { // OneOfNode represents a one-of declaration. Example: // -// oneof query { -// string by_name = 2; -// Type by_type = 3; -// Address by_address = 4; -// Labels by_label = 5; -// } +// oneof query { +// string by_name = 2; +// Type by_type = 3; +// Address by_address = 4; +// Labels by_label = 5; +// } type OneOfNode struct { compositeNode Keyword *KeywordNode @@ -340,11 +342,11 @@ func (*OneOfNode) msgElement() {} // NewOneOfNode creates a new *OneOfNode. All arguments must be non-nil. While // it is technically allowed for decls to be nil or empty, the resulting node // will not be a valid oneof, which must have at least one field. -// - keyword: The token corresponding to the "oneof" keyword. -// - name: The token corresponding to the oneof's name. -// - openBrace: The token corresponding to the "{" rune that starts the body. -// - decls: All declarations inside the oneof body. -// - closeBrace: The token corresponding to the "}" rune that ends the body. +// - keyword: The token corresponding to the "oneof" keyword. +// - name: The token corresponding to the oneof's name. +// - openBrace: The token corresponding to the "{" rune that starts the body. +// - decls: All declarations inside the oneof body. +// - closeBrace: The token corresponding to the "}" rune that ends the body. func NewOneOfNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []OneOfElement, closeBrace *RuneNode) *OneOfNode { if keyword == nil { panic("keyword is nil") @@ -437,7 +439,7 @@ var _ OneOfElement = (*EmptyDeclNode)(nil) // MapTypeNode represents the type declaration for a map field. It defines // both the key and value types for the map. Example: // -// map +// map type MapTypeNode struct { compositeNode Keyword *KeywordNode @@ -449,12 +451,12 @@ type MapTypeNode struct { } // NewMapTypeNode creates a new *MapTypeNode. All arguments must be non-nil. -// - keyword: The token corresponding to the "map" keyword. -// - openAngle: The token corresponding to the "<" rune after the keyword. -// - keyType: The token corresponding to the key type for the map. -// - comma: The token corresponding to the "," rune between key and value types. -// - valType: The token corresponding to the value type for the map. -// - closeAngle: The token corresponding to the ">" rune that ends the declaration. +// - keyword: The token corresponding to the "map" keyword. +// - openAngle: The token corresponding to the "<" rune after the keyword. +// - keyType: The token corresponding to the key type for the map. +// - comma: The token corresponding to the "," rune between key and value types. +// - valType: The token corresponding to the value type for the map. +// - closeAngle: The token corresponding to the ">" rune that ends the declaration. func NewMapTypeNode(keyword *KeywordNode, openAngle *RuneNode, keyType *IdentNode, comma *RuneNode, valType IdentValueNode, closeAngle *RuneNode) *MapTypeNode { if keyword == nil { panic("keyword is nil") @@ -490,7 +492,7 @@ func NewMapTypeNode(keyword *KeywordNode, openAngle *RuneNode, keyType *IdentNod // MapFieldNode represents a map field declaration. Example: // -// map replacements = 3 [deprecated = true]; +// map replacements = 3 [deprecated = true]; type MapFieldNode struct { compositeNode MapType *MapTypeNode @@ -505,12 +507,12 @@ func (*MapFieldNode) msgElement() {} // NewMapFieldNode creates a new *MapFieldNode. All arguments must be non-nil // except opts, which may be nil. -// - mapType: The token corresponding to the map type. -// - name: The token corresponding to the field's name. -// - equals: The token corresponding to the '=' rune after the name. -// - tag: The token corresponding to the field's tag number. -// - opts: Optional set of field options. -// - semicolon: The token corresponding to the ";" rune that ends the declaration. +// - mapType: The token corresponding to the map type. +// - name: The token corresponding to the field's name. +// - equals: The token corresponding to the '=' rune after the name. +// - tag: The token corresponding to the field's tag number. +// - opts: Optional set of field options. +// - semicolon: The token corresponding to the ";" rune that ends the declaration. func NewMapFieldNode(mapType *MapTypeNode, name *IdentNode, equals *RuneNode, tag *UintLiteralNode, opts *CompactOptionsNode, semicolon *RuneNode) *MapFieldNode { if mapType == nil { panic("mapType is nil") diff --git a/desc/protoparse/ast/file.go b/desc/protoparse/ast/file.go index ed151b1b..2ddd0ce2 100644 --- a/desc/protoparse/ast/file.go +++ b/desc/protoparse/ast/file.go @@ -93,7 +93,7 @@ var _ FileElement = (*EmptyDeclNode)(nil) // SyntaxNode represents a syntax declaration, which if present must be // the first non-comment content. Example: // -// syntax = "proto2"; +// syntax = "proto2"; // // Files that don't have a syntax node are assumed to use proto2 syntax. type SyntaxNode struct { @@ -105,10 +105,10 @@ type SyntaxNode struct { } // NewSyntaxNode creates a new *SyntaxNode. All four arguments must be non-nil: -// - keyword: The token corresponding to the "syntax" keyword. -// - equals: The token corresponding to the "=" rune. -// - syntax: The actual syntax value, e.g. "proto2" or "proto3". -// - semicolon: The token corresponding to the ";" rune that ends the declaration. +// - keyword: The token corresponding to the "syntax" keyword. +// - equals: The token corresponding to the "=" rune. +// - syntax: The actual syntax value, e.g. "proto2" or "proto3". +// - semicolon: The token corresponding to the ";" rune that ends the declaration. func NewSyntaxNode(keyword *KeywordNode, equals *RuneNode, syntax StringValueNode, semicolon *RuneNode) *SyntaxNode { if keyword == nil { panic("keyword is nil") @@ -136,7 +136,7 @@ func NewSyntaxNode(keyword *KeywordNode, equals *RuneNode, syntax StringValueNod // ImportNode represents an import statement. Example: // -// import "google/protobuf/empty.proto"; +// import "google/protobuf/empty.proto"; type ImportNode struct { compositeNode Keyword *KeywordNode @@ -154,11 +154,11 @@ type ImportNode struct { // a public import. When weak is non-nil, it indicates the "weak" keyword in the import // statement and means this is a weak import. When both are nil, this is a normal import. // The other arguments must be non-nil: -// - keyword: The token corresponding to the "import" keyword. -// - public: The token corresponding to the optional "public" keyword. -// - weak: The token corresponding to the optional "weak" keyword. -// - name: The actual imported file name. -// - semicolon: The token corresponding to the ";" rune that ends the declaration. +// - keyword: The token corresponding to the "import" keyword. +// - public: The token corresponding to the optional "public" keyword. +// - weak: The token corresponding to the optional "weak" keyword. +// - name: The actual imported file name. +// - semicolon: The token corresponding to the ";" rune that ends the declaration. func NewImportNode(keyword *KeywordNode, public *KeywordNode, weak *KeywordNode, name StringValueNode, semicolon *RuneNode) *ImportNode { if keyword == nil { panic("keyword is nil") @@ -198,7 +198,7 @@ func (*ImportNode) fileElement() {} // PackageNode represents a package declaration. Example: // -// package foobar.com; +// package foobar.com; type PackageNode struct { compositeNode Keyword *KeywordNode @@ -209,9 +209,9 @@ type PackageNode struct { func (*PackageNode) fileElement() {} // NewPackageNode creates a new *PackageNode. All three arguments must be non-nil: -// - keyword: The token corresponding to the "package" keyword. -// - name: The package name declared for the file. -// - semicolon: The token corresponding to the ";" rune that ends the declaration. +// - keyword: The token corresponding to the "package" keyword. +// - name: The package name declared for the file. +// - semicolon: The token corresponding to the ";" rune that ends the declaration. func NewPackageNode(keyword *KeywordNode, name IdentValueNode, semicolon *RuneNode) *PackageNode { if keyword == nil { panic("keyword is nil") diff --git a/desc/protoparse/ast/identifiers.go b/desc/protoparse/ast/identifiers.go index aa62add5..ed97e973 100644 --- a/desc/protoparse/ast/identifiers.go +++ b/desc/protoparse/ast/identifiers.go @@ -22,7 +22,7 @@ var _ IdentValueNode = (*CompoundIdentNode)(nil) // IdentNode represents a simple, unqualified identifier. These are used to name // elements declared in a protobuf file or to refer to elements. Example: // -// foobar +// foobar type IdentNode struct { terminalNode Val string @@ -56,7 +56,7 @@ func (n *IdentNode) ToKeyword() *KeywordNode { // dots). If the identifier has a leading dot, then it is a *fully* qualified // identifier. Example: // -// .com.foobar.Baz +// .com.foobar.Baz type CompoundIdentNode struct { compositeNode // Optional leading dot, indicating that the identifier is fully qualified. @@ -122,7 +122,7 @@ func (n *CompoundIdentNode) AsIdentifier() Identifier { // like identifiers, but they have special meaning in particular contexts. // Example: // -// message +// message type KeywordNode IdentNode // NewKeywordNode creates a new *KeywordNode. The given val is the keyword. diff --git a/desc/protoparse/ast/message.go b/desc/protoparse/ast/message.go index 80651b66..c98b0f81 100644 --- a/desc/protoparse/ast/message.go +++ b/desc/protoparse/ast/message.go @@ -4,9 +4,10 @@ import "fmt" // MessageDeclNode is a node in the AST that defines a message type. This // includes normal message fields as well as implicit messages: -// - *MessageNode -// - *GroupNode (the group is a field and inline message type) -// - *MapFieldNode (map fields implicitly define a MapEntry message type) +// - *MessageNode +// - *GroupNode (the group is a field and inline message type) +// - *MapFieldNode (map fields implicitly define a MapEntry message type) +// // This also allows NoSourceNode to be used in place of one of the above // for some usages. type MessageDeclNode interface { @@ -21,11 +22,11 @@ var _ MessageDeclNode = NoSourceNode{} // MessageNode represents a message declaration. Example: // -// message Foo { -// string name = 1; -// repeated string labels = 2; -// bytes extra = 3; -// } +// message Foo { +// string name = 1; +// repeated string labels = 2; +// bytes extra = 3; +// } type MessageNode struct { compositeNode Keyword *KeywordNode @@ -37,11 +38,11 @@ func (*MessageNode) fileElement() {} func (*MessageNode) msgElement() {} // NewMessageNode creates a new *MessageNode. All arguments must be non-nil. -// - keyword: The token corresponding to the "message" keyword. -// - name: The token corresponding to the field's name. -// - openBrace: The token corresponding to the "{" rune that starts the body. -// - decls: All declarations inside the message body. -// - closeBrace: The token corresponding to the "}" rune that ends the body. +// - keyword: The token corresponding to the "message" keyword. +// - name: The token corresponding to the field's name. +// - openBrace: The token corresponding to the "{" rune that starts the body. +// - decls: All declarations inside the message body. +// - closeBrace: The token corresponding to the "}" rune that ends the body. func NewMessageNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []MessageElement, closeBrace *RuneNode) *MessageNode { if keyword == nil { panic("keyword is nil") @@ -121,9 +122,9 @@ var _ MessageElement = (*EmptyDeclNode)(nil) // ExtendNode represents a declaration of extension fields. Example: // -// extend google.protobuf.FieldOptions { -// bool redacted = 33333; -// } +// extend google.protobuf.FieldOptions { +// bool redacted = 33333; +// } type ExtendNode struct { compositeNode Keyword *KeywordNode @@ -137,11 +138,11 @@ func (*ExtendNode) fileElement() {} func (*ExtendNode) msgElement() {} // NewExtendNode creates a new *ExtendNode. All arguments must be non-nil. -// - keyword: The token corresponding to the "extend" keyword. -// - extendee: The token corresponding to the name of the extended message. -// - openBrace: The token corresponding to the "{" rune that starts the body. -// - decls: All declarations inside the message body. -// - closeBrace: The token corresponding to the "}" rune that ends the body. +// - keyword: The token corresponding to the "extend" keyword. +// - extendee: The token corresponding to the name of the extended message. +// - openBrace: The token corresponding to the "{" rune that starts the body. +// - decls: All declarations inside the message body. +// - closeBrace: The token corresponding to the "}" rune that ends the body. func NewExtendNode(keyword *KeywordNode, extendee IdentValueNode, openBrace *RuneNode, decls []ExtendElement, closeBrace *RuneNode) *ExtendNode { if keyword == nil { panic("keyword is nil") diff --git a/desc/protoparse/ast/options.go b/desc/protoparse/ast/options.go index 40c32a42..c4ed169c 100644 --- a/desc/protoparse/ast/options.go +++ b/desc/protoparse/ast/options.go @@ -19,7 +19,7 @@ var _ OptionDeclNode = NoSourceNode{} // and end with semicolon) and for compact options found in fields, enum values, // and extension ranges. Example: // -// option (custom.option) = "foo"; +// option (custom.option) = "foo"; type OptionNode struct { compositeNode Keyword *KeywordNode // absent for compact options @@ -39,11 +39,11 @@ func (e *OptionNode) methodElement() {} // NewOptionNode creates a new *OptionNode for a full option declaration (as // used in files, messages, oneofs, enums, services, and methods). All arguments // must be non-nil. (Also see NewCompactOptionNode.) -// - keyword: The token corresponding to the "option" keyword. -// - name: The token corresponding to the name of the option. -// - equals: The token corresponding to the "=" rune after the name. -// - val: The token corresponding to the option value. -// - semicolon: The token corresponding to the ";" rune that ends the declaration. +// - keyword: The token corresponding to the "option" keyword. +// - name: The token corresponding to the name of the option. +// - equals: The token corresponding to the "=" rune after the name. +// - val: The token corresponding to the option value. +// - semicolon: The token corresponding to the ";" rune that ends the declaration. func NewOptionNode(keyword *KeywordNode, name *OptionNameNode, equals *RuneNode, val ValueNode, semicolon *RuneNode) *OptionNode { if keyword == nil { panic("keyword is nil") @@ -76,9 +76,9 @@ func NewOptionNode(keyword *KeywordNode, name *OptionNameNode, equals *RuneNode, // NewCompactOptionNode creates a new *OptionNode for a full compact declaration // (as used in fields, enum values, and extension ranges). All arguments must be // non-nil. -// - name: The token corresponding to the name of the option. -// - equals: The token corresponding to the "=" rune after the name. -// - val: The token corresponding to the option value. +// - name: The token corresponding to the name of the option. +// - equals: The token corresponding to the "=" rune after the name. +// - val: The token corresponding to the option value. func NewCompactOptionNode(name *OptionNameNode, equals *RuneNode, val ValueNode) *OptionNode { if name == nil { panic("name is nil") @@ -111,7 +111,7 @@ func (n *OptionNode) GetValue() ValueNode { // OptionNameNode represents an option name or even a traversal through message // types to name a nested option field. Example: // -// (foo.bar).baz.(bob) +// (foo.bar).baz.(bob) type OptionNameNode struct { compositeNode Parts []*FieldReferenceNode @@ -182,11 +182,11 @@ func NewOptionNameNode(parts []*FieldReferenceNode, dots []*RuneNode) *OptionNam // absent in an extension name. // // Examples: -// foobar -// (foo.bar) -// [foo.bar] -// [type.googleapis.com/foo.bar] // +// foobar +// (foo.bar) +// [foo.bar] +// [type.googleapis.com/foo.bar] type FieldReferenceNode struct { compositeNode Open *RuneNode // only present for extension names and "any" type references @@ -297,7 +297,7 @@ func (a *FieldReferenceNode) Value() string { // CompactOptionsNode represents a compact options declaration, as used with // fields, enum values, and extension ranges. Example: // -// [deprecated = true, json_name = "foo_bar"] +// [deprecated = true, json_name = "foo_bar"] type CompactOptionsNode struct { compositeNode OpenBracket *RuneNode diff --git a/desc/protoparse/ast/ranges.go b/desc/protoparse/ast/ranges.go index 77d3e8d8..cdd78baf 100644 --- a/desc/protoparse/ast/ranges.go +++ b/desc/protoparse/ast/ranges.go @@ -5,7 +5,7 @@ import "fmt" // ExtensionRangeNode represents an extension range declaration in an extendable // message. Example: // -// extensions 100 to max; +// extensions 100 to max; type ExtensionRangeNode struct { compositeNode Keyword *KeywordNode @@ -23,12 +23,12 @@ func (e *ExtensionRangeNode) msgElement() {} // NewExtensionRangeNode creates a new *ExtensionRangeNode. All args must be // non-nil except opts, which may be nil. -// - keyword: The token corresponding to the "extends" keyword. -// - ranges: One or more range expressions. -// - commas: Tokens that represent the "," runes that delimit the range expressions. -// The length of commas must be one less than the length of ranges. -// - opts: The node corresponding to options that apply to each of the ranges. -// - semicolon The token corresponding to the ";" rune that ends the declaration. +// - keyword: The token corresponding to the "extends" keyword. +// - ranges: One or more range expressions. +// - commas: Tokens that represent the "," runes that delimit the range expressions. +// The length of commas must be one less than the length of ranges. +// - opts: The node corresponding to options that apply to each of the ranges. +// - semicolon The token corresponding to the ";" rune that ends the declaration. func NewExtensionRangeNode(keyword *KeywordNode, ranges []*RangeNode, commas []*RuneNode, opts *CompactOptionsNode, semicolon *RuneNode) *ExtensionRangeNode { if keyword == nil { panic("keyword is nil") @@ -91,7 +91,7 @@ var _ RangeDeclNode = NoSourceNode{} // RangeNode represents a range expression, used in both extension ranges and // reserved ranges. Example: // -// 1000 to max +// 1000 to max type RangeNode struct { compositeNode StartVal IntValueNode @@ -191,8 +191,8 @@ func (n *RangeNode) EndValueAsInt32(min, max int32) (int32, bool) { // ReservedNode represents reserved declaration, which can be used to reserve // either names or numbers. Examples: // -// reserved 1, 10-12, 15; -// reserved "foo", "bar", "baz"; +// reserved 1, 10-12, 15; +// reserved "foo", "bar", "baz"; type ReservedNode struct { compositeNode Keyword *KeywordNode @@ -214,11 +214,11 @@ func (*ReservedNode) enumElement() {} // NewReservedRangesNode creates a new *ReservedNode that represents reserved // numeric ranges. All args must be non-nil. -// - keyword: The token corresponding to the "reserved" keyword. -// - ranges: One or more range expressions. -// - commas: Tokens that represent the "," runes that delimit the range expressions. -// The length of commas must be one less than the length of ranges. -// - semicolon The token corresponding to the ";" rune that ends the declaration. +// - keyword: The token corresponding to the "reserved" keyword. +// - ranges: One or more range expressions. +// - commas: Tokens that represent the "," runes that delimit the range expressions. +// The length of commas must be one less than the length of ranges. +// - semicolon The token corresponding to the ";" rune that ends the declaration. func NewReservedRangesNode(keyword *KeywordNode, ranges []*RangeNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode { if keyword == nil { panic("keyword is nil") @@ -260,11 +260,11 @@ func NewReservedRangesNode(keyword *KeywordNode, ranges []*RangeNode, commas []* // NewReservedNamesNode creates a new *ReservedNode that represents reserved // names. All args must be non-nil. -// - keyword: The token corresponding to the "reserved" keyword. -// - names: One or more names. -// - commas: Tokens that represent the "," runes that delimit the names. -// The length of commas must be one less than the length of names. -// - semicolon The token corresponding to the ";" rune that ends the declaration. +// - keyword: The token corresponding to the "reserved" keyword. +// - names: One or more names. +// - commas: Tokens that represent the "," runes that delimit the names. +// The length of commas must be one less than the length of names. +// - semicolon The token corresponding to the ";" rune that ends the declaration. func NewReservedNamesNode(keyword *KeywordNode, names []StringValueNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode { if keyword == nil { panic("keyword is nil") diff --git a/desc/protoparse/ast/service.go b/desc/protoparse/ast/service.go index d8cfe8b5..739b29cc 100644 --- a/desc/protoparse/ast/service.go +++ b/desc/protoparse/ast/service.go @@ -4,10 +4,10 @@ import "fmt" // ServiceNode represents a service declaration. Example: // -// service Foo { -// rpc Bar (Baz) returns (Bob); -// rpc Frobnitz (stream Parts) returns (Gyzmeaux); -// } +// service Foo { +// rpc Bar (Baz) returns (Bob); +// rpc Frobnitz (stream Parts) returns (Gyzmeaux); +// } type ServiceNode struct { compositeNode Keyword *KeywordNode @@ -20,11 +20,11 @@ type ServiceNode struct { func (*ServiceNode) fileElement() {} // NewServiceNode creates a new *ServiceNode. All arguments must be non-nil. -// - keyword: The token corresponding to the "service" keyword. -// - name: The token corresponding to the service's name. -// - openBrace: The token corresponding to the "{" rune that starts the body. -// - decls: All declarations inside the service body. -// - closeBrace: The token corresponding to the "}" rune that ends the body. +// - keyword: The token corresponding to the "service" keyword. +// - name: The token corresponding to the service's name. +// - openBrace: The token corresponding to the "{" rune that starts the body. +// - decls: All declarations inside the service body. +// - closeBrace: The token corresponding to the "}" rune that ends the body. func NewServiceNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []ServiceElement, closeBrace *RuneNode) *ServiceNode { if keyword == nil { panic("keyword is nil") @@ -90,7 +90,7 @@ var _ RPCDeclNode = NoSourceNode{} // RPCNode represents an RPC declaration. Example: // -// rpc Foo (Bar) returns (Baz); +// rpc Foo (Bar) returns (Baz); type RPCNode struct { compositeNode Keyword *KeywordNode @@ -107,12 +107,12 @@ type RPCNode struct { func (n *RPCNode) serviceElement() {} // NewRPCNode creates a new *RPCNode with no body. All arguments must be non-nil. -// - keyword: The token corresponding to the "rpc" keyword. -// - name: The token corresponding to the RPC's name. -// - input: The token corresponding to the RPC input message type. -// - returns: The token corresponding to the "returns" keyword that precedes the output type. -// - output: The token corresponding to the RPC output message type. -// - semicolon: The token corresponding to the ";" rune that ends the declaration. +// - keyword: The token corresponding to the "rpc" keyword. +// - name: The token corresponding to the RPC's name. +// - input: The token corresponding to the RPC input message type. +// - returns: The token corresponding to the "returns" keyword that precedes the output type. +// - output: The token corresponding to the RPC output message type. +// - semicolon: The token corresponding to the ";" rune that ends the declaration. func NewRPCNode(keyword *KeywordNode, name *IdentNode, input *RPCTypeNode, returns *KeywordNode, output *RPCTypeNode, semicolon *RuneNode) *RPCNode { if keyword == nil { panic("keyword is nil") @@ -148,14 +148,14 @@ func NewRPCNode(keyword *KeywordNode, name *IdentNode, input *RPCTypeNode, retur // NewRPCNodeWithBody creates a new *RPCNode that includes a body (and possibly // options). All arguments must be non-nil. -// - keyword: The token corresponding to the "rpc" keyword. -// - name: The token corresponding to the RPC's name. -// - input: The token corresponding to the RPC input message type. -// - returns: The token corresponding to the "returns" keyword that precedes the output type. -// - output: The token corresponding to the RPC output message type. -// - openBrace: The token corresponding to the "{" rune that starts the body. -// - decls: All declarations inside the RPC body. -// - closeBrace: The token corresponding to the "}" rune that ends the body. +// - keyword: The token corresponding to the "rpc" keyword. +// - name: The token corresponding to the RPC's name. +// - input: The token corresponding to the RPC input message type. +// - returns: The token corresponding to the "returns" keyword that precedes the output type. +// - output: The token corresponding to the RPC output message type. +// - openBrace: The token corresponding to the "{" rune that starts the body. +// - decls: All declarations inside the RPC body. +// - closeBrace: The token corresponding to the "}" rune that ends the body. func NewRPCNodeWithBody(keyword *KeywordNode, name *IdentNode, input *RPCTypeNode, returns *KeywordNode, output *RPCTypeNode, openBrace *RuneNode, decls []RPCElement, closeBrace *RuneNode) *RPCNode { if keyword == nil { panic("keyword is nil") @@ -229,7 +229,7 @@ var _ RPCElement = (*EmptyDeclNode)(nil) // RPCTypeNode represents the declaration of a request or response type for an // RPC. Example: // -// (stream foo.Bar) +// (stream foo.Bar) type RPCTypeNode struct { compositeNode OpenParen *RuneNode @@ -240,10 +240,10 @@ type RPCTypeNode struct { // NewRPCTypeNode creates a new *RPCTypeNode. All arguments must be non-nil // except stream, which may be nil. -// - openParen: The token corresponding to the "(" rune that starts the declaration. -// - stream: The token corresponding to the "stream" keyword or nil if not present. -// - msgType: The token corresponding to the message type's name. -// - closeParen: The token corresponding to the ")" rune that ends the declaration. +// - openParen: The token corresponding to the "(" rune that starts the declaration. +// - stream: The token corresponding to the "stream" keyword or nil if not present. +// - msgType: The token corresponding to the message type's name. +// - closeParen: The token corresponding to the ")" rune that ends the declaration. func NewRPCTypeNode(openParen *RuneNode, stream *KeywordNode, msgType IdentValueNode, closeParen *RuneNode) *RPCTypeNode { if openParen == nil { panic("openParen is nil") diff --git a/desc/protoparse/ast/values.go b/desc/protoparse/ast/values.go index 3855938f..c75f4481 100644 --- a/desc/protoparse/ast/values.go +++ b/desc/protoparse/ast/values.go @@ -53,7 +53,7 @@ var _ StringValueNode = (*CompoundStringLiteralNode)(nil) // StringLiteralNode represents a simple string literal. Example: // -// "proto2" +// "proto2" type StringLiteralNode struct { terminalNode // Val is the actual string value that the literal indicates. @@ -79,7 +79,7 @@ func (n *StringLiteralNode) AsString() string { // CompoundStringLiteralNode represents a compound string literal, which is // the concatenaton of adjacent string literals. Example: // -// "this " "is" " all one " "string" +// "this " "is" " all one " "string" type CompoundStringLiteralNode struct { compositeNode Val string @@ -392,7 +392,7 @@ func (n *BoolLiteralNode) Value() interface{} { // ArrayLiteralNode represents an array literal, which is only allowed inside of // a MessageLiteralNode, to indicate values for a repeated field. Example: // -// ["foo", "bar", "baz"] +// ["foo", "bar", "baz"] type ArrayLiteralNode struct { compositeNode OpenBracket *RuneNode @@ -458,7 +458,7 @@ func (n *ArrayLiteralNode) Value() interface{} { // protobuf text format and can be used for custom options with message types. // Example: // -// { foo:1 foo:2 foo:3 bar: } +// { foo:1 foo:2 foo:3 bar: } type MessageLiteralNode struct { compositeNode Open *RuneNode // should be '{' or '<' @@ -526,7 +526,7 @@ func (n *MessageLiteralNode) Value() interface{} { // MessageFieldNode represents a single field (name and value) inside of a // message literal. Example: // -// foo:"bar" +// foo:"bar" type MessageFieldNode struct { compositeNode Name *FieldReferenceNode diff --git a/desc/protoparse/linker.go b/desc/protoparse/linker.go index 55042556..d7916362 100644 --- a/desc/protoparse/linker.go +++ b/desc/protoparse/linker.go @@ -1190,7 +1190,8 @@ func canonicalEnumValueName(enumValueName, enumName string) string { // str is returned unchanged. // // The algorithm is adapted from the protoc source: -// https://github.com/protocolbuffers/protobuf/blob/v21.3/src/google/protobuf/descriptor.cc#L922 +// +// https://github.com/protocolbuffers/protobuf/blob/v21.3/src/google/protobuf/descriptor.cc#L922 func removePrefix(str, prefix string) string { j := 0 for i, r := range str { @@ -1227,7 +1228,8 @@ func removePrefix(str, prefix string) string { // enumValCamelCase converts the given string to upper-camel-case. // // The algorithm is adapted from the protoc source: -// https://github.com/protocolbuffers/protobuf/blob/v21.3/src/google/protobuf/descriptor.cc#L887 +// +// https://github.com/protocolbuffers/protobuf/blob/v21.3/src/google/protobuf/descriptor.cc#L887 func enumValCamelCase(name string) string { var js []rune nextUpper := true diff --git a/desc/protoparse/parser.go b/desc/protoparse/parser.go index 7af9866d..5ab50870 100644 --- a/desc/protoparse/parser.go +++ b/desc/protoparse/parser.go @@ -258,20 +258,20 @@ func (p Parser) ParseFiles(filenames ...string) ([]*desc.FileDescriptor, error) // steps omitted). // // There are a few side effects to not linking the descriptors: -// 1. No options will be interpreted. Options can refer to extensions or have -// message and enum types. Without linking, these extension and type -// references are not resolved, so the options may not be interpretable. -// So all options will appear in UninterpretedOption fields of the various -// descriptor options messages. -// 2. Type references will not be resolved. This means that the actual type -// names in the descriptors may be unqualified and even relative to the -// scope in which the type reference appears. This goes for fields that -// have message and enum types. It also applies to methods and their -// references to request and response message types. -// 3. Type references are not known. For non-scalar fields, until the type -// name is resolved (during linking), it is not known whether the type -// refers to a message or an enum. So all fields with such type references -// will not have their Type set, only the TypeName. +// 1. No options will be interpreted. Options can refer to extensions or have +// message and enum types. Without linking, these extension and type +// references are not resolved, so the options may not be interpretable. +// So all options will appear in UninterpretedOption fields of the various +// descriptor options messages. +// 2. Type references will not be resolved. This means that the actual type +// names in the descriptors may be unqualified and even relative to the +// scope in which the type reference appears. This goes for fields that +// have message and enum types. It also applies to methods and their +// references to request and response message types. +// 3. Type references are not known. For non-scalar fields, until the type +// name is resolved (during linking), it is not known whether the type +// refers to a message or an enum. So all fields with such type references +// will not have their Type set, only the TypeName. // // This method will still validate the syntax of parsed files. If the parser's // ValidateUnlinkedFiles field is true, additional checks, beyond syntax will diff --git a/desc/sourceinfo/registry.go b/desc/sourceinfo/registry.go index 1f7231f7..ad3bce0a 100644 --- a/desc/sourceinfo/registry.go +++ b/desc/sourceinfo/registry.go @@ -19,13 +19,12 @@ // following snippet demonstrates how to do this in your server. Do this instead of // using the reflection.Register function: // -// refSvr := reflection.NewServer(reflection.ServerOptions{ -// Services: grpcServer, -// DescriptorResolver: sourceinfo.GlobalFiles, -// ExtensionResolver: sourceinfo.GlobalFiles, -// }) -// grpc_reflection_v1alpha.RegisterServerReflectionServer(grpcServer, refSvr) -// +// refSvr := reflection.NewServer(reflection.ServerOptions{ +// Services: grpcServer, +// DescriptorResolver: sourceinfo.GlobalFiles, +// ExtensionResolver: sourceinfo.GlobalFiles, +// }) +// grpc_reflection_v1alpha.RegisterServerReflectionServer(grpcServer, refSvr) package sourceinfo import ( diff --git a/dynamic/doc.go b/dynamic/doc.go index c329fcdc..5d7f45e4 100644 --- a/dynamic/doc.go +++ b/dynamic/doc.go @@ -15,8 +15,7 @@ // will be used to create other messages or parse extension fields during // de-serialization. // -// -// Field Types +// # Field Types // // The types of values expected by setters and returned by getters are the // same as protoc generates for scalar fields. For repeated fields, there are @@ -72,8 +71,7 @@ // but if the factory is configured with a KnownTypeRegistry, or if the field's // type is a well-known type, it will return a zero value generated message. // -// -// Unrecognized Fields +// # Unrecognized Fields // // Unrecognized fields are preserved by the dynamic message when unmarshaling // from the standard binary format. If the message's MessageFactory was @@ -89,21 +87,20 @@ // it can even happen for non-extension fields! Here's an example scenario where // a non-extension field can initially be unknown and become known: // -// 1. A dynamic message is created with a descriptor, A, and then -// de-serialized from a stream of bytes. The stream includes an -// unrecognized tag T. The message will include tag T in its unrecognized -// field set. -// 2. Another call site retrieves a newer descriptor, A', which includes a -// newly added field with tag T. -// 3. That other call site then uses a FieldDescriptor to access the value of -// the new field. This will cause the dynamic message to parse the bytes -// for the unknown tag T and store them as a known field. -// 4. Subsequent operations for tag T, including setting the field using only -// tag number or de-serializing a stream that includes tag T, will operate -// as if that tag were part of the original descriptor, A. -// -// -// Compatibility +// 1. A dynamic message is created with a descriptor, A, and then +// de-serialized from a stream of bytes. The stream includes an +// unrecognized tag T. The message will include tag T in its unrecognized +// field set. +// 2. Another call site retrieves a newer descriptor, A', which includes a +// newly added field with tag T. +// 3. That other call site then uses a FieldDescriptor to access the value of +// the new field. This will cause the dynamic message to parse the bytes +// for the unknown tag T and store them as a known field. +// 4. Subsequent operations for tag T, including setting the field using only +// tag number or de-serializing a stream that includes tag T, will operate +// as if that tag were part of the original descriptor, A. +// +// # Compatibility // // In addition to implementing the proto.Message interface, the included // Message type also provides an XXX_MessageName() method, so it can work with @@ -145,8 +142,7 @@ // about fields that the dynamic message does not, these unrecognized fields may // become known fields in the generated message. // -// -// Registries +// # Registries // // This package also contains a couple of registries, for managing known types // and descriptors. diff --git a/dynamic/json.go b/dynamic/json.go index 02c8298b..2efd5849 100644 --- a/dynamic/json.go +++ b/dynamic/json.go @@ -60,7 +60,7 @@ var wellKnownTypeNames = map[string]struct{}{ // This method is convenient shorthand for invoking MarshalJSONPB with a default // (zero value) marshaler: // -// m.MarshalJSONPB(&jsonpb.Marshaler{}) +// m.MarshalJSONPB(&jsonpb.Marshaler{}) // // So enums are serialized using enum value name strings, and values that are // not present (including those with default/zero value for messages defined in @@ -80,7 +80,7 @@ func (m *Message) MarshalJSON() ([]byte, error) { // This method is convenient shorthand for invoking MarshalJSONPB with a default // (zero value) marshaler: // -// m.MarshalJSONPB(&jsonpb.Marshaler{Indent: " "}) +// m.MarshalJSONPB(&jsonpb.Marshaler{Indent: " "}) // // So enums are serialized using enum value name strings, and values that are // not present (including those with default/zero value for messages defined in @@ -497,7 +497,7 @@ func writeJsonString(b *indentBuffer, s string) error { // This method is shorthand for invoking UnmarshalJSONPB with a default (zero // value) unmarshaler: // -// m.UnmarshalMergeJSONPB(&jsonpb.Unmarshaler{}, js) +// m.UnmarshalMergeJSONPB(&jsonpb.Unmarshaler{}, js) // // So unknown fields will result in an error, and no provided jsonpb.AnyResolver // will be used when parsing google.protobuf.Any messages. diff --git a/dynamic/message_factory.go b/dynamic/message_factory.go index 2b551910..683e7b33 100644 --- a/dynamic/message_factory.go +++ b/dynamic/message_factory.go @@ -37,9 +37,10 @@ func NewMessageFactoryWithKnownTypeRegistry(ktr *KnownTypeRegistry) *MessageFact // (those for which protoc-generated code is statically linked into the Go program) are // known types. If any dynamic messages are produced, they will recognize and parse all // "default" extension fields. This is the equivalent of: -// NewMessageFactoryWithRegistries( -// NewExtensionRegistryWithDefaults(), -// NewKnownTypeRegistryWithDefaults()) +// +// NewMessageFactoryWithRegistries( +// NewExtensionRegistryWithDefaults(), +// NewKnownTypeRegistryWithDefaults()) func NewMessageFactoryWithDefaults() *MessageFactory { return NewMessageFactoryWithRegistries(NewExtensionRegistryWithDefaults(), NewKnownTypeRegistryWithDefaults()) }