github.com/whiteCcinn/protobuf-go@v1.0.9/compiler/protogen/protogen.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package protogen provides support for writing protoc plugins.
     6  //
     7  // Plugins for protoc, the Protocol Buffer compiler,
     8  // are programs which read a CodeGeneratorRequest message from standard input
     9  // and write a CodeGeneratorResponse message to standard output.
    10  // This package provides support for writing plugins which generate Go code.
    11  package protogen
    12  
    13  import (
    14  	"bufio"
    15  	"bytes"
    16  	"fmt"
    17  	"go/ast"
    18  	"go/parser"
    19  	"go/printer"
    20  	"go/token"
    21  	"go/types"
    22  	"io/ioutil"
    23  	"os"
    24  	"path"
    25  	"path/filepath"
    26  	"sort"
    27  	"strconv"
    28  	"strings"
    29  
    30  	"github.com/whiteCcinn/protobuf-go/encoding/prototext"
    31  	"github.com/whiteCcinn/protobuf-go/internal/genid"
    32  	"github.com/whiteCcinn/protobuf-go/internal/strs"
    33  	"github.com/whiteCcinn/protobuf-go/proto"
    34  	"github.com/whiteCcinn/protobuf-go/reflect/protodesc"
    35  	"github.com/whiteCcinn/protobuf-go/reflect/protoreflect"
    36  	"github.com/whiteCcinn/protobuf-go/reflect/protoregistry"
    37  
    38  	"github.com/whiteCcinn/protobuf-go/types/descriptorpb"
    39  	"github.com/whiteCcinn/protobuf-go/types/pluginpb"
    40  )
    41  
    42  const goPackageDocURL = "https://developers.google.com/protocol-buffers/docs/reference/go-generated#package"
    43  
    44  // Run executes a function as a protoc plugin.
    45  //
    46  // It reads a CodeGeneratorRequest message from os.Stdin, invokes the plugin
    47  // function, and writes a CodeGeneratorResponse message to os.Stdout.
    48  //
    49  // If a failure occurs while reading or writing, Run prints an error to
    50  // os.Stderr and calls os.Exit(1).
    51  func (opts Options) Run(f func(*Plugin) error) {
    52  	if err := run(opts, f); err != nil {
    53  		fmt.Fprintf(os.Stderr, "%s: %v\n", filepath.Base(os.Args[0]), err)
    54  		os.Exit(1)
    55  	}
    56  }
    57  
    58  func run(opts Options, f func(*Plugin) error) error {
    59  	if len(os.Args) > 1 {
    60  		return fmt.Errorf("unknown argument %q (this program should be run by protoc, not directly)", os.Args[1])
    61  	}
    62  	in, err := ioutil.ReadAll(os.Stdin)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	req := &pluginpb.CodeGeneratorRequest{}
    67  	if err := proto.Unmarshal(in, req); err != nil {
    68  		return err
    69  	}
    70  	gen, err := opts.New(req)
    71  	if err != nil {
    72  		return err
    73  	}
    74  	if err := f(gen); err != nil {
    75  		// Errors from the plugin function are reported by setting the
    76  		// error field in the CodeGeneratorResponse.
    77  		//
    78  		// In contrast, errors that indicate a problem in protoc
    79  		// itself (unparsable input, I/O errors, etc.) are reported
    80  		// to stderr.
    81  		gen.Error(err)
    82  	}
    83  	resp := gen.Response()
    84  	out, err := proto.Marshal(resp)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	if _, err := os.Stdout.Write(out); err != nil {
    89  		return err
    90  	}
    91  	return nil
    92  }
    93  
    94  // A Plugin is a protoc plugin invocation.
    95  type Plugin struct {
    96  	// Request is the CodeGeneratorRequest provided by protoc.
    97  	Request *pluginpb.CodeGeneratorRequest
    98  
    99  	// Files is the set of files to generate and everything they import.
   100  	// Files appear in topological order, so each file appears before any
   101  	// file that imports it.
   102  	Files       []*File
   103  	FilesByPath map[string]*File
   104  
   105  	// SupportedFeatures is the set of protobuf language features supported by
   106  	// this generator plugin. See the documentation for
   107  	// google.protobuf.CodeGeneratorResponse.supported_features for details.
   108  	SupportedFeatures uint64
   109  
   110  	fileReg        *protoregistry.Files
   111  	enumsByName    map[protoreflect.FullName]*Enum
   112  	messagesByName map[protoreflect.FullName]*Message
   113  	annotateCode   bool
   114  	pathType       pathType
   115  	module         string
   116  	genFiles       []*GeneratedFile
   117  	opts           Options
   118  	err            error
   119  }
   120  
   121  type Options struct {
   122  	// If ParamFunc is non-nil, it will be called with each unknown
   123  	// generator parameter.
   124  	//
   125  	// Plugins for protoc can accept parameters from the command line,
   126  	// passed in the --<lang>_out protoc, separated from the output
   127  	// directory with a colon; e.g.,
   128  	//
   129  	//   --go_out=<param1>=<value1>,<param2>=<value2>:<output_directory>
   130  	//
   131  	// Parameters passed in this fashion as a comma-separated list of
   132  	// key=value pairs will be passed to the ParamFunc.
   133  	//
   134  	// The (flag.FlagSet).Set method matches this function signature,
   135  	// so parameters can be converted into flags as in the following:
   136  	//
   137  	//   var flags flag.FlagSet
   138  	//   value := flags.Bool("param", false, "")
   139  	//   opts := &protogen.Options{
   140  	//     ParamFunc: flags.Set,
   141  	//   }
   142  	//   protogen.Run(opts, func(p *protogen.Plugin) error {
   143  	//     if *value { ... }
   144  	//   })
   145  	ParamFunc func(name, value string) error
   146  
   147  	// ImportRewriteFunc is called with the import path of each package
   148  	// imported by a generated file. It returns the import path to use
   149  	// for this package.
   150  	ImportRewriteFunc func(GoImportPath) GoImportPath
   151  }
   152  
   153  // New returns a new Plugin.
   154  func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error) {
   155  	gen := &Plugin{
   156  		Request:        req,
   157  		FilesByPath:    make(map[string]*File),
   158  		fileReg:        new(protoregistry.Files),
   159  		enumsByName:    make(map[protoreflect.FullName]*Enum),
   160  		messagesByName: make(map[protoreflect.FullName]*Message),
   161  		opts:           opts,
   162  	}
   163  
   164  	packageNames := make(map[string]GoPackageName) // filename -> package name
   165  	importPaths := make(map[string]GoImportPath)   // filename -> import path
   166  	for _, param := range strings.Split(req.GetParameter(), ",") {
   167  		var value string
   168  		if i := strings.Index(param, "="); i >= 0 {
   169  			value = param[i+1:]
   170  			param = param[0:i]
   171  		}
   172  		switch param {
   173  		case "":
   174  			// Ignore.
   175  		case "module":
   176  			gen.module = value
   177  		case "paths":
   178  			switch value {
   179  			case "import":
   180  				gen.pathType = pathTypeImport
   181  			case "source_relative":
   182  				gen.pathType = pathTypeSourceRelative
   183  			default:
   184  				return nil, fmt.Errorf(`unknown path type %q: want "import" or "source_relative"`, value)
   185  			}
   186  		case "annotate_code":
   187  			switch value {
   188  			case "true", "":
   189  				gen.annotateCode = true
   190  			case "false":
   191  			default:
   192  				return nil, fmt.Errorf(`bad value for parameter %q: want "true" or "false"`, param)
   193  			}
   194  		default:
   195  			if param[0] == 'M' {
   196  				impPath, pkgName := splitImportPathAndPackageName(value)
   197  				if pkgName != "" {
   198  					packageNames[param[1:]] = pkgName
   199  				}
   200  				if impPath != "" {
   201  					importPaths[param[1:]] = impPath
   202  				}
   203  				continue
   204  			}
   205  			if opts.ParamFunc != nil {
   206  				if err := opts.ParamFunc(param, value); err != nil {
   207  					return nil, err
   208  				}
   209  			}
   210  		}
   211  	}
   212  	// When the module= option is provided, we strip the module name
   213  	// prefix from generated files. This only makes sense if generated
   214  	// filenames are based on the import path.
   215  	if gen.module != "" && gen.pathType == pathTypeSourceRelative {
   216  		return nil, fmt.Errorf("cannot use module= with paths=source_relative")
   217  	}
   218  
   219  	// Figure out the import path and package name for each file.
   220  	//
   221  	// The rules here are complicated and have grown organically over time.
   222  	// Interactions between different ways of specifying package information
   223  	// may be surprising.
   224  	//
   225  	// The recommended approach is to include a go_package option in every
   226  	// .proto source file specifying the full import path of the Go package
   227  	// associated with this file.
   228  	//
   229  	//     option go_package = "github.com/whiteCcinn/protobuf-go/types/known/anypb";
   230  	//
   231  	// Alternatively, build systems which want to exert full control over
   232  	// import paths may specify M<filename>=<import_path> flags.
   233  	for _, fdesc := range gen.Request.ProtoFile {
   234  		// The "M" command-line flags take precedence over
   235  		// the "go_package" option in the .proto source file.
   236  		filename := fdesc.GetName()
   237  		impPath, pkgName := splitImportPathAndPackageName(fdesc.GetOptions().GetGoPackage())
   238  		if importPaths[filename] == "" && impPath != "" {
   239  			importPaths[filename] = impPath
   240  		}
   241  		if packageNames[filename] == "" && pkgName != "" {
   242  			packageNames[filename] = pkgName
   243  		}
   244  		switch {
   245  		case importPaths[filename] == "":
   246  			// The import path must be specified one way or another.
   247  			return nil, fmt.Errorf(
   248  				"unable to determine Go import path for %q\n\n"+
   249  					"Please specify either:\n"+
   250  					"\t• a \"go_package\" option in the .proto source file, or\n"+
   251  					"\t• a \"M\" argument on the command line.\n\n"+
   252  					"See %v for more information.\n",
   253  				fdesc.GetName(), goPackageDocURL)
   254  		case !strings.Contains(string(importPaths[filename]), ".") &&
   255  			!strings.Contains(string(importPaths[filename]), "/"):
   256  			// Check that import paths contain at least a dot or slash to avoid
   257  			// a common mistake where import path is confused with package name.
   258  			return nil, fmt.Errorf(
   259  				"invalid Go import path %q for %q\n\n"+
   260  					"The import path must contain at least one period ('.') or forward slash ('/') character.\n\n"+
   261  					"See %v for more information.\n",
   262  				string(importPaths[filename]), fdesc.GetName(), goPackageDocURL)
   263  		case packageNames[filename] == "":
   264  			// If the package name is not explicitly specified,
   265  			// then derive a reasonable package name from the import path.
   266  			//
   267  			// NOTE: The package name is derived first from the import path in
   268  			// the "go_package" option (if present) before trying the "M" flag.
   269  			// The inverted order for this is because the primary use of the "M"
   270  			// flag is by build systems that have full control over the
   271  			// import paths all packages, where it is generally expected that
   272  			// the Go package name still be identical for the Go toolchain and
   273  			// for custom build systems like Bazel.
   274  			if impPath == "" {
   275  				impPath = importPaths[filename]
   276  			}
   277  			packageNames[filename] = cleanPackageName(path.Base(string(impPath)))
   278  		}
   279  	}
   280  
   281  	// Consistency check: Every file with the same Go import path should have
   282  	// the same Go package name.
   283  	packageFiles := make(map[GoImportPath][]string)
   284  	for filename, importPath := range importPaths {
   285  		if _, ok := packageNames[filename]; !ok {
   286  			// Skip files mentioned in a M<file>=<import_path> parameter
   287  			// but which do not appear in the CodeGeneratorRequest.
   288  			continue
   289  		}
   290  		packageFiles[importPath] = append(packageFiles[importPath], filename)
   291  	}
   292  	for importPath, filenames := range packageFiles {
   293  		for i := 1; i < len(filenames); i++ {
   294  			if a, b := packageNames[filenames[0]], packageNames[filenames[i]]; a != b {
   295  				return nil, fmt.Errorf("Go package %v has inconsistent names %v (%v) and %v (%v)",
   296  					importPath, a, filenames[0], b, filenames[i])
   297  			}
   298  		}
   299  	}
   300  
   301  	for _, fdesc := range gen.Request.ProtoFile {
   302  		filename := fdesc.GetName()
   303  		if gen.FilesByPath[filename] != nil {
   304  			return nil, fmt.Errorf("duplicate file name: %q", filename)
   305  		}
   306  		f, err := newFile(gen, fdesc, packageNames[filename], importPaths[filename])
   307  		if err != nil {
   308  			return nil, err
   309  		}
   310  		gen.Files = append(gen.Files, f)
   311  		gen.FilesByPath[filename] = f
   312  	}
   313  	for _, filename := range gen.Request.FileToGenerate {
   314  		f, ok := gen.FilesByPath[filename]
   315  		if !ok {
   316  			return nil, fmt.Errorf("no descriptor for generated file: %v", filename)
   317  		}
   318  		f.Generate = true
   319  	}
   320  	return gen, nil
   321  }
   322  
   323  // Error records an error in code generation. The generator will report the
   324  // error back to protoc and will not produce output.
   325  func (gen *Plugin) Error(err error) {
   326  	if gen.err == nil {
   327  		gen.err = err
   328  	}
   329  }
   330  
   331  // Response returns the generator output.
   332  func (gen *Plugin) Response() *pluginpb.CodeGeneratorResponse {
   333  	resp := &pluginpb.CodeGeneratorResponse{}
   334  	if gen.err != nil {
   335  		resp.Error = proto.String(gen.err.Error())
   336  		return resp
   337  	}
   338  	for _, g := range gen.genFiles {
   339  		if g.skip {
   340  			continue
   341  		}
   342  		content, err := g.Content()
   343  		if err != nil {
   344  			return &pluginpb.CodeGeneratorResponse{
   345  				Error: proto.String(err.Error()),
   346  			}
   347  		}
   348  		filename := g.filename
   349  		if gen.module != "" {
   350  			trim := gen.module + "/"
   351  			if !strings.HasPrefix(filename, trim) {
   352  				return &pluginpb.CodeGeneratorResponse{
   353  					Error: proto.String(fmt.Sprintf("%v: generated file does not match prefix %q", filename, gen.module)),
   354  				}
   355  			}
   356  			filename = strings.TrimPrefix(filename, trim)
   357  		}
   358  		resp.File = append(resp.File, &pluginpb.CodeGeneratorResponse_File{
   359  			Name:    proto.String(filename),
   360  			Content: proto.String(string(content)),
   361  		})
   362  		if gen.annotateCode && strings.HasSuffix(g.filename, ".go") {
   363  			meta, err := g.metaFile(content)
   364  			if err != nil {
   365  				return &pluginpb.CodeGeneratorResponse{
   366  					Error: proto.String(err.Error()),
   367  				}
   368  			}
   369  			resp.File = append(resp.File, &pluginpb.CodeGeneratorResponse_File{
   370  				Name:    proto.String(filename + ".meta"),
   371  				Content: proto.String(meta),
   372  			})
   373  		}
   374  	}
   375  	if gen.SupportedFeatures > 0 {
   376  		resp.SupportedFeatures = proto.Uint64(gen.SupportedFeatures)
   377  	}
   378  	return resp
   379  }
   380  
   381  // A File describes a .proto source file.
   382  type File struct {
   383  	Desc  protoreflect.FileDescriptor
   384  	Proto *descriptorpb.FileDescriptorProto
   385  
   386  	GoDescriptorIdent GoIdent       // name of Go variable for the file descriptor
   387  	GoPackageName     GoPackageName // name of this file's Go package
   388  	GoImportPath      GoImportPath  // import path of this file's Go package
   389  
   390  	Enums      []*Enum      // top-level enum declarations
   391  	Messages   []*Message   // top-level message declarations
   392  	Extensions []*Extension // top-level extension declarations
   393  	Services   []*Service   // top-level service declarations
   394  
   395  	Generate bool // true if we should generate code for this file
   396  
   397  	// GeneratedFilenamePrefix is used to construct filenames for generated
   398  	// files associated with this source file.
   399  	//
   400  	// For example, the source file "dir/foo.proto" might have a filename prefix
   401  	// of "dir/foo". Appending ".pb.go" produces an output file of "dir/foo.pb.go".
   402  	GeneratedFilenamePrefix string
   403  
   404  	location Location
   405  }
   406  
   407  func newFile(gen *Plugin, p *descriptorpb.FileDescriptorProto, packageName GoPackageName, importPath GoImportPath) (*File, error) {
   408  	desc, err := protodesc.NewFile(p, gen.fileReg)
   409  	if err != nil {
   410  		return nil, fmt.Errorf("invalid FileDescriptorProto %q: %v", p.GetName(), err)
   411  	}
   412  	if err := gen.fileReg.RegisterFile(desc); err != nil {
   413  		return nil, fmt.Errorf("cannot register descriptor %q: %v", p.GetName(), err)
   414  	}
   415  	f := &File{
   416  		Desc:          desc,
   417  		Proto:         p,
   418  		GoPackageName: packageName,
   419  		GoImportPath:  importPath,
   420  		location:      Location{SourceFile: desc.Path()},
   421  	}
   422  
   423  	// Determine the prefix for generated Go files.
   424  	prefix := p.GetName()
   425  	if ext := path.Ext(prefix); ext == ".proto" || ext == ".protodevel" {
   426  		prefix = prefix[:len(prefix)-len(ext)]
   427  	}
   428  	switch gen.pathType {
   429  	case pathTypeImport:
   430  		// If paths=import, the output filename is derived from the Go import path.
   431  		prefix = path.Join(string(f.GoImportPath), path.Base(prefix))
   432  	case pathTypeSourceRelative:
   433  		// If paths=source_relative, the output filename is derived from
   434  		// the input filename.
   435  	}
   436  	f.GoDescriptorIdent = GoIdent{
   437  		GoName:       "File_" + strs.GoSanitized(p.GetName()),
   438  		GoImportPath: f.GoImportPath,
   439  	}
   440  	f.GeneratedFilenamePrefix = prefix
   441  
   442  	for i, eds := 0, desc.Enums(); i < eds.Len(); i++ {
   443  		f.Enums = append(f.Enums, newEnum(gen, f, nil, eds.Get(i)))
   444  	}
   445  	for i, mds := 0, desc.Messages(); i < mds.Len(); i++ {
   446  		f.Messages = append(f.Messages, newMessage(gen, f, nil, mds.Get(i)))
   447  	}
   448  	for i, xds := 0, desc.Extensions(); i < xds.Len(); i++ {
   449  		f.Extensions = append(f.Extensions, newField(gen, f, nil, xds.Get(i)))
   450  	}
   451  	for i, sds := 0, desc.Services(); i < sds.Len(); i++ {
   452  		f.Services = append(f.Services, newService(gen, f, sds.Get(i)))
   453  	}
   454  	for _, message := range f.Messages {
   455  		if err := message.resolveDependencies(gen); err != nil {
   456  			return nil, err
   457  		}
   458  	}
   459  	for _, extension := range f.Extensions {
   460  		if err := extension.resolveDependencies(gen); err != nil {
   461  			return nil, err
   462  		}
   463  	}
   464  	for _, service := range f.Services {
   465  		for _, method := range service.Methods {
   466  			if err := method.resolveDependencies(gen); err != nil {
   467  				return nil, err
   468  			}
   469  		}
   470  	}
   471  	return f, nil
   472  }
   473  
   474  // splitImportPathAndPackageName splits off the optional Go package name
   475  // from the Go import path when separated by a ';' delimiter.
   476  func splitImportPathAndPackageName(s string) (GoImportPath, GoPackageName) {
   477  	if i := strings.Index(s, ";"); i >= 0 {
   478  		return GoImportPath(s[:i]), GoPackageName(s[i+1:])
   479  	}
   480  	return GoImportPath(s), ""
   481  }
   482  
   483  // An Enum describes an enum.
   484  type Enum struct {
   485  	Desc protoreflect.EnumDescriptor
   486  
   487  	GoIdent GoIdent // name of the generated Go type
   488  
   489  	Values []*EnumValue // enum value declarations
   490  
   491  	Location Location   // location of this enum
   492  	Comments CommentSet // comments associated with this enum
   493  }
   494  
   495  func newEnum(gen *Plugin, f *File, parent *Message, desc protoreflect.EnumDescriptor) *Enum {
   496  	var loc Location
   497  	if parent != nil {
   498  		loc = parent.Location.appendPath(genid.DescriptorProto_EnumType_field_number, desc.Index())
   499  	} else {
   500  		loc = f.location.appendPath(genid.FileDescriptorProto_EnumType_field_number, desc.Index())
   501  	}
   502  	enum := &Enum{
   503  		Desc:     desc,
   504  		GoIdent:  newGoIdent(f, desc),
   505  		Location: loc,
   506  		Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
   507  	}
   508  	gen.enumsByName[desc.FullName()] = enum
   509  	for i, vds := 0, enum.Desc.Values(); i < vds.Len(); i++ {
   510  		enum.Values = append(enum.Values, newEnumValue(gen, f, parent, enum, vds.Get(i)))
   511  	}
   512  	return enum
   513  }
   514  
   515  // An EnumValue describes an enum value.
   516  type EnumValue struct {
   517  	Desc protoreflect.EnumValueDescriptor
   518  
   519  	GoIdent GoIdent // name of the generated Go declaration
   520  
   521  	Parent *Enum // enum in which this value is declared
   522  
   523  	Location Location   // location of this enum value
   524  	Comments CommentSet // comments associated with this enum value
   525  }
   526  
   527  func newEnumValue(gen *Plugin, f *File, message *Message, enum *Enum, desc protoreflect.EnumValueDescriptor) *EnumValue {
   528  	// A top-level enum value's name is: EnumName_ValueName
   529  	// An enum value contained in a message is: MessageName_ValueName
   530  	//
   531  	// For historical reasons, enum value names are not camel-cased.
   532  	parentIdent := enum.GoIdent
   533  	if message != nil {
   534  		parentIdent = message.GoIdent
   535  	}
   536  	name := parentIdent.GoName + "_" + string(desc.Name())
   537  	loc := enum.Location.appendPath(genid.EnumDescriptorProto_Value_field_number, desc.Index())
   538  	return &EnumValue{
   539  		Desc:     desc,
   540  		GoIdent:  f.GoImportPath.Ident(name),
   541  		Parent:   enum,
   542  		Location: loc,
   543  		Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
   544  	}
   545  }
   546  
   547  // A Message describes a message.
   548  type Message struct {
   549  	Desc protoreflect.MessageDescriptor
   550  
   551  	GoIdent GoIdent // name of the generated Go type
   552  
   553  	Fields []*Field // message field declarations
   554  	Oneofs []*Oneof // message oneof declarations
   555  
   556  	Enums      []*Enum      // nested enum declarations
   557  	Messages   []*Message   // nested message declarations
   558  	Extensions []*Extension // nested extension declarations
   559  
   560  	Location Location   // location of this message
   561  	Comments CommentSet // comments associated with this message
   562  }
   563  
   564  func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.MessageDescriptor) *Message {
   565  	var loc Location
   566  	if parent != nil {
   567  		loc = parent.Location.appendPath(genid.DescriptorProto_NestedType_field_number, desc.Index())
   568  	} else {
   569  		loc = f.location.appendPath(genid.FileDescriptorProto_MessageType_field_number, desc.Index())
   570  	}
   571  	message := &Message{
   572  		Desc:     desc,
   573  		GoIdent:  newGoIdent(f, desc),
   574  		Location: loc,
   575  		Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
   576  	}
   577  	gen.messagesByName[desc.FullName()] = message
   578  	for i, eds := 0, desc.Enums(); i < eds.Len(); i++ {
   579  		message.Enums = append(message.Enums, newEnum(gen, f, message, eds.Get(i)))
   580  	}
   581  	for i, mds := 0, desc.Messages(); i < mds.Len(); i++ {
   582  		message.Messages = append(message.Messages, newMessage(gen, f, message, mds.Get(i)))
   583  	}
   584  	for i, fds := 0, desc.Fields(); i < fds.Len(); i++ {
   585  		message.Fields = append(message.Fields, newField(gen, f, message, fds.Get(i)))
   586  	}
   587  	for i, ods := 0, desc.Oneofs(); i < ods.Len(); i++ {
   588  		message.Oneofs = append(message.Oneofs, newOneof(gen, f, message, ods.Get(i)))
   589  	}
   590  	for i, xds := 0, desc.Extensions(); i < xds.Len(); i++ {
   591  		message.Extensions = append(message.Extensions, newField(gen, f, message, xds.Get(i)))
   592  	}
   593  
   594  	// Resolve local references between fields and oneofs.
   595  	for _, field := range message.Fields {
   596  		if od := field.Desc.ContainingOneof(); od != nil {
   597  			oneof := message.Oneofs[od.Index()]
   598  			field.Oneof = oneof
   599  			oneof.Fields = append(oneof.Fields, field)
   600  		}
   601  	}
   602  
   603  	// Field name conflict resolution.
   604  	//
   605  	// We assume well-known method names that may be attached to a generated
   606  	// message type, as well as a 'Get*' method for each field. For each
   607  	// field in turn, we add _s to its name until there are no conflicts.
   608  	//
   609  	// Any change to the following set of method names is a potential
   610  	// incompatible API change because it may change generated field names.
   611  	//
   612  	// TODO: If we ever support a 'go_name' option to set the Go name of a
   613  	// field, we should consider dropping this entirely. The conflict
   614  	// resolution algorithm is subtle and surprising (changing the order
   615  	// in which fields appear in the .proto source file can change the
   616  	// names of fields in generated code), and does not adapt well to
   617  	// adding new per-field methods such as setters.
   618  	usedNames := map[string]bool{
   619  		"Reset":               true,
   620  		"String":              true,
   621  		"ProtoMessage":        true,
   622  		"Marshal":             true,
   623  		"Unmarshal":           true,
   624  		"ExtensionRangeArray": true,
   625  		"ExtensionMap":        true,
   626  		"Descriptor":          true,
   627  	}
   628  	makeNameUnique := func(name string, hasGetter bool) string {
   629  		for usedNames[name] || (hasGetter && usedNames["Get"+name]) {
   630  			name += "_"
   631  		}
   632  		usedNames[name] = true
   633  		usedNames["Get"+name] = hasGetter
   634  		return name
   635  	}
   636  	for _, field := range message.Fields {
   637  		field.GoName = makeNameUnique(field.GoName, true)
   638  		field.GoIdent.GoName = message.GoIdent.GoName + "_" + field.GoName
   639  		if field.Oneof != nil && field.Oneof.Fields[0] == field {
   640  			// Make the name for a oneof unique as well. For historical reasons,
   641  			// this assumes that a getter method is not generated for oneofs.
   642  			// This is incorrect, but fixing it breaks existing code.
   643  			field.Oneof.GoName = makeNameUnique(field.Oneof.GoName, false)
   644  			field.Oneof.GoIdent.GoName = message.GoIdent.GoName + "_" + field.Oneof.GoName
   645  		}
   646  	}
   647  
   648  	// Oneof field name conflict resolution.
   649  	//
   650  	// This conflict resolution is incomplete as it does not consider collisions
   651  	// with other oneof field types, but fixing it breaks existing code.
   652  	for _, field := range message.Fields {
   653  		if field.Oneof != nil {
   654  		Loop:
   655  			for {
   656  				for _, nestedMessage := range message.Messages {
   657  					if nestedMessage.GoIdent == field.GoIdent {
   658  						field.GoIdent.GoName += "_"
   659  						continue Loop
   660  					}
   661  				}
   662  				for _, nestedEnum := range message.Enums {
   663  					if nestedEnum.GoIdent == field.GoIdent {
   664  						field.GoIdent.GoName += "_"
   665  						continue Loop
   666  					}
   667  				}
   668  				break Loop
   669  			}
   670  		}
   671  	}
   672  
   673  	return message
   674  }
   675  
   676  func (message *Message) resolveDependencies(gen *Plugin) error {
   677  	for _, field := range message.Fields {
   678  		if err := field.resolveDependencies(gen); err != nil {
   679  			return err
   680  		}
   681  	}
   682  	for _, message := range message.Messages {
   683  		if err := message.resolveDependencies(gen); err != nil {
   684  			return err
   685  		}
   686  	}
   687  	for _, extension := range message.Extensions {
   688  		if err := extension.resolveDependencies(gen); err != nil {
   689  			return err
   690  		}
   691  	}
   692  	return nil
   693  }
   694  
   695  // A Field describes a message field.
   696  type Field struct {
   697  	Desc protoreflect.FieldDescriptor
   698  
   699  	// GoName is the base name of this field's Go field and methods.
   700  	// For code generated by protoc-gen-go, this means a field named
   701  	// '{{GoName}}' and a getter method named 'Get{{GoName}}'.
   702  	GoName string // e.g., "FieldName"
   703  
   704  	// GoIdent is the base name of a top-level declaration for this field.
   705  	// For code generated by protoc-gen-go, this means a wrapper type named
   706  	// '{{GoIdent}}' for members fields of a oneof, and a variable named
   707  	// 'E_{{GoIdent}}' for extension fields.
   708  	GoIdent GoIdent // e.g., "MessageName_FieldName"
   709  
   710  	Parent   *Message // message in which this field is declared; nil if top-level extension
   711  	Oneof    *Oneof   // containing oneof; nil if not part of a oneof
   712  	Extendee *Message // extended message for extension fields; nil otherwise
   713  
   714  	Enum    *Enum    // type for enum fields; nil otherwise
   715  	Message *Message // type for message or group fields; nil otherwise
   716  
   717  	Location Location   // location of this field
   718  	Comments CommentSet // comments associated with this field
   719  }
   720  
   721  func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDescriptor) *Field {
   722  	var loc Location
   723  	switch {
   724  	case desc.IsExtension() && message == nil:
   725  		loc = f.location.appendPath(genid.FileDescriptorProto_Extension_field_number, desc.Index())
   726  	case desc.IsExtension() && message != nil:
   727  		loc = message.Location.appendPath(genid.DescriptorProto_Extension_field_number, desc.Index())
   728  	default:
   729  		loc = message.Location.appendPath(genid.DescriptorProto_Field_field_number, desc.Index())
   730  	}
   731  	camelCased := strs.GoCamelCase(string(desc.Name()))
   732  	var parentPrefix string
   733  	if message != nil {
   734  		parentPrefix = message.GoIdent.GoName + "_"
   735  	}
   736  	field := &Field{
   737  		Desc:   desc,
   738  		GoName: camelCased,
   739  		GoIdent: GoIdent{
   740  			GoImportPath: f.GoImportPath,
   741  			GoName:       parentPrefix + camelCased,
   742  		},
   743  		Parent:   message,
   744  		Location: loc,
   745  		Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
   746  	}
   747  	return field
   748  }
   749  
   750  func (field *Field) resolveDependencies(gen *Plugin) error {
   751  	desc := field.Desc
   752  	switch desc.Kind() {
   753  	case protoreflect.EnumKind:
   754  		name := field.Desc.Enum().FullName()
   755  		enum, ok := gen.enumsByName[name]
   756  		if !ok {
   757  			return fmt.Errorf("field %v: no descriptor for enum %v", desc.FullName(), name)
   758  		}
   759  		field.Enum = enum
   760  	case protoreflect.MessageKind, protoreflect.GroupKind:
   761  		name := desc.Message().FullName()
   762  		message, ok := gen.messagesByName[name]
   763  		if !ok {
   764  			return fmt.Errorf("field %v: no descriptor for type %v", desc.FullName(), name)
   765  		}
   766  		field.Message = message
   767  	}
   768  	if desc.IsExtension() {
   769  		name := desc.ContainingMessage().FullName()
   770  		message, ok := gen.messagesByName[name]
   771  		if !ok {
   772  			return fmt.Errorf("field %v: no descriptor for type %v", desc.FullName(), name)
   773  		}
   774  		field.Extendee = message
   775  	}
   776  	return nil
   777  }
   778  
   779  // A Oneof describes a message oneof.
   780  type Oneof struct {
   781  	Desc protoreflect.OneofDescriptor
   782  
   783  	// GoName is the base name of this oneof's Go field and methods.
   784  	// For code generated by protoc-gen-go, this means a field named
   785  	// '{{GoName}}' and a getter method named 'Get{{GoName}}'.
   786  	GoName string // e.g., "OneofName"
   787  
   788  	// GoIdent is the base name of a top-level declaration for this oneof.
   789  	GoIdent GoIdent // e.g., "MessageName_OneofName"
   790  
   791  	Parent *Message // message in which this oneof is declared
   792  
   793  	Fields []*Field // fields that are part of this oneof
   794  
   795  	Location Location   // location of this oneof
   796  	Comments CommentSet // comments associated with this oneof
   797  }
   798  
   799  func newOneof(gen *Plugin, f *File, message *Message, desc protoreflect.OneofDescriptor) *Oneof {
   800  	loc := message.Location.appendPath(genid.DescriptorProto_OneofDecl_field_number, desc.Index())
   801  	camelCased := strs.GoCamelCase(string(desc.Name()))
   802  	parentPrefix := message.GoIdent.GoName + "_"
   803  	return &Oneof{
   804  		Desc:   desc,
   805  		Parent: message,
   806  		GoName: camelCased,
   807  		GoIdent: GoIdent{
   808  			GoImportPath: f.GoImportPath,
   809  			GoName:       parentPrefix + camelCased,
   810  		},
   811  		Location: loc,
   812  		Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
   813  	}
   814  }
   815  
   816  // Extension is an alias of Field for documentation.
   817  type Extension = Field
   818  
   819  // A Service describes a service.
   820  type Service struct {
   821  	Desc protoreflect.ServiceDescriptor
   822  
   823  	GoName string
   824  
   825  	Methods []*Method // service method declarations
   826  
   827  	Location Location   // location of this service
   828  	Comments CommentSet // comments associated with this service
   829  }
   830  
   831  func newService(gen *Plugin, f *File, desc protoreflect.ServiceDescriptor) *Service {
   832  	loc := f.location.appendPath(genid.FileDescriptorProto_Service_field_number, desc.Index())
   833  	service := &Service{
   834  		Desc:     desc,
   835  		GoName:   strs.GoCamelCase(string(desc.Name())),
   836  		Location: loc,
   837  		Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
   838  	}
   839  	for i, mds := 0, desc.Methods(); i < mds.Len(); i++ {
   840  		service.Methods = append(service.Methods, newMethod(gen, f, service, mds.Get(i)))
   841  	}
   842  	return service
   843  }
   844  
   845  // A Method describes a method in a service.
   846  type Method struct {
   847  	Desc protoreflect.MethodDescriptor
   848  
   849  	GoName string
   850  
   851  	Parent *Service // service in which this method is declared
   852  
   853  	Input  *Message
   854  	Output *Message
   855  
   856  	Location Location   // location of this method
   857  	Comments CommentSet // comments associated with this method
   858  }
   859  
   860  func newMethod(gen *Plugin, f *File, service *Service, desc protoreflect.MethodDescriptor) *Method {
   861  	loc := service.Location.appendPath(genid.ServiceDescriptorProto_Method_field_number, desc.Index())
   862  	method := &Method{
   863  		Desc:     desc,
   864  		GoName:   strs.GoCamelCase(string(desc.Name())),
   865  		Parent:   service,
   866  		Location: loc,
   867  		Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
   868  	}
   869  	return method
   870  }
   871  
   872  func (method *Method) resolveDependencies(gen *Plugin) error {
   873  	desc := method.Desc
   874  
   875  	inName := desc.Input().FullName()
   876  	in, ok := gen.messagesByName[inName]
   877  	if !ok {
   878  		return fmt.Errorf("method %v: no descriptor for type %v", desc.FullName(), inName)
   879  	}
   880  	method.Input = in
   881  
   882  	outName := desc.Output().FullName()
   883  	out, ok := gen.messagesByName[outName]
   884  	if !ok {
   885  		return fmt.Errorf("method %v: no descriptor for type %v", desc.FullName(), outName)
   886  	}
   887  	method.Output = out
   888  
   889  	return nil
   890  }
   891  
   892  // A GeneratedFile is a generated file.
   893  type GeneratedFile struct {
   894  	gen              *Plugin
   895  	skip             bool
   896  	filename         string
   897  	goImportPath     GoImportPath
   898  	buf              bytes.Buffer
   899  	packageNames     map[GoImportPath]GoPackageName
   900  	usedPackageNames map[GoPackageName]bool
   901  	manualImports    map[GoImportPath]bool
   902  	annotations      map[string][]Location
   903  }
   904  
   905  // NewGeneratedFile creates a new generated file with the given filename
   906  // and import path.
   907  func (gen *Plugin) NewGeneratedFile(filename string, goImportPath GoImportPath) *GeneratedFile {
   908  	g := &GeneratedFile{
   909  		gen:              gen,
   910  		filename:         filename,
   911  		goImportPath:     goImportPath,
   912  		packageNames:     make(map[GoImportPath]GoPackageName),
   913  		usedPackageNames: make(map[GoPackageName]bool),
   914  		manualImports:    make(map[GoImportPath]bool),
   915  		annotations:      make(map[string][]Location),
   916  	}
   917  
   918  	// All predeclared identifiers in Go are already used.
   919  	for _, s := range types.Universe.Names() {
   920  		g.usedPackageNames[GoPackageName(s)] = true
   921  	}
   922  
   923  	gen.genFiles = append(gen.genFiles, g)
   924  	return g
   925  }
   926  
   927  // P prints a line to the generated output. It converts each parameter to a
   928  // string following the same rules as fmt.Print. It never inserts spaces
   929  // between parameters.
   930  func (g *GeneratedFile) P(v ...interface{}) {
   931  	for _, x := range v {
   932  		switch x := x.(type) {
   933  		case GoIdent:
   934  			fmt.Fprint(&g.buf, g.QualifiedGoIdent(x))
   935  		default:
   936  			fmt.Fprint(&g.buf, x)
   937  		}
   938  	}
   939  	fmt.Fprintln(&g.buf)
   940  }
   941  
   942  // QualifiedGoIdent returns the string to use for a Go identifier.
   943  //
   944  // If the identifier is from a different Go package than the generated file,
   945  // the returned name will be qualified (package.name) and an import statement
   946  // for the identifier's package will be included in the file.
   947  func (g *GeneratedFile) QualifiedGoIdent(ident GoIdent) string {
   948  	if ident.GoImportPath == g.goImportPath {
   949  		return ident.GoName
   950  	}
   951  	if packageName, ok := g.packageNames[ident.GoImportPath]; ok {
   952  		return string(packageName) + "." + ident.GoName
   953  	}
   954  	packageName := cleanPackageName(path.Base(string(ident.GoImportPath)))
   955  	for i, orig := 1, packageName; g.usedPackageNames[packageName]; i++ {
   956  		packageName = orig + GoPackageName(strconv.Itoa(i))
   957  	}
   958  	g.packageNames[ident.GoImportPath] = packageName
   959  	g.usedPackageNames[packageName] = true
   960  	return string(packageName) + "." + ident.GoName
   961  }
   962  
   963  // Import ensures a package is imported by the generated file.
   964  //
   965  // Packages referenced by QualifiedGoIdent are automatically imported.
   966  // Explicitly importing a package with Import is generally only necessary
   967  // when the import will be blank (import _ "package").
   968  func (g *GeneratedFile) Import(importPath GoImportPath) {
   969  	g.manualImports[importPath] = true
   970  }
   971  
   972  // Write implements io.Writer.
   973  func (g *GeneratedFile) Write(p []byte) (n int, err error) {
   974  	return g.buf.Write(p)
   975  }
   976  
   977  // Skip removes the generated file from the plugin output.
   978  func (g *GeneratedFile) Skip() {
   979  	g.skip = true
   980  }
   981  
   982  // Unskip reverts a previous call to Skip, re-including the generated file in
   983  // the plugin output.
   984  func (g *GeneratedFile) Unskip() {
   985  	g.skip = false
   986  }
   987  
   988  // Annotate associates a symbol in a generated Go file with a location in a
   989  // source .proto file.
   990  //
   991  // The symbol may refer to a type, constant, variable, function, method, or
   992  // struct field.  The "T.sel" syntax is used to identify the method or field
   993  // 'sel' on type 'T'.
   994  func (g *GeneratedFile) Annotate(symbol string, loc Location) {
   995  	g.annotations[symbol] = append(g.annotations[symbol], loc)
   996  }
   997  
   998  // Content returns the contents of the generated file.
   999  func (g *GeneratedFile) Content() ([]byte, error) {
  1000  	if !strings.HasSuffix(g.filename, ".go") {
  1001  		return g.buf.Bytes(), nil
  1002  	}
  1003  
  1004  	// Reformat generated code.
  1005  	original := g.buf.Bytes()
  1006  	fset := token.NewFileSet()
  1007  	file, err := parser.ParseFile(fset, "", original, parser.ParseComments)
  1008  	if err != nil {
  1009  		// Print out the bad code with line numbers.
  1010  		// This should never happen in practice, but it can while changing generated code
  1011  		// so consider this a debugging aid.
  1012  		var src bytes.Buffer
  1013  		s := bufio.NewScanner(bytes.NewReader(original))
  1014  		for line := 1; s.Scan(); line++ {
  1015  			fmt.Fprintf(&src, "%5d\t%s\n", line, s.Bytes())
  1016  		}
  1017  		return nil, fmt.Errorf("%v: unparsable Go source: %v\n%v", g.filename, err, src.String())
  1018  	}
  1019  
  1020  	// Collect a sorted list of all imports.
  1021  	var importPaths [][2]string
  1022  	rewriteImport := func(importPath string) string {
  1023  		if f := g.gen.opts.ImportRewriteFunc; f != nil {
  1024  			return string(f(GoImportPath(importPath)))
  1025  		}
  1026  		return importPath
  1027  	}
  1028  	for importPath := range g.packageNames {
  1029  		pkgName := string(g.packageNames[GoImportPath(importPath)])
  1030  		pkgPath := rewriteImport(string(importPath))
  1031  		importPaths = append(importPaths, [2]string{pkgName, pkgPath})
  1032  	}
  1033  	for importPath := range g.manualImports {
  1034  		if _, ok := g.packageNames[importPath]; !ok {
  1035  			pkgPath := rewriteImport(string(importPath))
  1036  			importPaths = append(importPaths, [2]string{"_", pkgPath})
  1037  		}
  1038  	}
  1039  	sort.Slice(importPaths, func(i, j int) bool {
  1040  		return importPaths[i][1] < importPaths[j][1]
  1041  	})
  1042  
  1043  	// Modify the AST to include a new import block.
  1044  	if len(importPaths) > 0 {
  1045  		// Insert block after package statement or
  1046  		// possible comment attached to the end of the package statement.
  1047  		pos := file.Package
  1048  		tokFile := fset.File(file.Package)
  1049  		pkgLine := tokFile.Line(file.Package)
  1050  		for _, c := range file.Comments {
  1051  			if tokFile.Line(c.Pos()) > pkgLine {
  1052  				break
  1053  			}
  1054  			pos = c.End()
  1055  		}
  1056  
  1057  		// Construct the import block.
  1058  		impDecl := &ast.GenDecl{
  1059  			Tok:    token.IMPORT,
  1060  			TokPos: pos,
  1061  			Lparen: pos,
  1062  			Rparen: pos,
  1063  		}
  1064  		for _, importPath := range importPaths {
  1065  			impDecl.Specs = append(impDecl.Specs, &ast.ImportSpec{
  1066  				Name: &ast.Ident{
  1067  					Name:    importPath[0],
  1068  					NamePos: pos,
  1069  				},
  1070  				Path: &ast.BasicLit{
  1071  					Kind:     token.STRING,
  1072  					Value:    strconv.Quote(importPath[1]),
  1073  					ValuePos: pos,
  1074  				},
  1075  				EndPos: pos,
  1076  			})
  1077  		}
  1078  		file.Decls = append([]ast.Decl{impDecl}, file.Decls...)
  1079  	}
  1080  
  1081  	var out bytes.Buffer
  1082  	if err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(&out, fset, file); err != nil {
  1083  		return nil, fmt.Errorf("%v: can not reformat Go source: %v", g.filename, err)
  1084  	}
  1085  	return out.Bytes(), nil
  1086  }
  1087  
  1088  // metaFile returns the contents of the file's metadata file, which is a
  1089  // text formatted string of the google.protobuf.GeneratedCodeInfo.
  1090  func (g *GeneratedFile) metaFile(content []byte) (string, error) {
  1091  	fset := token.NewFileSet()
  1092  	astFile, err := parser.ParseFile(fset, "", content, 0)
  1093  	if err != nil {
  1094  		return "", err
  1095  	}
  1096  	info := &descriptorpb.GeneratedCodeInfo{}
  1097  
  1098  	seenAnnotations := make(map[string]bool)
  1099  	annotate := func(s string, ident *ast.Ident) {
  1100  		seenAnnotations[s] = true
  1101  		for _, loc := range g.annotations[s] {
  1102  			info.Annotation = append(info.Annotation, &descriptorpb.GeneratedCodeInfo_Annotation{
  1103  				SourceFile: proto.String(loc.SourceFile),
  1104  				Path:       loc.Path,
  1105  				Begin:      proto.Int32(int32(fset.Position(ident.Pos()).Offset)),
  1106  				End:        proto.Int32(int32(fset.Position(ident.End()).Offset)),
  1107  			})
  1108  		}
  1109  	}
  1110  	for _, decl := range astFile.Decls {
  1111  		switch decl := decl.(type) {
  1112  		case *ast.GenDecl:
  1113  			for _, spec := range decl.Specs {
  1114  				switch spec := spec.(type) {
  1115  				case *ast.TypeSpec:
  1116  					annotate(spec.Name.Name, spec.Name)
  1117  					switch st := spec.Type.(type) {
  1118  					case *ast.StructType:
  1119  						for _, field := range st.Fields.List {
  1120  							for _, name := range field.Names {
  1121  								annotate(spec.Name.Name+"."+name.Name, name)
  1122  							}
  1123  						}
  1124  					case *ast.InterfaceType:
  1125  						for _, field := range st.Methods.List {
  1126  							for _, name := range field.Names {
  1127  								annotate(spec.Name.Name+"."+name.Name, name)
  1128  							}
  1129  						}
  1130  					}
  1131  				case *ast.ValueSpec:
  1132  					for _, name := range spec.Names {
  1133  						annotate(name.Name, name)
  1134  					}
  1135  				}
  1136  			}
  1137  		case *ast.FuncDecl:
  1138  			if decl.Recv == nil {
  1139  				annotate(decl.Name.Name, decl.Name)
  1140  			} else {
  1141  				recv := decl.Recv.List[0].Type
  1142  				if s, ok := recv.(*ast.StarExpr); ok {
  1143  					recv = s.X
  1144  				}
  1145  				if id, ok := recv.(*ast.Ident); ok {
  1146  					annotate(id.Name+"."+decl.Name.Name, decl.Name)
  1147  				}
  1148  			}
  1149  		}
  1150  	}
  1151  	for a := range g.annotations {
  1152  		if !seenAnnotations[a] {
  1153  			return "", fmt.Errorf("%v: no symbol matching annotation %q", g.filename, a)
  1154  		}
  1155  	}
  1156  
  1157  	b, err := prototext.Marshal(info)
  1158  	if err != nil {
  1159  		return "", err
  1160  	}
  1161  	return string(b), nil
  1162  }
  1163  
  1164  // A GoIdent is a Go identifier, consisting of a name and import path.
  1165  // The name is a single identifier and may not be a dot-qualified selector.
  1166  type GoIdent struct {
  1167  	GoName       string
  1168  	GoImportPath GoImportPath
  1169  }
  1170  
  1171  func (id GoIdent) String() string { return fmt.Sprintf("%q.%v", id.GoImportPath, id.GoName) }
  1172  
  1173  // newGoIdent returns the Go identifier for a descriptor.
  1174  func newGoIdent(f *File, d protoreflect.Descriptor) GoIdent {
  1175  	name := strings.TrimPrefix(string(d.FullName()), string(f.Desc.Package())+".")
  1176  	return GoIdent{
  1177  		GoName:       strs.GoCamelCase(name),
  1178  		GoImportPath: f.GoImportPath,
  1179  	}
  1180  }
  1181  
  1182  // A GoImportPath is the import path of a Go package.
  1183  // For example: "github.com/whiteCcinn/protobuf-go/compiler/protogen"
  1184  type GoImportPath string
  1185  
  1186  func (p GoImportPath) String() string { return strconv.Quote(string(p)) }
  1187  
  1188  // Ident returns a GoIdent with s as the GoName and p as the GoImportPath.
  1189  func (p GoImportPath) Ident(s string) GoIdent {
  1190  	return GoIdent{GoName: s, GoImportPath: p}
  1191  }
  1192  
  1193  // A GoPackageName is the name of a Go package. e.g., "protobuf".
  1194  type GoPackageName string
  1195  
  1196  // cleanPackageName converts a string to a valid Go package name.
  1197  func cleanPackageName(name string) GoPackageName {
  1198  	return GoPackageName(strs.GoSanitized(name))
  1199  }
  1200  
  1201  type pathType int
  1202  
  1203  const (
  1204  	pathTypeImport pathType = iota
  1205  	pathTypeSourceRelative
  1206  )
  1207  
  1208  // A Location is a location in a .proto source file.
  1209  //
  1210  // See the google.protobuf.SourceCodeInfo documentation in descriptor.proto
  1211  // for details.
  1212  type Location struct {
  1213  	SourceFile string
  1214  	Path       protoreflect.SourcePath
  1215  }
  1216  
  1217  // appendPath add elements to a Location's path, returning a new Location.
  1218  func (loc Location) appendPath(num protoreflect.FieldNumber, idx int) Location {
  1219  	loc.Path = append(protoreflect.SourcePath(nil), loc.Path...) // make copy
  1220  	loc.Path = append(loc.Path, int32(num), int32(idx))
  1221  	return loc
  1222  }
  1223  
  1224  // CommentSet is a set of leading and trailing comments associated
  1225  // with a .proto descriptor declaration.
  1226  type CommentSet struct {
  1227  	LeadingDetached []Comments
  1228  	Leading         Comments
  1229  	Trailing        Comments
  1230  }
  1231  
  1232  func makeCommentSet(loc protoreflect.SourceLocation) CommentSet {
  1233  	var leadingDetached []Comments
  1234  	for _, s := range loc.LeadingDetachedComments {
  1235  		leadingDetached = append(leadingDetached, Comments(s))
  1236  	}
  1237  	return CommentSet{
  1238  		LeadingDetached: leadingDetached,
  1239  		Leading:         Comments(loc.LeadingComments),
  1240  		Trailing:        Comments(loc.TrailingComments),
  1241  	}
  1242  }
  1243  
  1244  // Comments is a comments string as provided by protoc.
  1245  type Comments string
  1246  
  1247  // String formats the comments by inserting // to the start of each line,
  1248  // ensuring that there is a trailing newline.
  1249  // An empty comment is formatted as an empty string.
  1250  func (c Comments) String() string {
  1251  	if c == "" {
  1252  		return ""
  1253  	}
  1254  	var b []byte
  1255  	for _, line := range strings.Split(strings.TrimSuffix(string(c), "\n"), "\n") {
  1256  		b = append(b, "//"...)
  1257  		b = append(b, line...)
  1258  		b = append(b, "\n"...)
  1259  	}
  1260  	return string(b)
  1261  }