mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-04-17 02:42:35 +00:00
cmd/protoc-gen-go: add support for field-tracking
Field-tracking is an experimental feature in the Go linker where it statically tracks whether a Go struct field is used. This CL modifies the generator to emit special markers that tells the linker to know which fields to track. Change-Id: I235da3f3d6c0ef2021b5fe1c16106ebb8fd6f557 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189558 Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
parent
2e7817f117
commit
26aef9d6d6
@ -1,35 +0,0 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
package internal_gengo
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"google.golang.org/protobuf/compiler/protogen"
|
||||
)
|
||||
|
||||
// messageAPIFlags provides flags that control the generated API.
|
||||
type messageAPIFlags struct {
|
||||
WeakMapField bool
|
||||
}
|
||||
|
||||
var messageAPIFlagsCache sync.Map
|
||||
|
||||
func loadMessageAPIFlags(message *protogen.Message) messageAPIFlags {
|
||||
if flags, ok := messageAPIFlagsCache.Load(message); ok {
|
||||
return flags.(messageAPIFlags)
|
||||
}
|
||||
|
||||
var flags messageAPIFlags
|
||||
for _, field := range message.Fields {
|
||||
if field.Desc.IsWeak() {
|
||||
flags.WeakMapField = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
messageAPIFlagsCache.Store(message, flags)
|
||||
return flags
|
||||
}
|
51
cmd/protoc-gen-go/internal_gengo/flags.go
Normal file
51
cmd/protoc-gen-go/internal_gengo/flags.go
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
package internal_gengo
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/compiler/protogen"
|
||||
"google.golang.org/protobuf/internal/encoding/wire"
|
||||
|
||||
"google.golang.org/protobuf/types/descriptorpb"
|
||||
)
|
||||
|
||||
// messageFlags provides flags that control the generated API.
|
||||
type messageFlags struct {
|
||||
IsTracked bool
|
||||
HasWeak bool
|
||||
}
|
||||
|
||||
func loadMessageFlags(message *protogen.Message) messageFlags {
|
||||
var flags messageFlags
|
||||
flags.IsTracked = isTrackedMessage(message)
|
||||
for _, field := range message.Fields {
|
||||
if field.Desc.IsWeak() {
|
||||
flags.HasWeak = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
// isTrackedMessage reports whether field tracking is enabled on the message.
|
||||
// It is a variable so that the behavior is easily overridden in another file.
|
||||
var isTrackedMessage = func(message *protogen.Message) (tracked bool) {
|
||||
const trackFieldUse_fieldNumber = 37383685
|
||||
|
||||
// Decode the option from unknown fields to avoid a dependency on the
|
||||
// annotation proto from protoc-gen-go.
|
||||
b := message.Desc.Options().(*descriptorpb.MessageOptions).ProtoReflect().GetUnknown()
|
||||
for len(b) > 0 {
|
||||
num, typ, n := wire.ConsumeTag(b)
|
||||
b = b[n:]
|
||||
if num == trackFieldUse_fieldNumber && typ == wire.VarintType {
|
||||
v, _ := wire.ConsumeVarint(b)
|
||||
tracked = wire.DecodeBool(v)
|
||||
}
|
||||
m := wire.ConsumeFieldValue(num, typ, b)
|
||||
b = b[m:]
|
||||
}
|
||||
return tracked
|
||||
}
|
@ -402,35 +402,42 @@ func genEnum(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, enum
|
||||
}
|
||||
}
|
||||
|
||||
type messageInfo struct {
|
||||
*protogen.Message
|
||||
messageFlags
|
||||
}
|
||||
|
||||
func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message) {
|
||||
if message.Desc.IsMapEntry() {
|
||||
return
|
||||
}
|
||||
|
||||
m := &messageInfo{message, loadMessageFlags(message)}
|
||||
|
||||
// Message type declaration.
|
||||
g.Annotate(message.GoIdent.GoName, message.Location)
|
||||
leadingComments := appendDeprecationSuffix(message.Comments.Leading,
|
||||
message.Desc.Options().(*descriptorpb.MessageOptions).GetDeprecated())
|
||||
g.Annotate(m.GoIdent.GoName, m.Location)
|
||||
leadingComments := appendDeprecationSuffix(m.Comments.Leading,
|
||||
m.Desc.Options().(*descriptorpb.MessageOptions).GetDeprecated())
|
||||
g.P(leadingComments,
|
||||
"type ", message.GoIdent, " struct {")
|
||||
genMessageFields(g, f, message)
|
||||
"type ", m.GoIdent, " struct {")
|
||||
genMessageFields(g, f, m)
|
||||
g.P("}")
|
||||
g.P()
|
||||
|
||||
genDefaultDecls(g, f, message)
|
||||
genMessageMethods(gen, g, f, message)
|
||||
genOneofWrapperTypes(gen, g, f, message)
|
||||
genMessageDefaultDecls(g, f, m)
|
||||
genMessageMethods(gen, g, f, m)
|
||||
genMessageOneofWrapperTypes(gen, g, f, m)
|
||||
}
|
||||
|
||||
func genMessageFields(g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message) {
|
||||
sf := f.allMessageFieldsByPtr[message]
|
||||
genMessageInternalFields(g, message, sf)
|
||||
for _, field := range message.Fields {
|
||||
genMessageField(g, f, message, field, sf)
|
||||
func genMessageFields(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
|
||||
sf := f.allMessageFieldsByPtr[m.Message]
|
||||
genMessageInternalFields(g, f, m, sf)
|
||||
for _, field := range m.Fields {
|
||||
genMessageField(g, f, m, field, sf)
|
||||
}
|
||||
}
|
||||
|
||||
func genMessageInternalFields(g *protogen.GeneratedFile, message *protogen.Message, sf *structFields) {
|
||||
func genMessageInternalFields(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, sf *structFields) {
|
||||
if generateMessageStateFields {
|
||||
g.P("state ", protoimplPackage.Ident("MessageState"))
|
||||
sf.append("state")
|
||||
@ -442,7 +449,7 @@ func genMessageInternalFields(g *protogen.GeneratedFile, message *protogen.Messa
|
||||
g.P("sizeCache", " ", protoimplPackage.Ident("SizeCache"))
|
||||
sf.append("sizeCache")
|
||||
}
|
||||
if loadMessageAPIFlags(message).WeakMapField {
|
||||
if m.HasWeak {
|
||||
g.P("XXX_weak", " ", protoimplPackage.Ident("WeakFields"), jsonIgnoreTags)
|
||||
sf.append("XXX_weak")
|
||||
}
|
||||
@ -453,7 +460,7 @@ func genMessageInternalFields(g *protogen.GeneratedFile, message *protogen.Messa
|
||||
g.P("unknownFields", " ", protoimplPackage.Ident("UnknownFields"))
|
||||
sf.append("unknownFields")
|
||||
}
|
||||
if message.Desc.ExtensionRanges().Len() > 0 {
|
||||
if m.Desc.ExtensionRanges().Len() > 0 {
|
||||
if generateExportedExtensionFields {
|
||||
g.P("XXX_InternalExtensions", " ", protoimplPackage.Ident("ExtensionFields"), jsonIgnoreTags)
|
||||
sf.append("XXX_InternalExtensions")
|
||||
@ -467,7 +474,7 @@ func genMessageInternalFields(g *protogen.GeneratedFile, message *protogen.Messa
|
||||
}
|
||||
}
|
||||
|
||||
func genMessageField(g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message, field *protogen.Field, sf *structFields) {
|
||||
func genMessageField(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, field *protogen.Field, sf *structFields) {
|
||||
if oneof := field.Oneof; oneof != nil {
|
||||
// It would be a bit simpler to iterate over the oneofs below,
|
||||
// but generating the field here keeps the contents of the Go
|
||||
@ -480,8 +487,11 @@ func genMessageField(g *protogen.GeneratedFile, f *fileInfo, message *protogen.M
|
||||
tags := structTags{
|
||||
{"protobuf_oneof", string(oneof.Desc.Name())},
|
||||
}
|
||||
if m.IsTracked {
|
||||
tags = append(tags, gotrackTags...)
|
||||
}
|
||||
|
||||
g.Annotate(message.GoIdent.GoName+"."+oneof.GoName, oneof.Location)
|
||||
g.Annotate(m.GoIdent.GoName+"."+oneof.GoName, oneof.Location)
|
||||
leadingComments := oneof.Comments.Leading
|
||||
if leadingComments != "" {
|
||||
leadingComments += "\n"
|
||||
@ -512,12 +522,15 @@ func genMessageField(g *protogen.GeneratedFile, f *fileInfo, message *protogen.M
|
||||
{"protobuf_val", fieldProtobufTagValue(val)},
|
||||
}...)
|
||||
}
|
||||
if m.IsTracked {
|
||||
tags = append(tags, gotrackTags...)
|
||||
}
|
||||
|
||||
name := field.GoName
|
||||
if field.Desc.IsWeak() {
|
||||
name = "XXX_weak_" + name
|
||||
}
|
||||
g.Annotate(message.GoIdent.GoName+"."+name, field.Location)
|
||||
g.Annotate(m.GoIdent.GoName+"."+name, field.Location)
|
||||
leadingComments := appendDeprecationSuffix(field.Comments.Leading,
|
||||
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
|
||||
g.P(leadingComments,
|
||||
@ -526,15 +539,15 @@ func genMessageField(g *protogen.GeneratedFile, f *fileInfo, message *protogen.M
|
||||
sf.append(field.GoName)
|
||||
}
|
||||
|
||||
// genDefaultDecls generates consts and vars holding the default
|
||||
// genMessageDefaultDecls generates consts and vars holding the default
|
||||
// values of fields.
|
||||
func genDefaultDecls(g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message) {
|
||||
func genMessageDefaultDecls(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
|
||||
var consts, vars []string
|
||||
for _, field := range message.Fields {
|
||||
for _, field := range m.Fields {
|
||||
if !field.Desc.HasDefault() {
|
||||
continue
|
||||
}
|
||||
name := "Default_" + message.GoIdent.GoName + "_" + field.GoName
|
||||
name := "Default_" + m.GoIdent.GoName + "_" + field.GoName
|
||||
goType, _ := fieldGoType(g, f, field)
|
||||
defVal := field.Desc.Default()
|
||||
switch field.Desc.Kind() {
|
||||
@ -566,7 +579,7 @@ func genDefaultDecls(g *protogen.GeneratedFile, f *fileInfo, message *protogen.M
|
||||
}
|
||||
}
|
||||
if len(consts) > 0 {
|
||||
g.P("// Default values for ", message.GoIdent, " fields.")
|
||||
g.P("// Default values for ", m.GoIdent, " fields.")
|
||||
g.P("const (")
|
||||
for _, s := range consts {
|
||||
g.P(s)
|
||||
@ -574,7 +587,7 @@ func genDefaultDecls(g *protogen.GeneratedFile, f *fileInfo, message *protogen.M
|
||||
g.P(")")
|
||||
}
|
||||
if len(vars) > 0 {
|
||||
g.P("// Default values for ", message.GoIdent, " fields.")
|
||||
g.P("// Default values for ", m.GoIdent, " fields.")
|
||||
g.P("var (")
|
||||
for _, s := range vars {
|
||||
g.P(s)
|
||||
@ -584,40 +597,40 @@ func genDefaultDecls(g *protogen.GeneratedFile, f *fileInfo, message *protogen.M
|
||||
g.P()
|
||||
}
|
||||
|
||||
func genMessageMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message) {
|
||||
genMessageBaseMethods(gen, g, f, message)
|
||||
genMessageGetterMethods(gen, g, f, message)
|
||||
genMessageSetterMethods(gen, g, f, message)
|
||||
func genMessageMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
|
||||
genMessageBaseMethods(gen, g, f, m)
|
||||
genMessageGetterMethods(gen, g, f, m)
|
||||
genMessageSetterMethods(gen, g, f, m)
|
||||
}
|
||||
|
||||
func genMessageBaseMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message) {
|
||||
func genMessageBaseMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
|
||||
// Reset method.
|
||||
g.P("func (x *", message.GoIdent, ") Reset() {")
|
||||
g.P("*x = ", message.GoIdent, "{}")
|
||||
g.P("func (x *", m.GoIdent, ") Reset() {")
|
||||
g.P("*x = ", m.GoIdent, "{}")
|
||||
g.P("}")
|
||||
g.P()
|
||||
|
||||
// String method.
|
||||
g.P("func (x *", message.GoIdent, ") String() string {")
|
||||
g.P("func (x *", m.GoIdent, ") String() string {")
|
||||
g.P("return ", protoimplPackage.Ident("X"), ".MessageStringOf(x)")
|
||||
g.P("}")
|
||||
g.P()
|
||||
|
||||
// ProtoMessage method.
|
||||
g.P("func (*", message.GoIdent, ") ProtoMessage() {}")
|
||||
g.P("func (*", m.GoIdent, ") ProtoMessage() {}")
|
||||
g.P()
|
||||
|
||||
// ProtoReflect method.
|
||||
genMessageReflectMethods(gen, g, f, message)
|
||||
genMessageReflectMethods(gen, g, f, m)
|
||||
|
||||
// Descriptor method.
|
||||
if generateRawDescMethods {
|
||||
var indexes []string
|
||||
for i := 1; i < len(message.Location.Path); i += 2 {
|
||||
indexes = append(indexes, strconv.Itoa(int(message.Location.Path[i])))
|
||||
for i := 1; i < len(m.Location.Path); i += 2 {
|
||||
indexes = append(indexes, strconv.Itoa(int(m.Location.Path[i])))
|
||||
}
|
||||
g.P("// Deprecated: Use ", message.GoIdent, ".ProtoReflect.Descriptor instead.")
|
||||
g.P("func (*", message.GoIdent, ") Descriptor() ([]byte, []int) {")
|
||||
g.P("// Deprecated: Use ", m.GoIdent, ".ProtoReflect.Descriptor instead.")
|
||||
g.P("func (*", m.GoIdent, ") Descriptor() ([]byte, []int) {")
|
||||
g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}")
|
||||
g.P("}")
|
||||
g.P()
|
||||
@ -625,9 +638,9 @@ func genMessageBaseMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *f
|
||||
|
||||
// ExtensionRangeArray method.
|
||||
if generateExtensionRangeMethods {
|
||||
if extranges := message.Desc.ExtensionRanges(); extranges.Len() > 0 {
|
||||
if extranges := m.Desc.ExtensionRanges(); extranges.Len() > 0 {
|
||||
protoExtRange := protoifacePackage.Ident("ExtensionRangeV1")
|
||||
extRangeVar := "extRange_" + message.GoIdent.GoName
|
||||
extRangeVar := "extRange_" + m.GoIdent.GoName
|
||||
g.P("var ", extRangeVar, " = []", protoExtRange, " {")
|
||||
for i := 0; i < extranges.Len(); i++ {
|
||||
r := extranges.Get(i)
|
||||
@ -635,8 +648,8 @@ func genMessageBaseMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *f
|
||||
}
|
||||
g.P("}")
|
||||
g.P()
|
||||
g.P("// Deprecated: Use ", message.GoIdent, ".ProtoReflect.Descriptor.ExtensionRanges instead.")
|
||||
g.P("func (*", message.GoIdent, ") ExtensionRangeArray() []", protoExtRange, " {")
|
||||
g.P("// Deprecated: Use ", m.GoIdent, ".ProtoReflect.Descriptor.ExtensionRanges instead.")
|
||||
g.P("func (*", m.GoIdent, ") ExtensionRangeArray() []", protoExtRange, " {")
|
||||
g.P("return ", extRangeVar)
|
||||
g.P("}")
|
||||
g.P()
|
||||
@ -644,12 +657,14 @@ func genMessageBaseMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *f
|
||||
}
|
||||
}
|
||||
|
||||
func genMessageGetterMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message) {
|
||||
for _, field := range message.Fields {
|
||||
func genMessageGetterMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
|
||||
for _, field := range m.Fields {
|
||||
genNoInterfacePragma(g, m.IsTracked)
|
||||
|
||||
// Getter for parent oneof.
|
||||
if oneof := field.Oneof; oneof != nil && oneof.Fields[0] == field {
|
||||
g.Annotate(message.GoIdent.GoName+".Get"+oneof.GoName, oneof.Location)
|
||||
g.P("func (m *", message.GoIdent.GoName, ") Get", oneof.GoName, "() ", oneofInterfaceName(oneof), " {")
|
||||
g.Annotate(m.GoIdent.GoName+".Get"+oneof.GoName, oneof.Location)
|
||||
g.P("func (m *", m.GoIdent.GoName, ") Get", oneof.GoName, "() ", oneofInterfaceName(oneof), " {")
|
||||
g.P("if m != nil {")
|
||||
g.P("return m.", oneof.GoName)
|
||||
g.P("}")
|
||||
@ -660,16 +675,16 @@ func genMessageGetterMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f
|
||||
|
||||
// Getter for message field.
|
||||
goType, pointer := fieldGoType(g, f, field)
|
||||
defaultValue := fieldDefaultValue(g, message, field)
|
||||
g.Annotate(message.GoIdent.GoName+".Get"+field.GoName, field.Location)
|
||||
defaultValue := fieldDefaultValue(g, m, field)
|
||||
g.Annotate(m.GoIdent.GoName+".Get"+field.GoName, field.Location)
|
||||
leadingComments := appendDeprecationSuffix("",
|
||||
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
|
||||
switch {
|
||||
case field.Desc.IsWeak():
|
||||
g.P(leadingComments, "func (x *", message.GoIdent, ") Get", field.GoName, "() ", protoifacePackage.Ident("MessageV1"), "{")
|
||||
g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", protoifacePackage.Ident("MessageV1"), "{")
|
||||
g.P("if x != nil {")
|
||||
g.P("v := x.XXX_weak[", field.Desc.Number(), "]")
|
||||
g.P("_ = x.XXX_weak_" + field.GoName) // for field tracking
|
||||
g.P("_ = x.XXX_weak_" + field.GoName) // for field-tracking
|
||||
g.P("if v != nil {")
|
||||
g.P("return v")
|
||||
g.P("}")
|
||||
@ -677,14 +692,14 @@ func genMessageGetterMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f
|
||||
g.P("return ", protoimplPackage.Ident("X"), ".WeakNil(", strconv.Quote(string(field.Message.Desc.FullName())), ")")
|
||||
g.P("}")
|
||||
case field.Oneof != nil:
|
||||
g.P(leadingComments, "func (x *", message.GoIdent, ") Get", field.GoName, "() ", goType, " {")
|
||||
g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", goType, " {")
|
||||
g.P("if x, ok := x.Get", field.Oneof.GoName, "().(*", field.GoIdent, "); ok {")
|
||||
g.P("return x.", field.GoName)
|
||||
g.P("}")
|
||||
g.P("return ", defaultValue)
|
||||
g.P("}")
|
||||
default:
|
||||
g.P(leadingComments, "func (x *", message.GoIdent, ") Get", field.GoName, "() ", goType, " {")
|
||||
g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", goType, " {")
|
||||
if field.Desc.Syntax() == protoreflect.Proto3 || defaultValue == "nil" {
|
||||
g.P("if x != nil {")
|
||||
} else {
|
||||
@ -703,25 +718,29 @@ func genMessageGetterMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f
|
||||
}
|
||||
}
|
||||
|
||||
func genMessageSetterMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message) {
|
||||
for _, field := range message.Fields {
|
||||
if field.Desc.IsWeak() {
|
||||
g.Annotate(message.GoIdent.GoName+".Set"+field.GoName, field.Location)
|
||||
leadingComments := appendDeprecationSuffix("",
|
||||
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
|
||||
g.P(leadingComments, "func (x *", message.GoIdent, ") Set", field.GoName, "(v ", protoifacePackage.Ident("MessageV1"), ") {")
|
||||
g.P("if x.XXX_weak == nil {")
|
||||
g.P("x.XXX_weak = make(", protoimplPackage.Ident("WeakFields"), ")")
|
||||
g.P("}")
|
||||
g.P("if v == nil {")
|
||||
g.P("delete(x.XXX_weak, ", field.Desc.Number(), ")")
|
||||
g.P("} else {")
|
||||
g.P("x.XXX_weak[", field.Desc.Number(), "] = v")
|
||||
g.P("x.XXX_weak_"+field.GoName, " = struct{}{}") // for field tracking
|
||||
g.P("}")
|
||||
g.P("}")
|
||||
g.P()
|
||||
func genMessageSetterMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
|
||||
for _, field := range m.Fields {
|
||||
if !field.Desc.IsWeak() {
|
||||
continue
|
||||
}
|
||||
|
||||
genNoInterfacePragma(g, m.IsTracked)
|
||||
|
||||
g.Annotate(m.GoIdent.GoName+".Set"+field.GoName, field.Location)
|
||||
leadingComments := appendDeprecationSuffix("",
|
||||
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
|
||||
g.P(leadingComments, "func (x *", m.GoIdent, ") Set", field.GoName, "(v ", protoifacePackage.Ident("MessageV1"), ") {")
|
||||
g.P("if x.XXX_weak == nil {")
|
||||
g.P("x.XXX_weak = make(", protoimplPackage.Ident("WeakFields"), ")")
|
||||
g.P("}")
|
||||
g.P("if v == nil {")
|
||||
g.P("delete(x.XXX_weak, ", field.Desc.Number(), ")")
|
||||
g.P("} else {")
|
||||
g.P("x.XXX_weak[", field.Desc.Number(), "] = v")
|
||||
g.P("x.XXX_weak_"+field.GoName, " = struct{}{}") // for field-tracking
|
||||
g.P("}")
|
||||
g.P("}")
|
||||
g.P()
|
||||
}
|
||||
}
|
||||
|
||||
@ -785,12 +804,12 @@ func fieldProtobufTagValue(field *protogen.Field) string {
|
||||
return tag.Marshal(field.Desc, enumName)
|
||||
}
|
||||
|
||||
func fieldDefaultValue(g *protogen.GeneratedFile, message *protogen.Message, field *protogen.Field) string {
|
||||
func fieldDefaultValue(g *protogen.GeneratedFile, m *messageInfo, field *protogen.Field) string {
|
||||
if field.Desc.IsList() {
|
||||
return "nil"
|
||||
}
|
||||
if field.Desc.HasDefault() {
|
||||
defVarName := "Default_" + message.GoIdent.GoName + "_" + field.GoName
|
||||
defVarName := "Default_" + m.GoIdent.GoName + "_" + field.GoName
|
||||
if field.Desc.Kind() == protoreflect.BytesKind {
|
||||
return "append([]byte(nil), " + defVarName + "...)"
|
||||
}
|
||||
@ -886,10 +905,10 @@ func genExtensions(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
// genOneofWrapperTypes generates the oneof wrapper types and
|
||||
// genMessageOneofWrapperTypes generates the oneof wrapper types and
|
||||
// associates the types with the parent message type.
|
||||
func genOneofWrapperTypes(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message) {
|
||||
for _, oneof := range message.Oneofs {
|
||||
func genMessageOneofWrapperTypes(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
|
||||
for _, oneof := range m.Oneofs {
|
||||
ifName := oneofInterfaceName(oneof)
|
||||
g.P("type ", ifName, " interface {")
|
||||
g.P(ifName, "()")
|
||||
@ -903,6 +922,9 @@ func genOneofWrapperTypes(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fi
|
||||
tags := structTags{
|
||||
{"protobuf", fieldProtobufTagValue(field)},
|
||||
}
|
||||
if m.IsTracked {
|
||||
tags = append(tags, gotrackTags...)
|
||||
}
|
||||
leadingComments := appendDeprecationSuffix(field.Comments.Leading,
|
||||
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
|
||||
g.P(leadingComments,
|
||||
@ -924,12 +946,24 @@ func oneofInterfaceName(oneof *protogen.Oneof) string {
|
||||
return "is" + oneof.GoIdent.GoName
|
||||
}
|
||||
|
||||
var jsonIgnoreTags = structTags{{"json", "-"}}
|
||||
// genNoInterfacePragma generates a standalone "nointerface" pragma to
|
||||
// decorate methods with field-tracking support.
|
||||
func genNoInterfacePragma(g *protogen.GeneratedFile, tracked bool) {
|
||||
if tracked {
|
||||
g.P("//go:nointerface")
|
||||
g.P()
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
gotrackTags = structTags{{"go", "track"}}
|
||||
jsonIgnoreTags = structTags{{"json", "-"}}
|
||||
)
|
||||
|
||||
// structTags is a data structure for build idiomatic Go struct tags.
|
||||
// Each [2]string is a key-value pair, where value is the unescaped string.
|
||||
//
|
||||
// Example: structTags{{"key", "value"}} -> `key:"value"`
|
||||
// Example: structTags{{"key", "value"}}.String() -> `key:"value"`
|
||||
type structTags [][2]string
|
||||
|
||||
func (tags structTags) String() string {
|
||||
|
@ -302,12 +302,12 @@ func genEnumReflectMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *f
|
||||
g.P()
|
||||
}
|
||||
|
||||
func genMessageReflectMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message) {
|
||||
idx := f.allMessagesByPtr[message]
|
||||
func genMessageReflectMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
|
||||
idx := f.allMessagesByPtr[m.Message]
|
||||
typesVar := messageTypesVarName(f)
|
||||
|
||||
// ProtoReflect method.
|
||||
g.P("func (x *", message.GoIdent, ") ProtoReflect() ", protoreflectPackage.Ident("Message"), " {")
|
||||
g.P("func (x *", m.GoIdent, ") ProtoReflect() ", protoreflectPackage.Ident("Message"), " {")
|
||||
g.P("mi := &", typesVar, "[", idx, "]")
|
||||
if generateMessageStateFields {
|
||||
g.P("if ", protoimplPackage.Ident("UnsafeEnabled"), " && x != nil {")
|
||||
|
106
internal/testprotos/annotation/annotation.pb.go
Normal file
106
internal/testprotos/annotation/annotation.pb.go
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: annotation/annotation.proto
|
||||
|
||||
package annotation
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
descriptorpb "google.golang.org/protobuf/types/descriptorpb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
var file_annotation_annotation_proto_extTypes = []protoimpl.ExtensionInfo{
|
||||
{
|
||||
ExtendedType: (*descriptorpb.MessageOptions)(nil),
|
||||
ExtensionType: (*bool)(nil),
|
||||
Field: 37383685,
|
||||
Name: "go_annotation.track_field_use",
|
||||
Tag: "varint,37383685,opt,name=track_field_use",
|
||||
Filename: "annotation/annotation.proto",
|
||||
},
|
||||
}
|
||||
|
||||
// Extension fields to descriptorpb.MessageOptions.
|
||||
var (
|
||||
// Setting this on a message enables tracking of which fields in the message
|
||||
// a specific binary might access. As a consequence, it also disables the use
|
||||
// of the message accessor methods to satisfy interfaces: they can only be
|
||||
// called directly.
|
||||
//
|
||||
// optional bool track_field_use = 37383685;
|
||||
E_TrackFieldUse = &file_annotation_annotation_proto_extTypes[0]
|
||||
)
|
||||
|
||||
var File_annotation_annotation_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_annotation_annotation_proto_rawDesc = []byte{
|
||||
0x0a, 0x1b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x61, 0x6e, 0x6e,
|
||||
0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x67,
|
||||
0x6f, 0x5f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x20, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65,
|
||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x4a,
|
||||
0x0a, 0x0f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x75, 0x73,
|
||||
0x65, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x18, 0x85, 0xdc, 0xe9, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x74, 0x72, 0x61,
|
||||
0x63, 0x6b, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x55, 0x73, 0x65, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x61, 0x6e, 0x6e,
|
||||
0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
}
|
||||
|
||||
var (
|
||||
file_annotation_annotation_proto_rawDescOnce sync.Once
|
||||
file_annotation_annotation_proto_rawDescData = file_annotation_annotation_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_annotation_annotation_proto_rawDescGZIP() []byte {
|
||||
file_annotation_annotation_proto_rawDescOnce.Do(func() {
|
||||
file_annotation_annotation_proto_rawDescData = protoimpl.X.CompressGZIP(file_annotation_annotation_proto_rawDescData)
|
||||
})
|
||||
return file_annotation_annotation_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_annotation_annotation_proto_goTypes = []interface{}{
|
||||
(*descriptorpb.MessageOptions)(nil), // 0: google.protobuf.MessageOptions
|
||||
}
|
||||
var file_annotation_annotation_proto_depIdxs = []int32{
|
||||
0, // 0: go_annotation.track_field_use:extendee -> google.protobuf.MessageOptions
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
0, // [0:1] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_annotation_annotation_proto_init() }
|
||||
func file_annotation_annotation_proto_init() {
|
||||
if File_annotation_annotation_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_annotation_annotation_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 0,
|
||||
NumExtensions: 1,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_annotation_annotation_proto_goTypes,
|
||||
DependencyIndexes: file_annotation_annotation_proto_depIdxs,
|
||||
ExtensionInfos: file_annotation_annotation_proto_extTypes,
|
||||
}.Build()
|
||||
File_annotation_annotation_proto = out.File
|
||||
file_annotation_annotation_proto_rawDesc = nil
|
||||
file_annotation_annotation_proto_goTypes = nil
|
||||
file_annotation_annotation_proto_depIdxs = nil
|
||||
}
|
19
internal/testprotos/annotation/annotation.proto
Normal file
19
internal/testprotos/annotation/annotation.proto
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package go_annotation;
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
option go_package = "google.golang.org/protobuf/internal/testprotos/annotation";
|
||||
|
||||
extend google.protobuf.MessageOptions {
|
||||
// Setting this on a message enables tracking of which fields in the message
|
||||
// a specific binary might access. As a consequence, it also disables the use
|
||||
// of the message accessor methods to satisfy interfaces: they can only be
|
||||
// called directly.
|
||||
optional bool track_field_use = 37383685;
|
||||
}
|
1039
internal/testprotos/fieldtrack/fieldtrack.pb.go
Normal file
1039
internal/testprotos/fieldtrack/fieldtrack.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
75
internal/testprotos/fieldtrack/fieldtrack.proto
Normal file
75
internal/testprotos/fieldtrack/fieldtrack.proto
Normal file
@ -0,0 +1,75 @@
|
||||
// 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.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package goproto.proto.test;
|
||||
|
||||
import "annotation/annotation.proto";
|
||||
import "test/test.proto";
|
||||
import weak "test/weak1/test_weak.proto";
|
||||
import weak "test/weak2/test_weak.proto";
|
||||
|
||||
option go_package = "google.golang.org/protobuf/internal/testprotos/fieldtrack";
|
||||
|
||||
message TestFieldTrack {
|
||||
option (go_annotation.track_field_use) = true;
|
||||
|
||||
optional int32 optional_int32 = 1;
|
||||
optional int64 optional_int64 = 2;
|
||||
optional uint32 optional_uint32 = 3;
|
||||
optional uint64 optional_uint64 = 4;
|
||||
optional sint32 optional_sint32 = 5;
|
||||
optional sint64 optional_sint64 = 6;
|
||||
optional fixed32 optional_fixed32 = 7;
|
||||
optional fixed64 optional_fixed64 = 8;
|
||||
optional sfixed32 optional_sfixed32 = 9;
|
||||
optional sfixed64 optional_sfixed64 = 10;
|
||||
optional float optional_float = 11;
|
||||
optional double optional_double = 12;
|
||||
optional bool optional_bool = 13;
|
||||
optional string optional_string = 14;
|
||||
optional bytes optional_bytes = 15;
|
||||
optional goproto.proto.test.TestAllTypes.NestedEnum optional_enum = 16;
|
||||
optional goproto.proto.test.TestAllTypes.NestedMessage optional_message = 17;
|
||||
|
||||
repeated int32 repeated_int32 = 21;
|
||||
repeated int64 repeated_int64 = 22;
|
||||
repeated uint32 repeated_uint32 = 23;
|
||||
repeated uint64 repeated_uint64 = 24;
|
||||
repeated sint32 repeated_sint32 = 25;
|
||||
repeated sint64 repeated_sint64 = 26;
|
||||
repeated fixed32 repeated_fixed32 = 27;
|
||||
repeated fixed64 repeated_fixed64 = 28;
|
||||
repeated sfixed32 repeated_sfixed32 = 29;
|
||||
repeated sfixed64 repeated_sfixed64 = 30;
|
||||
repeated float repeated_float = 31;
|
||||
repeated double repeated_double = 32;
|
||||
repeated bool repeated_bool = 33;
|
||||
repeated string repeated_string = 34;
|
||||
repeated bytes repeated_bytes = 35;
|
||||
repeated goproto.proto.test.TestAllTypes.NestedEnum repeated_enum = 36;
|
||||
repeated goproto.proto.test.TestAllTypes.NestedMessage repeated_message = 37;
|
||||
|
||||
map <string, int32> map_string_int32 = 41;
|
||||
map <string, int64> map_string_int64 = 42;
|
||||
map <string, uint32> map_string_uint32 = 43;
|
||||
map <string, uint64> map_string_uint64 = 44;
|
||||
map <string, sint32> map_string_sint32 = 45;
|
||||
map <string, sint64> map_string_sint64 = 46;
|
||||
map <string, fixed32> map_string_fixed32 = 47;
|
||||
map <string, fixed64> map_string_fixed64 = 48;
|
||||
map <string, sfixed32> map_string_sfixed32 = 49;
|
||||
map <string, sfixed64> map_string_sfixed64 = 50;
|
||||
map <string, float> map_string_float = 51;
|
||||
map <string, double> map_string_double = 52;
|
||||
map <string, bool> map_string_bool = 53;
|
||||
map <string, string> map_string_string = 54;
|
||||
map <string, bytes> map_string_bytes = 55;
|
||||
map <string, goproto.proto.test.TestAllTypes.NestedEnum> map_string_enum = 56;
|
||||
map <string, goproto.proto.test.TestAllTypes.NestedMessage> map_string_message = 57;
|
||||
|
||||
optional goproto.proto.test.weak.WeakImportMessage1 weak_message1 = 100 [weak=true];
|
||||
optional goproto.proto.test.weak.WeakImportMessage2 weak_message2 = 101 [weak=true];
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user