1*1c12ee1eSDan Willemsen// Copyright 2018 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 Willemsen// Package internal_gengo is internal to the protobuf module. 6*1c12ee1eSDan Willemsenpackage internal_gengo 7*1c12ee1eSDan Willemsen 8*1c12ee1eSDan Willemsenimport ( 9*1c12ee1eSDan Willemsen "fmt" 10*1c12ee1eSDan Willemsen "go/ast" 11*1c12ee1eSDan Willemsen "go/parser" 12*1c12ee1eSDan Willemsen "go/token" 13*1c12ee1eSDan Willemsen "math" 14*1c12ee1eSDan Willemsen "strconv" 15*1c12ee1eSDan Willemsen "strings" 16*1c12ee1eSDan Willemsen "unicode" 17*1c12ee1eSDan Willemsen "unicode/utf8" 18*1c12ee1eSDan Willemsen 19*1c12ee1eSDan Willemsen "google.golang.org/protobuf/compiler/protogen" 20*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/encoding/tag" 21*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/genid" 22*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/version" 23*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 24*1c12ee1eSDan Willemsen "google.golang.org/protobuf/runtime/protoimpl" 25*1c12ee1eSDan Willemsen 26*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/descriptorpb" 27*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/pluginpb" 28*1c12ee1eSDan Willemsen) 29*1c12ee1eSDan Willemsen 30*1c12ee1eSDan Willemsen// SupportedFeatures reports the set of supported protobuf language features. 31*1c12ee1eSDan Willemsenvar SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL) 32*1c12ee1eSDan Willemsen 33*1c12ee1eSDan Willemsen// GenerateVersionMarkers specifies whether to generate version markers. 34*1c12ee1eSDan Willemsenvar GenerateVersionMarkers = true 35*1c12ee1eSDan Willemsen 36*1c12ee1eSDan Willemsen// Standard library dependencies. 37*1c12ee1eSDan Willemsenconst ( 38*1c12ee1eSDan Willemsen base64Package = protogen.GoImportPath("encoding/base64") 39*1c12ee1eSDan Willemsen mathPackage = protogen.GoImportPath("math") 40*1c12ee1eSDan Willemsen reflectPackage = protogen.GoImportPath("reflect") 41*1c12ee1eSDan Willemsen sortPackage = protogen.GoImportPath("sort") 42*1c12ee1eSDan Willemsen stringsPackage = protogen.GoImportPath("strings") 43*1c12ee1eSDan Willemsen syncPackage = protogen.GoImportPath("sync") 44*1c12ee1eSDan Willemsen timePackage = protogen.GoImportPath("time") 45*1c12ee1eSDan Willemsen utf8Package = protogen.GoImportPath("unicode/utf8") 46*1c12ee1eSDan Willemsen) 47*1c12ee1eSDan Willemsen 48*1c12ee1eSDan Willemsen// Protobuf library dependencies. 49*1c12ee1eSDan Willemsen// 50*1c12ee1eSDan Willemsen// These are declared as an interface type so that they can be more easily 51*1c12ee1eSDan Willemsen// patched to support unique build environments that impose restrictions 52*1c12ee1eSDan Willemsen// on the dependencies of generated source code. 53*1c12ee1eSDan Willemsenvar ( 54*1c12ee1eSDan Willemsen protoPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/proto") 55*1c12ee1eSDan Willemsen protoifacePackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/runtime/protoiface") 56*1c12ee1eSDan Willemsen protoimplPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/runtime/protoimpl") 57*1c12ee1eSDan Willemsen protojsonPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/encoding/protojson") 58*1c12ee1eSDan Willemsen protoreflectPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoreflect") 59*1c12ee1eSDan Willemsen protoregistryPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoregistry") 60*1c12ee1eSDan Willemsen) 61*1c12ee1eSDan Willemsen 62*1c12ee1eSDan Willemsentype goImportPath interface { 63*1c12ee1eSDan Willemsen String() string 64*1c12ee1eSDan Willemsen Ident(string) protogen.GoIdent 65*1c12ee1eSDan Willemsen} 66*1c12ee1eSDan Willemsen 67*1c12ee1eSDan Willemsen// GenerateFile generates the contents of a .pb.go file. 68*1c12ee1eSDan Willemsenfunc GenerateFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile { 69*1c12ee1eSDan Willemsen filename := file.GeneratedFilenamePrefix + ".pb.go" 70*1c12ee1eSDan Willemsen g := gen.NewGeneratedFile(filename, file.GoImportPath) 71*1c12ee1eSDan Willemsen f := newFileInfo(file) 72*1c12ee1eSDan Willemsen 73*1c12ee1eSDan Willemsen genStandaloneComments(g, f, int32(genid.FileDescriptorProto_Syntax_field_number)) 74*1c12ee1eSDan Willemsen genGeneratedHeader(gen, g, f) 75*1c12ee1eSDan Willemsen genStandaloneComments(g, f, int32(genid.FileDescriptorProto_Package_field_number)) 76*1c12ee1eSDan Willemsen 77*1c12ee1eSDan Willemsen packageDoc := genPackageKnownComment(f) 78*1c12ee1eSDan Willemsen g.P(packageDoc, "package ", f.GoPackageName) 79*1c12ee1eSDan Willemsen g.P() 80*1c12ee1eSDan Willemsen 81*1c12ee1eSDan Willemsen // Emit a static check that enforces a minimum version of the proto package. 82*1c12ee1eSDan Willemsen if GenerateVersionMarkers { 83*1c12ee1eSDan Willemsen g.P("const (") 84*1c12ee1eSDan Willemsen g.P("// Verify that this generated code is sufficiently up-to-date.") 85*1c12ee1eSDan Willemsen g.P("_ = ", protoimplPackage.Ident("EnforceVersion"), "(", protoimpl.GenVersion, " - ", protoimplPackage.Ident("MinVersion"), ")") 86*1c12ee1eSDan Willemsen g.P("// Verify that runtime/protoimpl is sufficiently up-to-date.") 87*1c12ee1eSDan Willemsen g.P("_ = ", protoimplPackage.Ident("EnforceVersion"), "(", protoimplPackage.Ident("MaxVersion"), " - ", protoimpl.GenVersion, ")") 88*1c12ee1eSDan Willemsen g.P(")") 89*1c12ee1eSDan Willemsen g.P() 90*1c12ee1eSDan Willemsen } 91*1c12ee1eSDan Willemsen 92*1c12ee1eSDan Willemsen for i, imps := 0, f.Desc.Imports(); i < imps.Len(); i++ { 93*1c12ee1eSDan Willemsen genImport(gen, g, f, imps.Get(i)) 94*1c12ee1eSDan Willemsen } 95*1c12ee1eSDan Willemsen for _, enum := range f.allEnums { 96*1c12ee1eSDan Willemsen genEnum(g, f, enum) 97*1c12ee1eSDan Willemsen } 98*1c12ee1eSDan Willemsen for _, message := range f.allMessages { 99*1c12ee1eSDan Willemsen genMessage(g, f, message) 100*1c12ee1eSDan Willemsen } 101*1c12ee1eSDan Willemsen genExtensions(g, f) 102*1c12ee1eSDan Willemsen 103*1c12ee1eSDan Willemsen genReflectFileDescriptor(gen, g, f) 104*1c12ee1eSDan Willemsen 105*1c12ee1eSDan Willemsen return g 106*1c12ee1eSDan Willemsen} 107*1c12ee1eSDan Willemsen 108*1c12ee1eSDan Willemsen// genStandaloneComments prints all leading comments for a FileDescriptorProto 109*1c12ee1eSDan Willemsen// location identified by the field number n. 110*1c12ee1eSDan Willemsenfunc genStandaloneComments(g *protogen.GeneratedFile, f *fileInfo, n int32) { 111*1c12ee1eSDan Willemsen loc := f.Desc.SourceLocations().ByPath(protoreflect.SourcePath{n}) 112*1c12ee1eSDan Willemsen for _, s := range loc.LeadingDetachedComments { 113*1c12ee1eSDan Willemsen g.P(protogen.Comments(s)) 114*1c12ee1eSDan Willemsen g.P() 115*1c12ee1eSDan Willemsen } 116*1c12ee1eSDan Willemsen if s := loc.LeadingComments; s != "" { 117*1c12ee1eSDan Willemsen g.P(protogen.Comments(s)) 118*1c12ee1eSDan Willemsen g.P() 119*1c12ee1eSDan Willemsen } 120*1c12ee1eSDan Willemsen} 121*1c12ee1eSDan Willemsen 122*1c12ee1eSDan Willemsenfunc genGeneratedHeader(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo) { 123*1c12ee1eSDan Willemsen g.P("// Code generated by protoc-gen-go. DO NOT EDIT.") 124*1c12ee1eSDan Willemsen 125*1c12ee1eSDan Willemsen if GenerateVersionMarkers { 126*1c12ee1eSDan Willemsen g.P("// versions:") 127*1c12ee1eSDan Willemsen protocGenGoVersion := version.String() 128*1c12ee1eSDan Willemsen protocVersion := "(unknown)" 129*1c12ee1eSDan Willemsen if v := gen.Request.GetCompilerVersion(); v != nil { 130*1c12ee1eSDan Willemsen protocVersion = fmt.Sprintf("v%v.%v.%v", v.GetMajor(), v.GetMinor(), v.GetPatch()) 131*1c12ee1eSDan Willemsen if s := v.GetSuffix(); s != "" { 132*1c12ee1eSDan Willemsen protocVersion += "-" + s 133*1c12ee1eSDan Willemsen } 134*1c12ee1eSDan Willemsen } 135*1c12ee1eSDan Willemsen g.P("// \tprotoc-gen-go ", protocGenGoVersion) 136*1c12ee1eSDan Willemsen g.P("// \tprotoc ", protocVersion) 137*1c12ee1eSDan Willemsen } 138*1c12ee1eSDan Willemsen 139*1c12ee1eSDan Willemsen if f.Proto.GetOptions().GetDeprecated() { 140*1c12ee1eSDan Willemsen g.P("// ", f.Desc.Path(), " is a deprecated file.") 141*1c12ee1eSDan Willemsen } else { 142*1c12ee1eSDan Willemsen g.P("// source: ", f.Desc.Path()) 143*1c12ee1eSDan Willemsen } 144*1c12ee1eSDan Willemsen g.P() 145*1c12ee1eSDan Willemsen} 146*1c12ee1eSDan Willemsen 147*1c12ee1eSDan Willemsenfunc genImport(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, imp protoreflect.FileImport) { 148*1c12ee1eSDan Willemsen impFile, ok := gen.FilesByPath[imp.Path()] 149*1c12ee1eSDan Willemsen if !ok { 150*1c12ee1eSDan Willemsen return 151*1c12ee1eSDan Willemsen } 152*1c12ee1eSDan Willemsen if impFile.GoImportPath == f.GoImportPath { 153*1c12ee1eSDan Willemsen // Don't generate imports or aliases for types in the same Go package. 154*1c12ee1eSDan Willemsen return 155*1c12ee1eSDan Willemsen } 156*1c12ee1eSDan Willemsen // Generate imports for all non-weak dependencies, even if they are not 157*1c12ee1eSDan Willemsen // referenced, because other code and tools depend on having the 158*1c12ee1eSDan Willemsen // full transitive closure of protocol buffer types in the binary. 159*1c12ee1eSDan Willemsen if !imp.IsWeak { 160*1c12ee1eSDan Willemsen g.Import(impFile.GoImportPath) 161*1c12ee1eSDan Willemsen } 162*1c12ee1eSDan Willemsen if !imp.IsPublic { 163*1c12ee1eSDan Willemsen return 164*1c12ee1eSDan Willemsen } 165*1c12ee1eSDan Willemsen 166*1c12ee1eSDan Willemsen // Generate public imports by generating the imported file, parsing it, 167*1c12ee1eSDan Willemsen // and extracting every symbol that should receive a forwarding declaration. 168*1c12ee1eSDan Willemsen impGen := GenerateFile(gen, impFile) 169*1c12ee1eSDan Willemsen impGen.Skip() 170*1c12ee1eSDan Willemsen b, err := impGen.Content() 171*1c12ee1eSDan Willemsen if err != nil { 172*1c12ee1eSDan Willemsen gen.Error(err) 173*1c12ee1eSDan Willemsen return 174*1c12ee1eSDan Willemsen } 175*1c12ee1eSDan Willemsen fset := token.NewFileSet() 176*1c12ee1eSDan Willemsen astFile, err := parser.ParseFile(fset, "", b, parser.ParseComments) 177*1c12ee1eSDan Willemsen if err != nil { 178*1c12ee1eSDan Willemsen gen.Error(err) 179*1c12ee1eSDan Willemsen return 180*1c12ee1eSDan Willemsen } 181*1c12ee1eSDan Willemsen genForward := func(tok token.Token, name string, expr ast.Expr) { 182*1c12ee1eSDan Willemsen // Don't import unexported symbols. 183*1c12ee1eSDan Willemsen r, _ := utf8.DecodeRuneInString(name) 184*1c12ee1eSDan Willemsen if !unicode.IsUpper(r) { 185*1c12ee1eSDan Willemsen return 186*1c12ee1eSDan Willemsen } 187*1c12ee1eSDan Willemsen // Don't import the FileDescriptor. 188*1c12ee1eSDan Willemsen if name == impFile.GoDescriptorIdent.GoName { 189*1c12ee1eSDan Willemsen return 190*1c12ee1eSDan Willemsen } 191*1c12ee1eSDan Willemsen // Don't import decls referencing a symbol defined in another package. 192*1c12ee1eSDan Willemsen // i.e., don't import decls which are themselves public imports: 193*1c12ee1eSDan Willemsen // 194*1c12ee1eSDan Willemsen // type T = somepackage.T 195*1c12ee1eSDan Willemsen if _, ok := expr.(*ast.SelectorExpr); ok { 196*1c12ee1eSDan Willemsen return 197*1c12ee1eSDan Willemsen } 198*1c12ee1eSDan Willemsen g.P(tok, " ", name, " = ", impFile.GoImportPath.Ident(name)) 199*1c12ee1eSDan Willemsen } 200*1c12ee1eSDan Willemsen g.P("// Symbols defined in public import of ", imp.Path(), ".") 201*1c12ee1eSDan Willemsen g.P() 202*1c12ee1eSDan Willemsen for _, decl := range astFile.Decls { 203*1c12ee1eSDan Willemsen switch decl := decl.(type) { 204*1c12ee1eSDan Willemsen case *ast.GenDecl: 205*1c12ee1eSDan Willemsen for _, spec := range decl.Specs { 206*1c12ee1eSDan Willemsen switch spec := spec.(type) { 207*1c12ee1eSDan Willemsen case *ast.TypeSpec: 208*1c12ee1eSDan Willemsen genForward(decl.Tok, spec.Name.Name, spec.Type) 209*1c12ee1eSDan Willemsen case *ast.ValueSpec: 210*1c12ee1eSDan Willemsen for i, name := range spec.Names { 211*1c12ee1eSDan Willemsen var expr ast.Expr 212*1c12ee1eSDan Willemsen if i < len(spec.Values) { 213*1c12ee1eSDan Willemsen expr = spec.Values[i] 214*1c12ee1eSDan Willemsen } 215*1c12ee1eSDan Willemsen genForward(decl.Tok, name.Name, expr) 216*1c12ee1eSDan Willemsen } 217*1c12ee1eSDan Willemsen case *ast.ImportSpec: 218*1c12ee1eSDan Willemsen default: 219*1c12ee1eSDan Willemsen panic(fmt.Sprintf("can't generate forward for spec type %T", spec)) 220*1c12ee1eSDan Willemsen } 221*1c12ee1eSDan Willemsen } 222*1c12ee1eSDan Willemsen } 223*1c12ee1eSDan Willemsen } 224*1c12ee1eSDan Willemsen g.P() 225*1c12ee1eSDan Willemsen} 226*1c12ee1eSDan Willemsen 227*1c12ee1eSDan Willemsenfunc genEnum(g *protogen.GeneratedFile, f *fileInfo, e *enumInfo) { 228*1c12ee1eSDan Willemsen // Enum type declaration. 229*1c12ee1eSDan Willemsen g.Annotate(e.GoIdent.GoName, e.Location) 230*1c12ee1eSDan Willemsen leadingComments := appendDeprecationSuffix(e.Comments.Leading, 231*1c12ee1eSDan Willemsen e.Desc.ParentFile(), 232*1c12ee1eSDan Willemsen e.Desc.Options().(*descriptorpb.EnumOptions).GetDeprecated()) 233*1c12ee1eSDan Willemsen g.P(leadingComments, 234*1c12ee1eSDan Willemsen "type ", e.GoIdent, " int32") 235*1c12ee1eSDan Willemsen 236*1c12ee1eSDan Willemsen // Enum value constants. 237*1c12ee1eSDan Willemsen g.P("const (") 238*1c12ee1eSDan Willemsen for _, value := range e.Values { 239*1c12ee1eSDan Willemsen g.Annotate(value.GoIdent.GoName, value.Location) 240*1c12ee1eSDan Willemsen leadingComments := appendDeprecationSuffix(value.Comments.Leading, 241*1c12ee1eSDan Willemsen value.Desc.ParentFile(), 242*1c12ee1eSDan Willemsen value.Desc.Options().(*descriptorpb.EnumValueOptions).GetDeprecated()) 243*1c12ee1eSDan Willemsen g.P(leadingComments, 244*1c12ee1eSDan Willemsen value.GoIdent, " ", e.GoIdent, " = ", value.Desc.Number(), 245*1c12ee1eSDan Willemsen trailingComment(value.Comments.Trailing)) 246*1c12ee1eSDan Willemsen } 247*1c12ee1eSDan Willemsen g.P(")") 248*1c12ee1eSDan Willemsen g.P() 249*1c12ee1eSDan Willemsen 250*1c12ee1eSDan Willemsen // Enum value maps. 251*1c12ee1eSDan Willemsen g.P("// Enum value maps for ", e.GoIdent, ".") 252*1c12ee1eSDan Willemsen g.P("var (") 253*1c12ee1eSDan Willemsen g.P(e.GoIdent.GoName+"_name", " = map[int32]string{") 254*1c12ee1eSDan Willemsen for _, value := range e.Values { 255*1c12ee1eSDan Willemsen duplicate := "" 256*1c12ee1eSDan Willemsen if value.Desc != e.Desc.Values().ByNumber(value.Desc.Number()) { 257*1c12ee1eSDan Willemsen duplicate = "// Duplicate value: " 258*1c12ee1eSDan Willemsen } 259*1c12ee1eSDan Willemsen g.P(duplicate, value.Desc.Number(), ": ", strconv.Quote(string(value.Desc.Name())), ",") 260*1c12ee1eSDan Willemsen } 261*1c12ee1eSDan Willemsen g.P("}") 262*1c12ee1eSDan Willemsen g.P(e.GoIdent.GoName+"_value", " = map[string]int32{") 263*1c12ee1eSDan Willemsen for _, value := range e.Values { 264*1c12ee1eSDan Willemsen g.P(strconv.Quote(string(value.Desc.Name())), ": ", value.Desc.Number(), ",") 265*1c12ee1eSDan Willemsen } 266*1c12ee1eSDan Willemsen g.P("}") 267*1c12ee1eSDan Willemsen g.P(")") 268*1c12ee1eSDan Willemsen g.P() 269*1c12ee1eSDan Willemsen 270*1c12ee1eSDan Willemsen // Enum method. 271*1c12ee1eSDan Willemsen // 272*1c12ee1eSDan Willemsen // NOTE: A pointer value is needed to represent presence in proto2. 273*1c12ee1eSDan Willemsen // Since a proto2 message can reference a proto3 enum, it is useful to 274*1c12ee1eSDan Willemsen // always generate this method (even on proto3 enums) to support that case. 275*1c12ee1eSDan Willemsen g.P("func (x ", e.GoIdent, ") Enum() *", e.GoIdent, " {") 276*1c12ee1eSDan Willemsen g.P("p := new(", e.GoIdent, ")") 277*1c12ee1eSDan Willemsen g.P("*p = x") 278*1c12ee1eSDan Willemsen g.P("return p") 279*1c12ee1eSDan Willemsen g.P("}") 280*1c12ee1eSDan Willemsen g.P() 281*1c12ee1eSDan Willemsen 282*1c12ee1eSDan Willemsen // String method. 283*1c12ee1eSDan Willemsen g.P("func (x ", e.GoIdent, ") String() string {") 284*1c12ee1eSDan Willemsen g.P("return ", protoimplPackage.Ident("X"), ".EnumStringOf(x.Descriptor(), ", protoreflectPackage.Ident("EnumNumber"), "(x))") 285*1c12ee1eSDan Willemsen g.P("}") 286*1c12ee1eSDan Willemsen g.P() 287*1c12ee1eSDan Willemsen 288*1c12ee1eSDan Willemsen genEnumReflectMethods(g, f, e) 289*1c12ee1eSDan Willemsen 290*1c12ee1eSDan Willemsen // UnmarshalJSON method. 291*1c12ee1eSDan Willemsen if e.genJSONMethod && e.Desc.Syntax() == protoreflect.Proto2 { 292*1c12ee1eSDan Willemsen g.P("// Deprecated: Do not use.") 293*1c12ee1eSDan Willemsen g.P("func (x *", e.GoIdent, ") UnmarshalJSON(b []byte) error {") 294*1c12ee1eSDan Willemsen g.P("num, err := ", protoimplPackage.Ident("X"), ".UnmarshalJSONEnum(x.Descriptor(), b)") 295*1c12ee1eSDan Willemsen g.P("if err != nil {") 296*1c12ee1eSDan Willemsen g.P("return err") 297*1c12ee1eSDan Willemsen g.P("}") 298*1c12ee1eSDan Willemsen g.P("*x = ", e.GoIdent, "(num)") 299*1c12ee1eSDan Willemsen g.P("return nil") 300*1c12ee1eSDan Willemsen g.P("}") 301*1c12ee1eSDan Willemsen g.P() 302*1c12ee1eSDan Willemsen } 303*1c12ee1eSDan Willemsen 304*1c12ee1eSDan Willemsen // EnumDescriptor method. 305*1c12ee1eSDan Willemsen if e.genRawDescMethod { 306*1c12ee1eSDan Willemsen var indexes []string 307*1c12ee1eSDan Willemsen for i := 1; i < len(e.Location.Path); i += 2 { 308*1c12ee1eSDan Willemsen indexes = append(indexes, strconv.Itoa(int(e.Location.Path[i]))) 309*1c12ee1eSDan Willemsen } 310*1c12ee1eSDan Willemsen g.P("// Deprecated: Use ", e.GoIdent, ".Descriptor instead.") 311*1c12ee1eSDan Willemsen g.P("func (", e.GoIdent, ") EnumDescriptor() ([]byte, []int) {") 312*1c12ee1eSDan Willemsen g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}") 313*1c12ee1eSDan Willemsen g.P("}") 314*1c12ee1eSDan Willemsen g.P() 315*1c12ee1eSDan Willemsen f.needRawDesc = true 316*1c12ee1eSDan Willemsen } 317*1c12ee1eSDan Willemsen} 318*1c12ee1eSDan Willemsen 319*1c12ee1eSDan Willemsenfunc genMessage(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { 320*1c12ee1eSDan Willemsen if m.Desc.IsMapEntry() { 321*1c12ee1eSDan Willemsen return 322*1c12ee1eSDan Willemsen } 323*1c12ee1eSDan Willemsen 324*1c12ee1eSDan Willemsen // Message type declaration. 325*1c12ee1eSDan Willemsen g.Annotate(m.GoIdent.GoName, m.Location) 326*1c12ee1eSDan Willemsen leadingComments := appendDeprecationSuffix(m.Comments.Leading, 327*1c12ee1eSDan Willemsen m.Desc.ParentFile(), 328*1c12ee1eSDan Willemsen m.Desc.Options().(*descriptorpb.MessageOptions).GetDeprecated()) 329*1c12ee1eSDan Willemsen g.P(leadingComments, 330*1c12ee1eSDan Willemsen "type ", m.GoIdent, " struct {") 331*1c12ee1eSDan Willemsen genMessageFields(g, f, m) 332*1c12ee1eSDan Willemsen g.P("}") 333*1c12ee1eSDan Willemsen g.P() 334*1c12ee1eSDan Willemsen 335*1c12ee1eSDan Willemsen genMessageKnownFunctions(g, f, m) 336*1c12ee1eSDan Willemsen genMessageDefaultDecls(g, f, m) 337*1c12ee1eSDan Willemsen genMessageMethods(g, f, m) 338*1c12ee1eSDan Willemsen genMessageOneofWrapperTypes(g, f, m) 339*1c12ee1eSDan Willemsen} 340*1c12ee1eSDan Willemsen 341*1c12ee1eSDan Willemsenfunc genMessageFields(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { 342*1c12ee1eSDan Willemsen sf := f.allMessageFieldsByPtr[m] 343*1c12ee1eSDan Willemsen genMessageInternalFields(g, f, m, sf) 344*1c12ee1eSDan Willemsen for _, field := range m.Fields { 345*1c12ee1eSDan Willemsen genMessageField(g, f, m, field, sf) 346*1c12ee1eSDan Willemsen } 347*1c12ee1eSDan Willemsen} 348*1c12ee1eSDan Willemsen 349*1c12ee1eSDan Willemsenfunc genMessageInternalFields(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, sf *structFields) { 350*1c12ee1eSDan Willemsen g.P(genid.State_goname, " ", protoimplPackage.Ident("MessageState")) 351*1c12ee1eSDan Willemsen sf.append(genid.State_goname) 352*1c12ee1eSDan Willemsen g.P(genid.SizeCache_goname, " ", protoimplPackage.Ident("SizeCache")) 353*1c12ee1eSDan Willemsen sf.append(genid.SizeCache_goname) 354*1c12ee1eSDan Willemsen if m.hasWeak { 355*1c12ee1eSDan Willemsen g.P(genid.WeakFields_goname, " ", protoimplPackage.Ident("WeakFields")) 356*1c12ee1eSDan Willemsen sf.append(genid.WeakFields_goname) 357*1c12ee1eSDan Willemsen } 358*1c12ee1eSDan Willemsen g.P(genid.UnknownFields_goname, " ", protoimplPackage.Ident("UnknownFields")) 359*1c12ee1eSDan Willemsen sf.append(genid.UnknownFields_goname) 360*1c12ee1eSDan Willemsen if m.Desc.ExtensionRanges().Len() > 0 { 361*1c12ee1eSDan Willemsen g.P(genid.ExtensionFields_goname, " ", protoimplPackage.Ident("ExtensionFields")) 362*1c12ee1eSDan Willemsen sf.append(genid.ExtensionFields_goname) 363*1c12ee1eSDan Willemsen } 364*1c12ee1eSDan Willemsen if sf.count > 0 { 365*1c12ee1eSDan Willemsen g.P() 366*1c12ee1eSDan Willemsen } 367*1c12ee1eSDan Willemsen} 368*1c12ee1eSDan Willemsen 369*1c12ee1eSDan Willemsenfunc genMessageField(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, field *protogen.Field, sf *structFields) { 370*1c12ee1eSDan Willemsen if oneof := field.Oneof; oneof != nil && !oneof.Desc.IsSynthetic() { 371*1c12ee1eSDan Willemsen // It would be a bit simpler to iterate over the oneofs below, 372*1c12ee1eSDan Willemsen // but generating the field here keeps the contents of the Go 373*1c12ee1eSDan Willemsen // struct in the same order as the contents of the source 374*1c12ee1eSDan Willemsen // .proto file. 375*1c12ee1eSDan Willemsen if oneof.Fields[0] != field { 376*1c12ee1eSDan Willemsen return // only generate for first appearance 377*1c12ee1eSDan Willemsen } 378*1c12ee1eSDan Willemsen 379*1c12ee1eSDan Willemsen tags := structTags{ 380*1c12ee1eSDan Willemsen {"protobuf_oneof", string(oneof.Desc.Name())}, 381*1c12ee1eSDan Willemsen } 382*1c12ee1eSDan Willemsen if m.isTracked { 383*1c12ee1eSDan Willemsen tags = append(tags, gotrackTags...) 384*1c12ee1eSDan Willemsen } 385*1c12ee1eSDan Willemsen 386*1c12ee1eSDan Willemsen g.Annotate(m.GoIdent.GoName+"."+oneof.GoName, oneof.Location) 387*1c12ee1eSDan Willemsen leadingComments := oneof.Comments.Leading 388*1c12ee1eSDan Willemsen if leadingComments != "" { 389*1c12ee1eSDan Willemsen leadingComments += "\n" 390*1c12ee1eSDan Willemsen } 391*1c12ee1eSDan Willemsen ss := []string{fmt.Sprintf(" Types that are assignable to %s:\n", oneof.GoName)} 392*1c12ee1eSDan Willemsen for _, field := range oneof.Fields { 393*1c12ee1eSDan Willemsen ss = append(ss, "\t*"+field.GoIdent.GoName+"\n") 394*1c12ee1eSDan Willemsen } 395*1c12ee1eSDan Willemsen leadingComments += protogen.Comments(strings.Join(ss, "")) 396*1c12ee1eSDan Willemsen g.P(leadingComments, 397*1c12ee1eSDan Willemsen oneof.GoName, " ", oneofInterfaceName(oneof), tags) 398*1c12ee1eSDan Willemsen sf.append(oneof.GoName) 399*1c12ee1eSDan Willemsen return 400*1c12ee1eSDan Willemsen } 401*1c12ee1eSDan Willemsen goType, pointer := fieldGoType(g, f, field) 402*1c12ee1eSDan Willemsen if pointer { 403*1c12ee1eSDan Willemsen goType = "*" + goType 404*1c12ee1eSDan Willemsen } 405*1c12ee1eSDan Willemsen tags := structTags{ 406*1c12ee1eSDan Willemsen {"protobuf", fieldProtobufTagValue(field)}, 407*1c12ee1eSDan Willemsen {"json", fieldJSONTagValue(field)}, 408*1c12ee1eSDan Willemsen } 409*1c12ee1eSDan Willemsen if field.Desc.IsMap() { 410*1c12ee1eSDan Willemsen key := field.Message.Fields[0] 411*1c12ee1eSDan Willemsen val := field.Message.Fields[1] 412*1c12ee1eSDan Willemsen tags = append(tags, structTags{ 413*1c12ee1eSDan Willemsen {"protobuf_key", fieldProtobufTagValue(key)}, 414*1c12ee1eSDan Willemsen {"protobuf_val", fieldProtobufTagValue(val)}, 415*1c12ee1eSDan Willemsen }...) 416*1c12ee1eSDan Willemsen } 417*1c12ee1eSDan Willemsen if m.isTracked { 418*1c12ee1eSDan Willemsen tags = append(tags, gotrackTags...) 419*1c12ee1eSDan Willemsen } 420*1c12ee1eSDan Willemsen 421*1c12ee1eSDan Willemsen name := field.GoName 422*1c12ee1eSDan Willemsen if field.Desc.IsWeak() { 423*1c12ee1eSDan Willemsen name = genid.WeakFieldPrefix_goname + name 424*1c12ee1eSDan Willemsen } 425*1c12ee1eSDan Willemsen g.Annotate(m.GoIdent.GoName+"."+name, field.Location) 426*1c12ee1eSDan Willemsen leadingComments := appendDeprecationSuffix(field.Comments.Leading, 427*1c12ee1eSDan Willemsen field.Desc.ParentFile(), 428*1c12ee1eSDan Willemsen field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) 429*1c12ee1eSDan Willemsen g.P(leadingComments, 430*1c12ee1eSDan Willemsen name, " ", goType, tags, 431*1c12ee1eSDan Willemsen trailingComment(field.Comments.Trailing)) 432*1c12ee1eSDan Willemsen sf.append(field.GoName) 433*1c12ee1eSDan Willemsen} 434*1c12ee1eSDan Willemsen 435*1c12ee1eSDan Willemsen// genMessageDefaultDecls generates consts and vars holding the default 436*1c12ee1eSDan Willemsen// values of fields. 437*1c12ee1eSDan Willemsenfunc genMessageDefaultDecls(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { 438*1c12ee1eSDan Willemsen var consts, vars []string 439*1c12ee1eSDan Willemsen for _, field := range m.Fields { 440*1c12ee1eSDan Willemsen if !field.Desc.HasDefault() { 441*1c12ee1eSDan Willemsen continue 442*1c12ee1eSDan Willemsen } 443*1c12ee1eSDan Willemsen name := "Default_" + m.GoIdent.GoName + "_" + field.GoName 444*1c12ee1eSDan Willemsen goType, _ := fieldGoType(g, f, field) 445*1c12ee1eSDan Willemsen defVal := field.Desc.Default() 446*1c12ee1eSDan Willemsen switch field.Desc.Kind() { 447*1c12ee1eSDan Willemsen case protoreflect.StringKind: 448*1c12ee1eSDan Willemsen consts = append(consts, fmt.Sprintf("%s = %s(%q)", name, goType, defVal.String())) 449*1c12ee1eSDan Willemsen case protoreflect.BytesKind: 450*1c12ee1eSDan Willemsen vars = append(vars, fmt.Sprintf("%s = %s(%q)", name, goType, defVal.Bytes())) 451*1c12ee1eSDan Willemsen case protoreflect.EnumKind: 452*1c12ee1eSDan Willemsen idx := field.Desc.DefaultEnumValue().Index() 453*1c12ee1eSDan Willemsen val := field.Enum.Values[idx] 454*1c12ee1eSDan Willemsen if val.GoIdent.GoImportPath == f.GoImportPath { 455*1c12ee1eSDan Willemsen consts = append(consts, fmt.Sprintf("%s = %s", name, g.QualifiedGoIdent(val.GoIdent))) 456*1c12ee1eSDan Willemsen } else { 457*1c12ee1eSDan Willemsen // If the enum value is declared in a different Go package, 458*1c12ee1eSDan Willemsen // reference it by number since the name may not be correct. 459*1c12ee1eSDan Willemsen // See https://github.com/golang/protobuf/issues/513. 460*1c12ee1eSDan Willemsen consts = append(consts, fmt.Sprintf("%s = %s(%d) // %s", 461*1c12ee1eSDan Willemsen name, g.QualifiedGoIdent(field.Enum.GoIdent), val.Desc.Number(), g.QualifiedGoIdent(val.GoIdent))) 462*1c12ee1eSDan Willemsen } 463*1c12ee1eSDan Willemsen case protoreflect.FloatKind, protoreflect.DoubleKind: 464*1c12ee1eSDan Willemsen if f := defVal.Float(); math.IsNaN(f) || math.IsInf(f, 0) { 465*1c12ee1eSDan Willemsen var fn, arg string 466*1c12ee1eSDan Willemsen switch f := defVal.Float(); { 467*1c12ee1eSDan Willemsen case math.IsInf(f, -1): 468*1c12ee1eSDan Willemsen fn, arg = g.QualifiedGoIdent(mathPackage.Ident("Inf")), "-1" 469*1c12ee1eSDan Willemsen case math.IsInf(f, +1): 470*1c12ee1eSDan Willemsen fn, arg = g.QualifiedGoIdent(mathPackage.Ident("Inf")), "+1" 471*1c12ee1eSDan Willemsen case math.IsNaN(f): 472*1c12ee1eSDan Willemsen fn, arg = g.QualifiedGoIdent(mathPackage.Ident("NaN")), "" 473*1c12ee1eSDan Willemsen } 474*1c12ee1eSDan Willemsen vars = append(vars, fmt.Sprintf("%s = %s(%s(%s))", name, goType, fn, arg)) 475*1c12ee1eSDan Willemsen } else { 476*1c12ee1eSDan Willemsen consts = append(consts, fmt.Sprintf("%s = %s(%v)", name, goType, f)) 477*1c12ee1eSDan Willemsen } 478*1c12ee1eSDan Willemsen default: 479*1c12ee1eSDan Willemsen consts = append(consts, fmt.Sprintf("%s = %s(%v)", name, goType, defVal.Interface())) 480*1c12ee1eSDan Willemsen } 481*1c12ee1eSDan Willemsen } 482*1c12ee1eSDan Willemsen if len(consts) > 0 { 483*1c12ee1eSDan Willemsen g.P("// Default values for ", m.GoIdent, " fields.") 484*1c12ee1eSDan Willemsen g.P("const (") 485*1c12ee1eSDan Willemsen for _, s := range consts { 486*1c12ee1eSDan Willemsen g.P(s) 487*1c12ee1eSDan Willemsen } 488*1c12ee1eSDan Willemsen g.P(")") 489*1c12ee1eSDan Willemsen } 490*1c12ee1eSDan Willemsen if len(vars) > 0 { 491*1c12ee1eSDan Willemsen g.P("// Default values for ", m.GoIdent, " fields.") 492*1c12ee1eSDan Willemsen g.P("var (") 493*1c12ee1eSDan Willemsen for _, s := range vars { 494*1c12ee1eSDan Willemsen g.P(s) 495*1c12ee1eSDan Willemsen } 496*1c12ee1eSDan Willemsen g.P(")") 497*1c12ee1eSDan Willemsen } 498*1c12ee1eSDan Willemsen g.P() 499*1c12ee1eSDan Willemsen} 500*1c12ee1eSDan Willemsen 501*1c12ee1eSDan Willemsenfunc genMessageMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { 502*1c12ee1eSDan Willemsen genMessageBaseMethods(g, f, m) 503*1c12ee1eSDan Willemsen genMessageGetterMethods(g, f, m) 504*1c12ee1eSDan Willemsen genMessageSetterMethods(g, f, m) 505*1c12ee1eSDan Willemsen} 506*1c12ee1eSDan Willemsen 507*1c12ee1eSDan Willemsenfunc genMessageBaseMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { 508*1c12ee1eSDan Willemsen // Reset method. 509*1c12ee1eSDan Willemsen g.P("func (x *", m.GoIdent, ") Reset() {") 510*1c12ee1eSDan Willemsen g.P("*x = ", m.GoIdent, "{}") 511*1c12ee1eSDan Willemsen g.P("if ", protoimplPackage.Ident("UnsafeEnabled"), " {") 512*1c12ee1eSDan Willemsen g.P("mi := &", messageTypesVarName(f), "[", f.allMessagesByPtr[m], "]") 513*1c12ee1eSDan Willemsen g.P("ms := ", protoimplPackage.Ident("X"), ".MessageStateOf(", protoimplPackage.Ident("Pointer"), "(x))") 514*1c12ee1eSDan Willemsen g.P("ms.StoreMessageInfo(mi)") 515*1c12ee1eSDan Willemsen g.P("}") 516*1c12ee1eSDan Willemsen g.P("}") 517*1c12ee1eSDan Willemsen g.P() 518*1c12ee1eSDan Willemsen 519*1c12ee1eSDan Willemsen // String method. 520*1c12ee1eSDan Willemsen g.P("func (x *", m.GoIdent, ") String() string {") 521*1c12ee1eSDan Willemsen g.P("return ", protoimplPackage.Ident("X"), ".MessageStringOf(x)") 522*1c12ee1eSDan Willemsen g.P("}") 523*1c12ee1eSDan Willemsen g.P() 524*1c12ee1eSDan Willemsen 525*1c12ee1eSDan Willemsen // ProtoMessage method. 526*1c12ee1eSDan Willemsen g.P("func (*", m.GoIdent, ") ProtoMessage() {}") 527*1c12ee1eSDan Willemsen g.P() 528*1c12ee1eSDan Willemsen 529*1c12ee1eSDan Willemsen // ProtoReflect method. 530*1c12ee1eSDan Willemsen genMessageReflectMethods(g, f, m) 531*1c12ee1eSDan Willemsen 532*1c12ee1eSDan Willemsen // Descriptor method. 533*1c12ee1eSDan Willemsen if m.genRawDescMethod { 534*1c12ee1eSDan Willemsen var indexes []string 535*1c12ee1eSDan Willemsen for i := 1; i < len(m.Location.Path); i += 2 { 536*1c12ee1eSDan Willemsen indexes = append(indexes, strconv.Itoa(int(m.Location.Path[i]))) 537*1c12ee1eSDan Willemsen } 538*1c12ee1eSDan Willemsen g.P("// Deprecated: Use ", m.GoIdent, ".ProtoReflect.Descriptor instead.") 539*1c12ee1eSDan Willemsen g.P("func (*", m.GoIdent, ") Descriptor() ([]byte, []int) {") 540*1c12ee1eSDan Willemsen g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}") 541*1c12ee1eSDan Willemsen g.P("}") 542*1c12ee1eSDan Willemsen g.P() 543*1c12ee1eSDan Willemsen f.needRawDesc = true 544*1c12ee1eSDan Willemsen } 545*1c12ee1eSDan Willemsen} 546*1c12ee1eSDan Willemsen 547*1c12ee1eSDan Willemsenfunc genMessageGetterMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { 548*1c12ee1eSDan Willemsen for _, field := range m.Fields { 549*1c12ee1eSDan Willemsen genNoInterfacePragma(g, m.isTracked) 550*1c12ee1eSDan Willemsen 551*1c12ee1eSDan Willemsen // Getter for parent oneof. 552*1c12ee1eSDan Willemsen if oneof := field.Oneof; oneof != nil && oneof.Fields[0] == field && !oneof.Desc.IsSynthetic() { 553*1c12ee1eSDan Willemsen g.Annotate(m.GoIdent.GoName+".Get"+oneof.GoName, oneof.Location) 554*1c12ee1eSDan Willemsen g.P("func (m *", m.GoIdent.GoName, ") Get", oneof.GoName, "() ", oneofInterfaceName(oneof), " {") 555*1c12ee1eSDan Willemsen g.P("if m != nil {") 556*1c12ee1eSDan Willemsen g.P("return m.", oneof.GoName) 557*1c12ee1eSDan Willemsen g.P("}") 558*1c12ee1eSDan Willemsen g.P("return nil") 559*1c12ee1eSDan Willemsen g.P("}") 560*1c12ee1eSDan Willemsen g.P() 561*1c12ee1eSDan Willemsen } 562*1c12ee1eSDan Willemsen 563*1c12ee1eSDan Willemsen // Getter for message field. 564*1c12ee1eSDan Willemsen goType, pointer := fieldGoType(g, f, field) 565*1c12ee1eSDan Willemsen defaultValue := fieldDefaultValue(g, f, m, field) 566*1c12ee1eSDan Willemsen g.Annotate(m.GoIdent.GoName+".Get"+field.GoName, field.Location) 567*1c12ee1eSDan Willemsen leadingComments := appendDeprecationSuffix("", 568*1c12ee1eSDan Willemsen field.Desc.ParentFile(), 569*1c12ee1eSDan Willemsen field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) 570*1c12ee1eSDan Willemsen switch { 571*1c12ee1eSDan Willemsen case field.Desc.IsWeak(): 572*1c12ee1eSDan Willemsen g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", protoPackage.Ident("Message"), "{") 573*1c12ee1eSDan Willemsen g.P("var w ", protoimplPackage.Ident("WeakFields")) 574*1c12ee1eSDan Willemsen g.P("if x != nil {") 575*1c12ee1eSDan Willemsen g.P("w = x.", genid.WeakFields_goname) 576*1c12ee1eSDan Willemsen if m.isTracked { 577*1c12ee1eSDan Willemsen g.P("_ = x.", genid.WeakFieldPrefix_goname+field.GoName) 578*1c12ee1eSDan Willemsen } 579*1c12ee1eSDan Willemsen g.P("}") 580*1c12ee1eSDan Willemsen g.P("return ", protoimplPackage.Ident("X"), ".GetWeak(w, ", field.Desc.Number(), ", ", strconv.Quote(string(field.Message.Desc.FullName())), ")") 581*1c12ee1eSDan Willemsen g.P("}") 582*1c12ee1eSDan Willemsen case field.Oneof != nil && !field.Oneof.Desc.IsSynthetic(): 583*1c12ee1eSDan Willemsen g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", goType, " {") 584*1c12ee1eSDan Willemsen g.P("if x, ok := x.Get", field.Oneof.GoName, "().(*", field.GoIdent, "); ok {") 585*1c12ee1eSDan Willemsen g.P("return x.", field.GoName) 586*1c12ee1eSDan Willemsen g.P("}") 587*1c12ee1eSDan Willemsen g.P("return ", defaultValue) 588*1c12ee1eSDan Willemsen g.P("}") 589*1c12ee1eSDan Willemsen default: 590*1c12ee1eSDan Willemsen g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", goType, " {") 591*1c12ee1eSDan Willemsen if !field.Desc.HasPresence() || defaultValue == "nil" { 592*1c12ee1eSDan Willemsen g.P("if x != nil {") 593*1c12ee1eSDan Willemsen } else { 594*1c12ee1eSDan Willemsen g.P("if x != nil && x.", field.GoName, " != nil {") 595*1c12ee1eSDan Willemsen } 596*1c12ee1eSDan Willemsen star := "" 597*1c12ee1eSDan Willemsen if pointer { 598*1c12ee1eSDan Willemsen star = "*" 599*1c12ee1eSDan Willemsen } 600*1c12ee1eSDan Willemsen g.P("return ", star, " x.", field.GoName) 601*1c12ee1eSDan Willemsen g.P("}") 602*1c12ee1eSDan Willemsen g.P("return ", defaultValue) 603*1c12ee1eSDan Willemsen g.P("}") 604*1c12ee1eSDan Willemsen } 605*1c12ee1eSDan Willemsen g.P() 606*1c12ee1eSDan Willemsen } 607*1c12ee1eSDan Willemsen} 608*1c12ee1eSDan Willemsen 609*1c12ee1eSDan Willemsenfunc genMessageSetterMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { 610*1c12ee1eSDan Willemsen for _, field := range m.Fields { 611*1c12ee1eSDan Willemsen if !field.Desc.IsWeak() { 612*1c12ee1eSDan Willemsen continue 613*1c12ee1eSDan Willemsen } 614*1c12ee1eSDan Willemsen 615*1c12ee1eSDan Willemsen genNoInterfacePragma(g, m.isTracked) 616*1c12ee1eSDan Willemsen 617*1c12ee1eSDan Willemsen g.Annotate(m.GoIdent.GoName+".Set"+field.GoName, field.Location) 618*1c12ee1eSDan Willemsen leadingComments := appendDeprecationSuffix("", 619*1c12ee1eSDan Willemsen field.Desc.ParentFile(), 620*1c12ee1eSDan Willemsen field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) 621*1c12ee1eSDan Willemsen g.P(leadingComments, "func (x *", m.GoIdent, ") Set", field.GoName, "(v ", protoPackage.Ident("Message"), ") {") 622*1c12ee1eSDan Willemsen g.P("var w *", protoimplPackage.Ident("WeakFields")) 623*1c12ee1eSDan Willemsen g.P("if x != nil {") 624*1c12ee1eSDan Willemsen g.P("w = &x.", genid.WeakFields_goname) 625*1c12ee1eSDan Willemsen if m.isTracked { 626*1c12ee1eSDan Willemsen g.P("_ = x.", genid.WeakFieldPrefix_goname+field.GoName) 627*1c12ee1eSDan Willemsen } 628*1c12ee1eSDan Willemsen g.P("}") 629*1c12ee1eSDan Willemsen g.P(protoimplPackage.Ident("X"), ".SetWeak(w, ", field.Desc.Number(), ", ", strconv.Quote(string(field.Message.Desc.FullName())), ", v)") 630*1c12ee1eSDan Willemsen g.P("}") 631*1c12ee1eSDan Willemsen g.P() 632*1c12ee1eSDan Willemsen } 633*1c12ee1eSDan Willemsen} 634*1c12ee1eSDan Willemsen 635*1c12ee1eSDan Willemsen// fieldGoType returns the Go type used for a field. 636*1c12ee1eSDan Willemsen// 637*1c12ee1eSDan Willemsen// If it returns pointer=true, the struct field is a pointer to the type. 638*1c12ee1eSDan Willemsenfunc fieldGoType(g *protogen.GeneratedFile, f *fileInfo, field *protogen.Field) (goType string, pointer bool) { 639*1c12ee1eSDan Willemsen if field.Desc.IsWeak() { 640*1c12ee1eSDan Willemsen return "struct{}", false 641*1c12ee1eSDan Willemsen } 642*1c12ee1eSDan Willemsen 643*1c12ee1eSDan Willemsen pointer = field.Desc.HasPresence() 644*1c12ee1eSDan Willemsen switch field.Desc.Kind() { 645*1c12ee1eSDan Willemsen case protoreflect.BoolKind: 646*1c12ee1eSDan Willemsen goType = "bool" 647*1c12ee1eSDan Willemsen case protoreflect.EnumKind: 648*1c12ee1eSDan Willemsen goType = g.QualifiedGoIdent(field.Enum.GoIdent) 649*1c12ee1eSDan Willemsen case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: 650*1c12ee1eSDan Willemsen goType = "int32" 651*1c12ee1eSDan Willemsen case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: 652*1c12ee1eSDan Willemsen goType = "uint32" 653*1c12ee1eSDan Willemsen case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: 654*1c12ee1eSDan Willemsen goType = "int64" 655*1c12ee1eSDan Willemsen case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: 656*1c12ee1eSDan Willemsen goType = "uint64" 657*1c12ee1eSDan Willemsen case protoreflect.FloatKind: 658*1c12ee1eSDan Willemsen goType = "float32" 659*1c12ee1eSDan Willemsen case protoreflect.DoubleKind: 660*1c12ee1eSDan Willemsen goType = "float64" 661*1c12ee1eSDan Willemsen case protoreflect.StringKind: 662*1c12ee1eSDan Willemsen goType = "string" 663*1c12ee1eSDan Willemsen case protoreflect.BytesKind: 664*1c12ee1eSDan Willemsen goType = "[]byte" 665*1c12ee1eSDan Willemsen pointer = false // rely on nullability of slices for presence 666*1c12ee1eSDan Willemsen case protoreflect.MessageKind, protoreflect.GroupKind: 667*1c12ee1eSDan Willemsen goType = "*" + g.QualifiedGoIdent(field.Message.GoIdent) 668*1c12ee1eSDan Willemsen pointer = false // pointer captured as part of the type 669*1c12ee1eSDan Willemsen } 670*1c12ee1eSDan Willemsen switch { 671*1c12ee1eSDan Willemsen case field.Desc.IsList(): 672*1c12ee1eSDan Willemsen return "[]" + goType, false 673*1c12ee1eSDan Willemsen case field.Desc.IsMap(): 674*1c12ee1eSDan Willemsen keyType, _ := fieldGoType(g, f, field.Message.Fields[0]) 675*1c12ee1eSDan Willemsen valType, _ := fieldGoType(g, f, field.Message.Fields[1]) 676*1c12ee1eSDan Willemsen return fmt.Sprintf("map[%v]%v", keyType, valType), false 677*1c12ee1eSDan Willemsen } 678*1c12ee1eSDan Willemsen return goType, pointer 679*1c12ee1eSDan Willemsen} 680*1c12ee1eSDan Willemsen 681*1c12ee1eSDan Willemsenfunc fieldProtobufTagValue(field *protogen.Field) string { 682*1c12ee1eSDan Willemsen var enumName string 683*1c12ee1eSDan Willemsen if field.Desc.Kind() == protoreflect.EnumKind { 684*1c12ee1eSDan Willemsen enumName = protoimpl.X.LegacyEnumName(field.Enum.Desc) 685*1c12ee1eSDan Willemsen } 686*1c12ee1eSDan Willemsen return tag.Marshal(field.Desc, enumName) 687*1c12ee1eSDan Willemsen} 688*1c12ee1eSDan Willemsen 689*1c12ee1eSDan Willemsenfunc fieldDefaultValue(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, field *protogen.Field) string { 690*1c12ee1eSDan Willemsen if field.Desc.IsList() { 691*1c12ee1eSDan Willemsen return "nil" 692*1c12ee1eSDan Willemsen } 693*1c12ee1eSDan Willemsen if field.Desc.HasDefault() { 694*1c12ee1eSDan Willemsen defVarName := "Default_" + m.GoIdent.GoName + "_" + field.GoName 695*1c12ee1eSDan Willemsen if field.Desc.Kind() == protoreflect.BytesKind { 696*1c12ee1eSDan Willemsen return "append([]byte(nil), " + defVarName + "...)" 697*1c12ee1eSDan Willemsen } 698*1c12ee1eSDan Willemsen return defVarName 699*1c12ee1eSDan Willemsen } 700*1c12ee1eSDan Willemsen switch field.Desc.Kind() { 701*1c12ee1eSDan Willemsen case protoreflect.BoolKind: 702*1c12ee1eSDan Willemsen return "false" 703*1c12ee1eSDan Willemsen case protoreflect.StringKind: 704*1c12ee1eSDan Willemsen return `""` 705*1c12ee1eSDan Willemsen case protoreflect.MessageKind, protoreflect.GroupKind, protoreflect.BytesKind: 706*1c12ee1eSDan Willemsen return "nil" 707*1c12ee1eSDan Willemsen case protoreflect.EnumKind: 708*1c12ee1eSDan Willemsen val := field.Enum.Values[0] 709*1c12ee1eSDan Willemsen if val.GoIdent.GoImportPath == f.GoImportPath { 710*1c12ee1eSDan Willemsen return g.QualifiedGoIdent(val.GoIdent) 711*1c12ee1eSDan Willemsen } else { 712*1c12ee1eSDan Willemsen // If the enum value is declared in a different Go package, 713*1c12ee1eSDan Willemsen // reference it by number since the name may not be correct. 714*1c12ee1eSDan Willemsen // See https://github.com/golang/protobuf/issues/513. 715*1c12ee1eSDan Willemsen return g.QualifiedGoIdent(field.Enum.GoIdent) + "(" + strconv.FormatInt(int64(val.Desc.Number()), 10) + ")" 716*1c12ee1eSDan Willemsen } 717*1c12ee1eSDan Willemsen default: 718*1c12ee1eSDan Willemsen return "0" 719*1c12ee1eSDan Willemsen } 720*1c12ee1eSDan Willemsen} 721*1c12ee1eSDan Willemsen 722*1c12ee1eSDan Willemsenfunc fieldJSONTagValue(field *protogen.Field) string { 723*1c12ee1eSDan Willemsen return string(field.Desc.Name()) + ",omitempty" 724*1c12ee1eSDan Willemsen} 725*1c12ee1eSDan Willemsen 726*1c12ee1eSDan Willemsenfunc genExtensions(g *protogen.GeneratedFile, f *fileInfo) { 727*1c12ee1eSDan Willemsen if len(f.allExtensions) == 0 { 728*1c12ee1eSDan Willemsen return 729*1c12ee1eSDan Willemsen } 730*1c12ee1eSDan Willemsen 731*1c12ee1eSDan Willemsen g.P("var ", extensionTypesVarName(f), " = []", protoimplPackage.Ident("ExtensionInfo"), "{") 732*1c12ee1eSDan Willemsen for _, x := range f.allExtensions { 733*1c12ee1eSDan Willemsen g.P("{") 734*1c12ee1eSDan Willemsen g.P("ExtendedType: (*", x.Extendee.GoIdent, ")(nil),") 735*1c12ee1eSDan Willemsen goType, pointer := fieldGoType(g, f, x.Extension) 736*1c12ee1eSDan Willemsen if pointer { 737*1c12ee1eSDan Willemsen goType = "*" + goType 738*1c12ee1eSDan Willemsen } 739*1c12ee1eSDan Willemsen g.P("ExtensionType: (", goType, ")(nil),") 740*1c12ee1eSDan Willemsen g.P("Field: ", x.Desc.Number(), ",") 741*1c12ee1eSDan Willemsen g.P("Name: ", strconv.Quote(string(x.Desc.FullName())), ",") 742*1c12ee1eSDan Willemsen g.P("Tag: ", strconv.Quote(fieldProtobufTagValue(x.Extension)), ",") 743*1c12ee1eSDan Willemsen g.P("Filename: ", strconv.Quote(f.Desc.Path()), ",") 744*1c12ee1eSDan Willemsen g.P("},") 745*1c12ee1eSDan Willemsen } 746*1c12ee1eSDan Willemsen g.P("}") 747*1c12ee1eSDan Willemsen g.P() 748*1c12ee1eSDan Willemsen 749*1c12ee1eSDan Willemsen // Group extensions by the target message. 750*1c12ee1eSDan Willemsen var orderedTargets []protogen.GoIdent 751*1c12ee1eSDan Willemsen allExtensionsByTarget := make(map[protogen.GoIdent][]*extensionInfo) 752*1c12ee1eSDan Willemsen allExtensionsByPtr := make(map[*extensionInfo]int) 753*1c12ee1eSDan Willemsen for i, x := range f.allExtensions { 754*1c12ee1eSDan Willemsen target := x.Extendee.GoIdent 755*1c12ee1eSDan Willemsen if len(allExtensionsByTarget[target]) == 0 { 756*1c12ee1eSDan Willemsen orderedTargets = append(orderedTargets, target) 757*1c12ee1eSDan Willemsen } 758*1c12ee1eSDan Willemsen allExtensionsByTarget[target] = append(allExtensionsByTarget[target], x) 759*1c12ee1eSDan Willemsen allExtensionsByPtr[x] = i 760*1c12ee1eSDan Willemsen } 761*1c12ee1eSDan Willemsen for _, target := range orderedTargets { 762*1c12ee1eSDan Willemsen g.P("// Extension fields to ", target, ".") 763*1c12ee1eSDan Willemsen g.P("var (") 764*1c12ee1eSDan Willemsen for _, x := range allExtensionsByTarget[target] { 765*1c12ee1eSDan Willemsen xd := x.Desc 766*1c12ee1eSDan Willemsen typeName := xd.Kind().String() 767*1c12ee1eSDan Willemsen switch xd.Kind() { 768*1c12ee1eSDan Willemsen case protoreflect.EnumKind: 769*1c12ee1eSDan Willemsen typeName = string(xd.Enum().FullName()) 770*1c12ee1eSDan Willemsen case protoreflect.MessageKind, protoreflect.GroupKind: 771*1c12ee1eSDan Willemsen typeName = string(xd.Message().FullName()) 772*1c12ee1eSDan Willemsen } 773*1c12ee1eSDan Willemsen fieldName := string(xd.Name()) 774*1c12ee1eSDan Willemsen 775*1c12ee1eSDan Willemsen leadingComments := x.Comments.Leading 776*1c12ee1eSDan Willemsen if leadingComments != "" { 777*1c12ee1eSDan Willemsen leadingComments += "\n" 778*1c12ee1eSDan Willemsen } 779*1c12ee1eSDan Willemsen leadingComments += protogen.Comments(fmt.Sprintf(" %v %v %v = %v;\n", 780*1c12ee1eSDan Willemsen xd.Cardinality(), typeName, fieldName, xd.Number())) 781*1c12ee1eSDan Willemsen leadingComments = appendDeprecationSuffix(leadingComments, 782*1c12ee1eSDan Willemsen x.Desc.ParentFile(), 783*1c12ee1eSDan Willemsen x.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) 784*1c12ee1eSDan Willemsen g.P(leadingComments, 785*1c12ee1eSDan Willemsen "E_", x.GoIdent, " = &", extensionTypesVarName(f), "[", allExtensionsByPtr[x], "]", 786*1c12ee1eSDan Willemsen trailingComment(x.Comments.Trailing)) 787*1c12ee1eSDan Willemsen } 788*1c12ee1eSDan Willemsen g.P(")") 789*1c12ee1eSDan Willemsen g.P() 790*1c12ee1eSDan Willemsen } 791*1c12ee1eSDan Willemsen} 792*1c12ee1eSDan Willemsen 793*1c12ee1eSDan Willemsen// genMessageOneofWrapperTypes generates the oneof wrapper types and 794*1c12ee1eSDan Willemsen// associates the types with the parent message type. 795*1c12ee1eSDan Willemsenfunc genMessageOneofWrapperTypes(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { 796*1c12ee1eSDan Willemsen for _, oneof := range m.Oneofs { 797*1c12ee1eSDan Willemsen if oneof.Desc.IsSynthetic() { 798*1c12ee1eSDan Willemsen continue 799*1c12ee1eSDan Willemsen } 800*1c12ee1eSDan Willemsen ifName := oneofInterfaceName(oneof) 801*1c12ee1eSDan Willemsen g.P("type ", ifName, " interface {") 802*1c12ee1eSDan Willemsen g.P(ifName, "()") 803*1c12ee1eSDan Willemsen g.P("}") 804*1c12ee1eSDan Willemsen g.P() 805*1c12ee1eSDan Willemsen for _, field := range oneof.Fields { 806*1c12ee1eSDan Willemsen g.Annotate(field.GoIdent.GoName, field.Location) 807*1c12ee1eSDan Willemsen g.Annotate(field.GoIdent.GoName+"."+field.GoName, field.Location) 808*1c12ee1eSDan Willemsen g.P("type ", field.GoIdent, " struct {") 809*1c12ee1eSDan Willemsen goType, _ := fieldGoType(g, f, field) 810*1c12ee1eSDan Willemsen tags := structTags{ 811*1c12ee1eSDan Willemsen {"protobuf", fieldProtobufTagValue(field)}, 812*1c12ee1eSDan Willemsen } 813*1c12ee1eSDan Willemsen if m.isTracked { 814*1c12ee1eSDan Willemsen tags = append(tags, gotrackTags...) 815*1c12ee1eSDan Willemsen } 816*1c12ee1eSDan Willemsen leadingComments := appendDeprecationSuffix(field.Comments.Leading, 817*1c12ee1eSDan Willemsen field.Desc.ParentFile(), 818*1c12ee1eSDan Willemsen field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) 819*1c12ee1eSDan Willemsen g.P(leadingComments, 820*1c12ee1eSDan Willemsen field.GoName, " ", goType, tags, 821*1c12ee1eSDan Willemsen trailingComment(field.Comments.Trailing)) 822*1c12ee1eSDan Willemsen g.P("}") 823*1c12ee1eSDan Willemsen g.P() 824*1c12ee1eSDan Willemsen } 825*1c12ee1eSDan Willemsen for _, field := range oneof.Fields { 826*1c12ee1eSDan Willemsen g.P("func (*", field.GoIdent, ") ", ifName, "() {}") 827*1c12ee1eSDan Willemsen g.P() 828*1c12ee1eSDan Willemsen } 829*1c12ee1eSDan Willemsen } 830*1c12ee1eSDan Willemsen} 831*1c12ee1eSDan Willemsen 832*1c12ee1eSDan Willemsen// oneofInterfaceName returns the name of the interface type implemented by 833*1c12ee1eSDan Willemsen// the oneof field value types. 834*1c12ee1eSDan Willemsenfunc oneofInterfaceName(oneof *protogen.Oneof) string { 835*1c12ee1eSDan Willemsen return "is" + oneof.GoIdent.GoName 836*1c12ee1eSDan Willemsen} 837*1c12ee1eSDan Willemsen 838*1c12ee1eSDan Willemsen// genNoInterfacePragma generates a standalone "nointerface" pragma to 839*1c12ee1eSDan Willemsen// decorate methods with field-tracking support. 840*1c12ee1eSDan Willemsenfunc genNoInterfacePragma(g *protogen.GeneratedFile, tracked bool) { 841*1c12ee1eSDan Willemsen if tracked { 842*1c12ee1eSDan Willemsen g.P("//go:nointerface") 843*1c12ee1eSDan Willemsen g.P() 844*1c12ee1eSDan Willemsen } 845*1c12ee1eSDan Willemsen} 846*1c12ee1eSDan Willemsen 847*1c12ee1eSDan Willemsenvar gotrackTags = structTags{{"go", "track"}} 848*1c12ee1eSDan Willemsen 849*1c12ee1eSDan Willemsen// structTags is a data structure for build idiomatic Go struct tags. 850*1c12ee1eSDan Willemsen// Each [2]string is a key-value pair, where value is the unescaped string. 851*1c12ee1eSDan Willemsen// 852*1c12ee1eSDan Willemsen// Example: structTags{{"key", "value"}}.String() -> `key:"value"` 853*1c12ee1eSDan Willemsentype structTags [][2]string 854*1c12ee1eSDan Willemsen 855*1c12ee1eSDan Willemsenfunc (tags structTags) String() string { 856*1c12ee1eSDan Willemsen if len(tags) == 0 { 857*1c12ee1eSDan Willemsen return "" 858*1c12ee1eSDan Willemsen } 859*1c12ee1eSDan Willemsen var ss []string 860*1c12ee1eSDan Willemsen for _, tag := range tags { 861*1c12ee1eSDan Willemsen // NOTE: When quoting the value, we need to make sure the backtick 862*1c12ee1eSDan Willemsen // character does not appear. Convert all cases to the escaped hex form. 863*1c12ee1eSDan Willemsen key := tag[0] 864*1c12ee1eSDan Willemsen val := strings.Replace(strconv.Quote(tag[1]), "`", `\x60`, -1) 865*1c12ee1eSDan Willemsen ss = append(ss, fmt.Sprintf("%s:%s", key, val)) 866*1c12ee1eSDan Willemsen } 867*1c12ee1eSDan Willemsen return "`" + strings.Join(ss, " ") + "`" 868*1c12ee1eSDan Willemsen} 869*1c12ee1eSDan Willemsen 870*1c12ee1eSDan Willemsen// appendDeprecationSuffix optionally appends a deprecation notice as a suffix. 871*1c12ee1eSDan Willemsenfunc appendDeprecationSuffix(prefix protogen.Comments, parentFile protoreflect.FileDescriptor, deprecated bool) protogen.Comments { 872*1c12ee1eSDan Willemsen fileDeprecated := parentFile.Options().(*descriptorpb.FileOptions).GetDeprecated() 873*1c12ee1eSDan Willemsen if !deprecated && !fileDeprecated { 874*1c12ee1eSDan Willemsen return prefix 875*1c12ee1eSDan Willemsen } 876*1c12ee1eSDan Willemsen if prefix != "" { 877*1c12ee1eSDan Willemsen prefix += "\n" 878*1c12ee1eSDan Willemsen } 879*1c12ee1eSDan Willemsen if fileDeprecated { 880*1c12ee1eSDan Willemsen return prefix + " Deprecated: The entire proto file " + protogen.Comments(parentFile.Path()) + " is marked as deprecated.\n" 881*1c12ee1eSDan Willemsen } 882*1c12ee1eSDan Willemsen return prefix + " Deprecated: Marked as deprecated in " + protogen.Comments(parentFile.Path()) + ".\n" 883*1c12ee1eSDan Willemsen} 884*1c12ee1eSDan Willemsen 885*1c12ee1eSDan Willemsen// trailingComment is like protogen.Comments, but lacks a trailing newline. 886*1c12ee1eSDan Willemsentype trailingComment protogen.Comments 887*1c12ee1eSDan Willemsen 888*1c12ee1eSDan Willemsenfunc (c trailingComment) String() string { 889*1c12ee1eSDan Willemsen s := strings.TrimSuffix(protogen.Comments(c).String(), "\n") 890*1c12ee1eSDan Willemsen if strings.Contains(s, "\n") { 891*1c12ee1eSDan Willemsen // We don't support multi-lined trailing comments as it is unclear 892*1c12ee1eSDan Willemsen // how to best render them in the generated code. 893*1c12ee1eSDan Willemsen return "" 894*1c12ee1eSDan Willemsen } 895*1c12ee1eSDan Willemsen return s 896*1c12ee1eSDan Willemsen} 897