or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

compiler-protogen.mdcore.mdencoding.mdindex.mdreflection.mdruntime.mdtesting.mdtypes-descriptorpb.mdtypes-dynamicpb.mdtypes-known.mdtypes-pluginpb.md
tile.json

compiler-protogen.mddocs/

Code Generation with Protogen

The protogen package provides high-level support for writing protoc plugins that generate Go code from .proto files. It handles the protocol buffer compiler plugin protocol and provides structured access to file descriptors, messages, fields, and other protobuf elements.

Package Import

import (
    "google.golang.org/protobuf/compiler/protogen"
    "google.golang.org/protobuf/types/pluginpb"
    "google.golang.org/protobuf/types/descriptorpb"
    "google.golang.org/protobuf/reflect/protoreflect"
    "google.golang.org/protobuf/types/gofeaturespb"
)

Plugin Execution

Options

Configure and run a protoc plugin.

// Options configures a code generation request
type Options struct {
    // ParamFunc is called with each unknown generator parameter
    // Plugins can accept parameters from the command line via --<lang>_out
    // Parameters are passed as key=value pairs
    //
    // The (flag.FlagSet).Set method matches this function signature
    ParamFunc func(name, value string) error

    // ImportRewriteFunc is called with the import path of each package
    // imported by a generated file. It returns the import path to use
    ImportRewriteFunc func(GoImportPath) GoImportPath

    // DefaultAPILevel overrides which API to generate by default
    // One of OPEN, HYBRID or OPAQUE
    DefaultAPILevel gofeaturespb.GoFeatures_APILevel

    // InternalStripForEditionsDiff is for internal use by Go Protobuf only
    InternalStripForEditionsDiff *bool
}

// New returns a new Plugin from a CodeGeneratorRequest
func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error)

// Run executes a function as a protoc plugin
// It reads a pluginpb.CodeGeneratorRequest message from os.Stdin,
// invokes the plugin function, and writes a pluginpb.CodeGeneratorResponse
// message to os.Stdout
func (opts Options) Run(f func(*Plugin) error)

Usage example:

import (
    "flag"
    "google.golang.org/protobuf/compiler/protogen"
)

func main() {
    var flags flag.FlagSet
    myFlag := flags.Bool("my_option", false, "Enable my option")

    protogen.Options{
        ParamFunc: flags.Set,
    }.Run(func(gen *protogen.Plugin) error {
        if *myFlag {
            // Custom behavior based on flag
        }

        for _, f := range gen.Files {
            if !f.Generate {
                continue
            }
            generateFile(gen, f)
        }
        return nil
    })
}

Plugin Context

Plugin Type

The main context for a protoc plugin invocation.

// Plugin is a protoc plugin invocation
type Plugin struct {
    // Request is the CodeGeneratorRequest provided by protoc
    Request *pluginpb.CodeGeneratorRequest

    // Files is the set of files to generate and everything they import
    // Files appear in topological order, so each file appears before any
    // file that imports it
    Files       []*File
    FilesByPath map[string]*File

    // SupportedFeatures is the set of protobuf language features supported by
    // this generator plugin
    SupportedFeatures uint64

    SupportedEditionsMinimum descriptorpb.Edition
    SupportedEditionsMaximum descriptorpb.Edition

    // Has unexported fields.
}

// NewGeneratedFile creates a new generated file with the given filename and
// import path
func (gen *Plugin) NewGeneratedFile(filename string, goImportPath GoImportPath) *GeneratedFile

// Error records an error in code generation
// The generator will report the error back to protoc and will not produce output
func (gen *Plugin) Error(err error)

// Response returns the generator output
func (gen *Plugin) Response() *pluginpb.CodeGeneratorResponse

// InternalStripForEditionsDiff is for internal use by Go Protobuf only
func (gen *Plugin) InternalStripForEditionsDiff() bool

Generated Files

GeneratedFile Type

