// Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // This file contains functions for fetching the options for a protoreflect descriptor. // // TODO: Replace this with the appropriate protoreflect API, once it exists. package internal_gengo import ( "github.com/golang/protobuf/proto" descpb "github.com/golang/protobuf/protoc-gen-go/descriptor" "github.com/golang/protobuf/v2/protogen" "github.com/golang/protobuf/v2/reflect/protoreflect" ) // messageOptions returns the MessageOptions for a message. func messageOptions(gen *protogen.Plugin, message *protogen.Message) *descpb.MessageOptions { d := getDescriptorProto(gen, message.Desc, message.Path) if d == nil { return nil } return d.(*descpb.DescriptorProto).GetOptions() } // fieldOptions returns the FieldOptions for a message. func fieldOptions(gen *protogen.Plugin, field *protogen.Field) *descpb.FieldOptions { d := getDescriptorProto(gen, field.Desc, field.Path) if d == nil { return nil } return d.(*descpb.FieldDescriptorProto).GetOptions() } // enumOptions returns the EnumOptions for an enum func enumOptions(gen *protogen.Plugin, enum *protogen.Enum) *descpb.EnumOptions { d := getDescriptorProto(gen, enum.Desc, enum.Path) if d == nil { return nil } return d.(*descpb.EnumDescriptorProto).GetOptions() } // enumValueOptions returns the EnumValueOptions for an enum value func enumValueOptions(gen *protogen.Plugin, value *protogen.EnumValue) *descpb.EnumValueOptions { d := getDescriptorProto(gen, value.Desc, value.Path) if d == nil { return nil } return d.(*descpb.EnumValueDescriptorProto).GetOptions() } func getDescriptorProto(gen *protogen.Plugin, desc protoreflect.Descriptor, path []int32) proto.Message { var p proto.Message // Look up the FileDescriptorProto. for { if fdesc, ok := desc.(protoreflect.FileDescriptor); ok { file, ok := gen.FileByName(fdesc.Path()) if !ok { return nil } p = file.Proto break } var ok bool desc, ok = desc.Parent() if !ok { return nil } } const ( // field numbers in FileDescriptorProto filePackageField = 2 // package fileMessageField = 4 // message_type fileEnumField = 5 // enum_type fileExtensionField = 7 // extension // field numbers in DescriptorProto messageFieldField = 2 // field messageMessageField = 3 // nested_type messageEnumField = 4 // enum_type messageExtensionField = 6 // extension messageOneofField = 8 // oneof_decl // field numbers in EnumDescriptorProto enumValueField = 2 // value ) for len(path) > 1 { switch d := p.(type) { case *descpb.FileDescriptorProto: switch path[0] { case fileMessageField: p = d.MessageType[path[1]] case fileEnumField: p = d.EnumType[path[1]] default: return nil } case *descpb.DescriptorProto: switch path[0] { case messageFieldField: p = d.Field[path[1]] case messageMessageField: p = d.NestedType[path[1]] case messageEnumField: p = d.EnumType[path[1]] default: return nil } case *descpb.EnumDescriptorProto: switch path[0] { case enumValueField: p = d.Value[path[1]] default: return nil } default: return nil } path = path[2:] } return p }