1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage internal_gengo 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "unicode" 9*1c12ee1eSDan Willemsen "unicode/utf8" 10*1c12ee1eSDan Willemsen 11*1c12ee1eSDan Willemsen "google.golang.org/protobuf/compiler/protogen" 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/protowire" 13*1c12ee1eSDan Willemsen 14*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/descriptorpb" 15*1c12ee1eSDan Willemsen) 16*1c12ee1eSDan Willemsen 17*1c12ee1eSDan Willemsentype fileInfo struct { 18*1c12ee1eSDan Willemsen *protogen.File 19*1c12ee1eSDan Willemsen 20*1c12ee1eSDan Willemsen allEnums []*enumInfo 21*1c12ee1eSDan Willemsen allMessages []*messageInfo 22*1c12ee1eSDan Willemsen allExtensions []*extensionInfo 23*1c12ee1eSDan Willemsen 24*1c12ee1eSDan Willemsen allEnumsByPtr map[*enumInfo]int // value is index into allEnums 25*1c12ee1eSDan Willemsen allMessagesByPtr map[*messageInfo]int // value is index into allMessages 26*1c12ee1eSDan Willemsen allMessageFieldsByPtr map[*messageInfo]*structFields 27*1c12ee1eSDan Willemsen 28*1c12ee1eSDan Willemsen // needRawDesc specifies whether the generator should emit logic to provide 29*1c12ee1eSDan Willemsen // the legacy raw descriptor in GZIP'd form. 30*1c12ee1eSDan Willemsen // This is updated by enum and message generation logic as necessary, 31*1c12ee1eSDan Willemsen // and checked at the end of file generation. 32*1c12ee1eSDan Willemsen needRawDesc bool 33*1c12ee1eSDan Willemsen} 34*1c12ee1eSDan Willemsen 35*1c12ee1eSDan Willemsentype structFields struct { 36*1c12ee1eSDan Willemsen count int 37*1c12ee1eSDan Willemsen unexported map[int]string 38*1c12ee1eSDan Willemsen} 39*1c12ee1eSDan Willemsen 40*1c12ee1eSDan Willemsenfunc (sf *structFields) append(name string) { 41*1c12ee1eSDan Willemsen if r, _ := utf8.DecodeRuneInString(name); !unicode.IsUpper(r) { 42*1c12ee1eSDan Willemsen if sf.unexported == nil { 43*1c12ee1eSDan Willemsen sf.unexported = make(map[int]string) 44*1c12ee1eSDan Willemsen } 45*1c12ee1eSDan Willemsen sf.unexported[sf.count] = name 46*1c12ee1eSDan Willemsen } 47*1c12ee1eSDan Willemsen sf.count++ 48*1c12ee1eSDan Willemsen} 49*1c12ee1eSDan Willemsen 50*1c12ee1eSDan Willemsenfunc newFileInfo(file *protogen.File) *fileInfo { 51*1c12ee1eSDan Willemsen f := &fileInfo{File: file} 52*1c12ee1eSDan Willemsen 53*1c12ee1eSDan Willemsen // Collect all enums, messages, and extensions in "flattened ordering". 54*1c12ee1eSDan Willemsen // See filetype.TypeBuilder. 55*1c12ee1eSDan Willemsen var walkMessages func([]*protogen.Message, func(*protogen.Message)) 56*1c12ee1eSDan Willemsen walkMessages = func(messages []*protogen.Message, f func(*protogen.Message)) { 57*1c12ee1eSDan Willemsen for _, m := range messages { 58*1c12ee1eSDan Willemsen f(m) 59*1c12ee1eSDan Willemsen walkMessages(m.Messages, f) 60*1c12ee1eSDan Willemsen } 61*1c12ee1eSDan Willemsen } 62*1c12ee1eSDan Willemsen initEnumInfos := func(enums []*protogen.Enum) { 63*1c12ee1eSDan Willemsen for _, enum := range enums { 64*1c12ee1eSDan Willemsen f.allEnums = append(f.allEnums, newEnumInfo(f, enum)) 65*1c12ee1eSDan Willemsen } 66*1c12ee1eSDan Willemsen } 67*1c12ee1eSDan Willemsen initMessageInfos := func(messages []*protogen.Message) { 68*1c12ee1eSDan Willemsen for _, message := range messages { 69*1c12ee1eSDan Willemsen f.allMessages = append(f.allMessages, newMessageInfo(f, message)) 70*1c12ee1eSDan Willemsen } 71*1c12ee1eSDan Willemsen } 72*1c12ee1eSDan Willemsen initExtensionInfos := func(extensions []*protogen.Extension) { 73*1c12ee1eSDan Willemsen for _, extension := range extensions { 74*1c12ee1eSDan Willemsen f.allExtensions = append(f.allExtensions, newExtensionInfo(f, extension)) 75*1c12ee1eSDan Willemsen } 76*1c12ee1eSDan Willemsen } 77*1c12ee1eSDan Willemsen initEnumInfos(f.Enums) 78*1c12ee1eSDan Willemsen initMessageInfos(f.Messages) 79*1c12ee1eSDan Willemsen initExtensionInfos(f.Extensions) 80*1c12ee1eSDan Willemsen walkMessages(f.Messages, func(m *protogen.Message) { 81*1c12ee1eSDan Willemsen initEnumInfos(m.Enums) 82*1c12ee1eSDan Willemsen initMessageInfos(m.Messages) 83*1c12ee1eSDan Willemsen initExtensionInfos(m.Extensions) 84*1c12ee1eSDan Willemsen }) 85*1c12ee1eSDan Willemsen 86*1c12ee1eSDan Willemsen // Derive a reverse mapping of enum and message pointers to their index 87*1c12ee1eSDan Willemsen // in allEnums and allMessages. 88*1c12ee1eSDan Willemsen if len(f.allEnums) > 0 { 89*1c12ee1eSDan Willemsen f.allEnumsByPtr = make(map[*enumInfo]int) 90*1c12ee1eSDan Willemsen for i, e := range f.allEnums { 91*1c12ee1eSDan Willemsen f.allEnumsByPtr[e] = i 92*1c12ee1eSDan Willemsen } 93*1c12ee1eSDan Willemsen } 94*1c12ee1eSDan Willemsen if len(f.allMessages) > 0 { 95*1c12ee1eSDan Willemsen f.allMessagesByPtr = make(map[*messageInfo]int) 96*1c12ee1eSDan Willemsen f.allMessageFieldsByPtr = make(map[*messageInfo]*structFields) 97*1c12ee1eSDan Willemsen for i, m := range f.allMessages { 98*1c12ee1eSDan Willemsen f.allMessagesByPtr[m] = i 99*1c12ee1eSDan Willemsen f.allMessageFieldsByPtr[m] = new(structFields) 100*1c12ee1eSDan Willemsen } 101*1c12ee1eSDan Willemsen } 102*1c12ee1eSDan Willemsen 103*1c12ee1eSDan Willemsen return f 104*1c12ee1eSDan Willemsen} 105*1c12ee1eSDan Willemsen 106*1c12ee1eSDan Willemsentype enumInfo struct { 107*1c12ee1eSDan Willemsen *protogen.Enum 108*1c12ee1eSDan Willemsen 109*1c12ee1eSDan Willemsen genJSONMethod bool 110*1c12ee1eSDan Willemsen genRawDescMethod bool 111*1c12ee1eSDan Willemsen} 112*1c12ee1eSDan Willemsen 113*1c12ee1eSDan Willemsenfunc newEnumInfo(f *fileInfo, enum *protogen.Enum) *enumInfo { 114*1c12ee1eSDan Willemsen e := &enumInfo{Enum: enum} 115*1c12ee1eSDan Willemsen e.genJSONMethod = true 116*1c12ee1eSDan Willemsen e.genRawDescMethod = true 117*1c12ee1eSDan Willemsen return e 118*1c12ee1eSDan Willemsen} 119*1c12ee1eSDan Willemsen 120*1c12ee1eSDan Willemsentype messageInfo struct { 121*1c12ee1eSDan Willemsen *protogen.Message 122*1c12ee1eSDan Willemsen 123*1c12ee1eSDan Willemsen genRawDescMethod bool 124*1c12ee1eSDan Willemsen genExtRangeMethod bool 125*1c12ee1eSDan Willemsen 126*1c12ee1eSDan Willemsen isTracked bool 127*1c12ee1eSDan Willemsen hasWeak bool 128*1c12ee1eSDan Willemsen} 129*1c12ee1eSDan Willemsen 130*1c12ee1eSDan Willemsenfunc newMessageInfo(f *fileInfo, message *protogen.Message) *messageInfo { 131*1c12ee1eSDan Willemsen m := &messageInfo{Message: message} 132*1c12ee1eSDan Willemsen m.genRawDescMethod = true 133*1c12ee1eSDan Willemsen m.genExtRangeMethod = true 134*1c12ee1eSDan Willemsen m.isTracked = isTrackedMessage(m) 135*1c12ee1eSDan Willemsen for _, field := range m.Fields { 136*1c12ee1eSDan Willemsen m.hasWeak = m.hasWeak || field.Desc.IsWeak() 137*1c12ee1eSDan Willemsen } 138*1c12ee1eSDan Willemsen return m 139*1c12ee1eSDan Willemsen} 140*1c12ee1eSDan Willemsen 141*1c12ee1eSDan Willemsen// isTrackedMessage reports whether field tracking is enabled on the message. 142*1c12ee1eSDan Willemsenfunc isTrackedMessage(m *messageInfo) (tracked bool) { 143*1c12ee1eSDan Willemsen const trackFieldUse_fieldNumber = 37383685 144*1c12ee1eSDan Willemsen 145*1c12ee1eSDan Willemsen // Decode the option from unknown fields to avoid a dependency on the 146*1c12ee1eSDan Willemsen // annotation proto from protoc-gen-go. 147*1c12ee1eSDan Willemsen b := m.Desc.Options().(*descriptorpb.MessageOptions).ProtoReflect().GetUnknown() 148*1c12ee1eSDan Willemsen for len(b) > 0 { 149*1c12ee1eSDan Willemsen num, typ, n := protowire.ConsumeTag(b) 150*1c12ee1eSDan Willemsen b = b[n:] 151*1c12ee1eSDan Willemsen if num == trackFieldUse_fieldNumber && typ == protowire.VarintType { 152*1c12ee1eSDan Willemsen v, _ := protowire.ConsumeVarint(b) 153*1c12ee1eSDan Willemsen tracked = protowire.DecodeBool(v) 154*1c12ee1eSDan Willemsen } 155*1c12ee1eSDan Willemsen m := protowire.ConsumeFieldValue(num, typ, b) 156*1c12ee1eSDan Willemsen b = b[m:] 157*1c12ee1eSDan Willemsen } 158*1c12ee1eSDan Willemsen return tracked 159*1c12ee1eSDan Willemsen} 160*1c12ee1eSDan Willemsen 161*1c12ee1eSDan Willemsentype extensionInfo struct { 162*1c12ee1eSDan Willemsen *protogen.Extension 163*1c12ee1eSDan Willemsen} 164*1c12ee1eSDan Willemsen 165*1c12ee1eSDan Willemsenfunc newExtensionInfo(f *fileInfo, extension *protogen.Extension) *extensionInfo { 166*1c12ee1eSDan Willemsen x := &extensionInfo{Extension: extension} 167*1c12ee1eSDan Willemsen return x 168*1c12ee1eSDan Willemsen} 169