Represents a single generated Go source file.

// GeneratedFile is a generated file
type GeneratedFile struct {
    // Has unexported fields.
}

// P prints a line to the generated output
// It converts each parameter to a string following the same rules as fmt.Print
// It never inserts spaces between parameters
func (g *GeneratedFile) P(v ...any)

// Write implements io.Writer
func (g *GeneratedFile) Write(p []byte) (n int, err error)

// Import ensures a package is imported by the generated file
// Packages referenced by GeneratedFile.QualifiedGoIdent are automatically imported
// Explicitly importing with Import is generally only necessary for blank imports
func (g *GeneratedFile) Import(importPath GoImportPath)

// QualifiedGoIdent returns the string to use for a Go identifier
// If the identifier is from a different Go package than the generated file,
// the returned name will be qualified (package.name) and an import statement
// will be included in the file
func (g *GeneratedFile) QualifiedGoIdent(ident GoIdent) string

// AnnotateSymbol associates a symbol in a generated Go file with a location in
// a source .proto file and a semantic type
// The symbol may refer to a type, constant, variable, function, method, or struct field
// The "T.sel" syntax is used to identify the method or field 'sel' on type 'T'
func (g *GeneratedFile) AnnotateSymbol(symbol string, info Annotation)

// Annotate associates a symbol in a generated Go file with a location in
// a source .proto file
// Deprecated: Use AnnotateSymbol instead
func (g *GeneratedFile) Annotate(symbol string, loc Location)

// Content returns the contents of the generated file
func (g *GeneratedFile) Content() ([]byte, error)

// Skip removes the generated file from the plugin output
func (g *GeneratedFile) Skip()

// Unskip reverts a previous call to Skip, re-including the generated file
func (g *GeneratedFile) Unskip()

// InternalStripForEditionsDiff is for internal use by Go Protobuf only
func (g *GeneratedFile) InternalStripForEditionsDiff() bool

Usage example:

func generateFile(gen *protogen.Plugin, file *protogen.File) {
    filename := file.GeneratedFilenamePrefix + ".myext.go"
    g := gen.NewGeneratedFile(filename, file.GoImportPath)

    // Generate package declaration
    g.P("package ", file.GoPackageName)
    g.P()

    // Generate imports and code
    g.P("import (")
    g.P("  ", g.QualifiedGoIdent(protogen.GoIdent{
        GoImportPath: "context",
        GoName:       "",
    }))
    g.P(")")
    g.P()

    // Generate type declarations
    for _, message := range file.Messages {
        generateMessage(g, message)
    }
}

Type Descriptors

File Descriptor

Represents a .proto source file.

// File describes a .proto source file
type File struct {
    Desc  protoreflect.FileDescriptor
    Proto *descriptorpb.FileDescriptorProto

    GoDescriptorIdent GoIdent       // name of Go variable for the file descriptor
    GoPackageName     GoPackageName // name of this file's Go package
    GoImportPath      GoImportPath  // import path of this file's Go package

    Enums      []*Enum      // top-level enum declarations
    Messages   []*Message   // top-level message declarations
    Extensions []*Extension // top-level extension declarations
    Services   []*Service   // top-level service declarations

    Generate bool // true if we should generate code for this file

    // GeneratedFilenamePrefix is used to construct filenames for generated files
    // For example, "dir/foo.proto" might have a prefix of "dir/foo"
    GeneratedFilenamePrefix string

    // APILevel specifies which API to generate. One of OPEN, HYBRID or OPAQUE
    APILevel gofeaturespb.GoFeatures_APILevel

    // Has unexported fields.
}

Message Descriptor

Represents a protocol buffer message type.

