mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2024-12-26 21:24:22 +00:00
eb7b468655
For golang/protobuf#1657 Change-Id: I7b2b0c30506706015ce278e6054439c9ad9ef727 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/634815 TryBot-Bypass: Michael Stapelberg <stapelberg@google.com> Reviewed-by: Joseph Tsai <joetsai@digital-static.net> Reviewed-by: Damien Neil <dneil@google.com>
172 lines
4.5 KiB
Go
172 lines
4.5 KiB
Go
// 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 (
|
|
"unicode"
|
|
"unicode/utf8"
|
|
|
|
"google.golang.org/protobuf/compiler/protogen"
|
|
"google.golang.org/protobuf/encoding/protowire"
|
|
|
|
"google.golang.org/protobuf/types/descriptorpb"
|
|
)
|
|
|
|
type fileInfo struct {
|
|
*protogen.File
|
|
|
|
allEnums []*enumInfo
|
|
allMessages []*messageInfo
|
|
allExtensions []*extensionInfo
|
|
|
|
allEnumsByPtr map[*enumInfo]int // value is index into allEnums
|
|
allMessagesByPtr map[*messageInfo]int // value is index into allMessages
|
|
allMessageFieldsByPtr map[*messageInfo]*structFields
|
|
|
|
// needRawDesc specifies whether the generator should emit logic to provide
|
|
// the legacy raw descriptor in GZIP'd form.
|
|
// This is updated by enum and message generation logic as necessary,
|
|
// and checked at the end of file generation.
|
|
needRawDesc bool
|
|
}
|
|
|
|
type structFields struct {
|
|
count int
|
|
unexported map[int]string
|
|
}
|
|
|
|
func (sf *structFields) append(name string) {
|
|
if r, _ := utf8.DecodeRuneInString(name); !unicode.IsUpper(r) {
|
|
if sf.unexported == nil {
|
|
sf.unexported = make(map[int]string)
|
|
}
|
|
sf.unexported[sf.count] = name
|
|
}
|
|
sf.count++
|
|
}
|
|
|
|
func newFileInfo(file *protogen.File) *fileInfo {
|
|
f := &fileInfo{File: file}
|
|
|
|
// Collect all enums, messages, and extensions in "flattened ordering".
|
|
// See filetype.TypeBuilder.
|
|
var walkMessages func([]*protogen.Message, func(*protogen.Message))
|
|
walkMessages = func(messages []*protogen.Message, f func(*protogen.Message)) {
|
|
for _, m := range messages {
|
|
f(m)
|
|
walkMessages(m.Messages, f)
|
|
}
|
|
}
|
|
initEnumInfos := func(enums []*protogen.Enum) {
|
|
for _, enum := range enums {
|
|
f.allEnums = append(f.allEnums, newEnumInfo(f, enum))
|
|
}
|
|
}
|
|
initMessageInfos := func(messages []*protogen.Message) {
|
|
for _, message := range messages {
|
|
f.allMessages = append(f.allMessages, newMessageInfo(f, message))
|
|
}
|
|
}
|
|
initExtensionInfos := func(extensions []*protogen.Extension) {
|
|
for _, extension := range extensions {
|
|
f.allExtensions = append(f.allExtensions, newExtensionInfo(f, extension))
|
|
}
|
|
}
|
|
initEnumInfos(f.Enums)
|
|
initMessageInfos(f.Messages)
|
|
initExtensionInfos(f.Extensions)
|
|
walkMessages(f.Messages, func(m *protogen.Message) {
|
|
initEnumInfos(m.Enums)
|
|
initMessageInfos(m.Messages)
|
|
initExtensionInfos(m.Extensions)
|
|
})
|
|
|
|
// Derive a reverse mapping of enum and message pointers to their index
|
|
// in allEnums and allMessages.
|
|
if len(f.allEnums) > 0 {
|
|
f.allEnumsByPtr = make(map[*enumInfo]int)
|
|
for i, e := range f.allEnums {
|
|
f.allEnumsByPtr[e] = i
|
|
}
|
|
}
|
|
if len(f.allMessages) > 0 {
|
|
f.allMessagesByPtr = make(map[*messageInfo]int)
|
|
f.allMessageFieldsByPtr = make(map[*messageInfo]*structFields)
|
|
for i, m := range f.allMessages {
|
|
f.allMessagesByPtr[m] = i
|
|
f.allMessageFieldsByPtr[m] = new(structFields)
|
|
}
|
|
}
|
|
|
|
return f
|
|
}
|
|
|
|
type enumInfo struct {
|
|
*protogen.Enum
|
|
|
|
genJSONMethod bool
|
|
genRawDescMethod bool
|
|
}
|
|
|
|
func newEnumInfo(f *fileInfo, enum *protogen.Enum) *enumInfo {
|
|
e := &enumInfo{Enum: enum}
|
|
e.genJSONMethod = true
|
|
e.genRawDescMethod = true
|
|
opaqueNewEnumInfoHook(f, e)
|
|
return e
|
|
}
|
|
|
|
type messageInfo struct {
|
|
*protogen.Message
|
|
|
|
genRawDescMethod bool
|
|
genExtRangeMethod bool
|
|
|
|
isTracked bool
|
|
noInterface bool
|
|
hasWeak bool
|
|
}
|
|
|
|
func newMessageInfo(f *fileInfo, message *protogen.Message) *messageInfo {
|
|
m := &messageInfo{Message: message}
|
|
m.genRawDescMethod = true
|
|
m.genExtRangeMethod = true
|
|
m.isTracked = isTrackedMessage(m)
|
|
for _, field := range m.Fields {
|
|
m.hasWeak = m.hasWeak || field.Desc.IsWeak()
|
|
}
|
|
opaqueNewMessageInfoHook(f, m)
|
|
return m
|
|
}
|
|
|
|
// isTrackedMessage reports whether field tracking is enabled on the message.
|
|
func isTrackedMessage(m *messageInfo) (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 := m.Desc.Options().(*descriptorpb.MessageOptions).ProtoReflect().GetUnknown()
|
|
for len(b) > 0 {
|
|
num, typ, n := protowire.ConsumeTag(b)
|
|
b = b[n:]
|
|
if num == trackFieldUse_fieldNumber && typ == protowire.VarintType {
|
|
v, _ := protowire.ConsumeVarint(b)
|
|
tracked = protowire.DecodeBool(v)
|
|
}
|
|
m := protowire.ConsumeFieldValue(num, typ, b)
|
|
b = b[m:]
|
|
}
|
|
return tracked
|
|
}
|
|
|
|
type extensionInfo struct {
|
|
*protogen.Extension
|
|
}
|
|
|
|
func newExtensionInfo(f *fileInfo, extension *protogen.Extension) *extensionInfo {
|
|
x := &extensionInfo{Extension: extension}
|
|
return x
|
|
}
|