// Message describes a message
type Message struct {
    Desc protoreflect.MessageDescriptor

    GoIdent GoIdent // name of the generated Go type

    Fields []*Field // message field declarations
    Oneofs []*Oneof // message oneof declarations

    Enums      []*Enum      // nested enum declarations
    Messages   []*Message   // nested message declarations
    Extensions []*Extension // nested extension declarations

    Location Location   // location of this message
    Comments CommentSet // comments associated with this message

    // APILevel specifies which API to generate. One of OPEN, HYBRID or OPAQUE
    APILevel gofeaturespb.GoFeatures_APILevel
}

Field Descriptor

Represents a message field.

// Field describes a message field
type Field struct {
    Desc protoreflect.FieldDescriptor

    // GoName is the base name of this field's Go field and methods
    // For code generated by protoc-gen-go, this means a field named
    // '{{GoName}}' and a getter method named 'Get{{GoName}}'
    GoName string // e.g., "FieldName"

    // GoIdent is the base name of a top-level declaration for this field
    // For code generated by protoc-gen-go, this means a wrapper type named
    // '{{GoIdent}}' for members fields of a oneof, and a variable named
    // 'E_{{GoIdent}}' for extension fields
    GoIdent GoIdent // e.g., "MessageName_FieldName"

    Parent   *Message // message in which this field is declared; nil if top-level extension
    Oneof    *Oneof   // containing oneof; nil if not part of a oneof
    Extendee *Message // extended message for extension fields; nil otherwise

    Enum    *Enum    // type for enum fields; nil otherwise
    Message *Message // type for message or group fields; nil otherwise

    Location Location   // location of this field
    Comments CommentSet // comments associated with this field

    // Has unexported fields.
}

// Extension is an alias of Field for documentation
type Extension = Field

// MethodName returns the (possibly mangled) name of the generated accessor method,
// along with the backwards-compatible name (if needed)
// method must be one of Get, Set, Has, Clear. MethodName panics otherwise
func (field *Field) MethodName(method string) (name, compat string)

// BuilderFieldName returns the name of this field in the corresponding _builder struct
func (field *Field) BuilderFieldName() string

Enum Descriptor

Represents an enum type.

// Enum describes an enum
type Enum struct {
    Desc protoreflect.EnumDescriptor

    GoIdent GoIdent // name of the generated Go type

    Values []*EnumValue // enum value declarations

    Location Location   // location of this enum
    Comments CommentSet // comments associated with this enum
}

// EnumValue describes an enum value
type EnumValue struct {
    Desc protoreflect.EnumValueDescriptor

    GoIdent GoIdent // name of the generated Go declaration

    // PrefixedAlias is usually empty, except when the strip_enum_prefix feature
    // was set to GENERATE_BOTH, in which case PrefixedAlias holds the old name
    // which should be generated as an alias for compatibility
    PrefixedAlias GoIdent

    Parent *Enum // enum in which this value is declared

    Location Location   // location of this enum value
    Comments CommentSet // comments associated with this enum value
}

Oneof Descriptor

Represents a oneof field group.

// Oneof describes a message oneof
type Oneof struct {
    Desc protoreflect.OneofDescriptor

    // GoName is the base name of this oneof's Go field and methods
    // For code generated by protoc-gen-go, this means a field named
    // '{{GoName}}' and a getter method named 'Get{{GoName}}'
    GoName string // e.g., "OneofName"

    // GoIdent is the base name of a top-level declaration for this oneof
    GoIdent GoIdent // e.g., "MessageName_OneofName"

    Parent *Message // message in which this oneof is declared

    Fields []*Field // fields that are part of this oneof

    Location Location   // location of this oneof
    Comments CommentSet // comments associated with this oneof

    // Has unexported fields.
}

// MethodName returns the (possibly mangled) name of the generated accessor method
// method must be one of Has, Clear, Which. MethodName panics otherwise
func (oneof *Oneof) MethodName(method string) string

Service Descriptor

Represents a gRPC service.

// Service describes a service
type Service struct {
    Desc protoreflect.ServiceDescriptor

    GoName string

    Methods []*Method // service method declarations

    Location Location   // location of this service
    Comments CommentSet // comments associated with this service
}

// Method describes a method in a service
type Method struct {
    Desc protoreflect.MethodDescriptor

    GoName string

    Parent *Service // service in which this method is declared

    Input  *Message
    Output *Message

    Location Location   // location of this method
    Comments CommentSet // comments associated with this method
}

Go Identifiers

Go Identity Types

Types for representing Go identifiers and import paths.

// GoIdent is a Go identifier, consisting of a name and import path
// The name is a single identifier and may not be a dot-qualified selector
type GoIdent struct {
    GoName       string
    GoImportPath GoImportPath
}

func (id GoIdent) String() string

// GoImportPath is the import path of a Go package
// For example: "google.golang.org/protobuf/compiler/protogen"
type GoImportPath string

// Ident returns a GoIdent with s as the GoName and p as the GoImportPath
func (p GoImportPath) Ident(s string) GoIdent

func (p GoImportPath) String() string

// GoPackageName is the name of a Go package, e.g., "protobuf"
type GoPackageName string

Source Code Information

Location

Represents a location in a .proto source file.

// Location is a location in a .proto source file
type Location struct {
    SourceFile string
    Path       protoreflect.SourcePath
}

Annotation

Provides semantic detail for generated elements.

// Annotation provides semantic detail for a generated proto element
type Annotation struct {
    // Location is the source .proto file for the element
    Location Location

    // Semantic is the symbol's effect on the element in the original .proto file
    Semantic *descriptorpb.GeneratedCodeInfo_Annotation_Semantic
}

Comments

Documentation comments from .proto files.

// Comments is a comments string as provided by protoc
type Comments string

// String formats the comments by inserting // to the start of each line,
// ensuring that there is a trailing newline
// An empty comment is formatted as an empty string
func (c Comments) String() string

// CommentSet is a set of leading and trailing comments associated with a
// .proto descriptor declaration
type CommentSet struct {
    LeadingDetached []Comments
    Leading         Comments
    Trailing        Comments
}

Complete Plugin Example

package main

import (
    "fmt"
    "google.golang.org/protobuf/compiler/protogen"
)

func main() {
    protogen.Options{}.Run(func(gen *protogen.Plugin) error {
        // Set supported features
        gen.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)

        // Process each file marked for generation
        for _, f := range gen.Files {
            if !f.Generate {
                continue
            }
            generateFile(gen, f)
        }
        return nil
    })
}

func generateFile(gen *protogen.Plugin, file *protogen.File) {
    filename := file.GeneratedFilenamePrefix + ".myext.go"
    g := gen.NewGeneratedFile(filename, file.GoImportPath)

    // Generate header
    g.P("// Code generated by protoc-gen-myext. DO NOT EDIT.")
    g.P()
    g.P("package ", file.GoPackageName)
    g.P()

    // Generate for each message
    for _, message := range file.Messages {
        generateMessage(g, message)
    }
}

func generateMessage(g *protogen.GeneratedFile, message *protogen.Message) {
    // Generate comments
    g.P(message.Comments.Leading.String())
    g.P("type ", message.GoIdent, "Wrapper struct {")
    g.P("  Inner *", g.QualifiedGoIdent(message.GoIdent))
    g.P("}")
    g.P()

    // Generate method
    g.P("func (w *", message.GoIdent, "Wrapper) Validate() error {")
    g.P("  // Add validation logic here")
    g.P("  return nil")
    g.P("}")
    g.P()

    // Annotate symbol for IDE integration
    g.AnnotateSymbol(message.GoIdent.GoName+"Wrapper", protogen.Annotation{
        Location: message.Location,
    })

    // Recursively process nested messages
    for _, nested := range message.Messages {
        generateMessage(g, nested)
    }
}

This comprehensive API enables building sophisticated protoc plugins that generate Go code from protocol buffer definitions with full access to type information, comments, and source locations.