protogetter

package module
v1.0.0-cofide.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 8, 2026 License: MIT Imports: 14 Imported by: 0

README

Protogetter

This is a fork of ghostiam/protogetter.

It carries one change: typesNamed resolves type aliases, so a message reached through an alias such as type Message = pb.Message is recognised as a message. Without it the linter reports nothing at all for the messages a package re-exports that way, and offers a partial fix for a selector chain rooted at one. The change is offered upstream, and this fork exists to be consumed until it lands there, at which point the fork should be abandoned for the upstream release.

Everything else is upstream. To take a new upstream release, rebase this branch onto its tag and tag the result as <upstream version>-cofide.<n>. Only the module path, the two imports of it, the install line below and this note differ from upstream on top of the fix.

Welcome to the Protogetter project!

Overview

Protogetter is a linter developed specifically for Go programmers working with nested protobuf types.
It's designed to aid developers in preventing invalid memory address or nil pointer dereference errors arising from direct access of nested protobuf fields.

When working with protobuf, it's quite common to have complex structures where a message field is contained within another message, which itself can be part of another message, and so on. If these fields are accessed directly and some field in the call chain will not be initialized, it can result in application panic.

Protogetter addresses this issue by suggesting use of getter methods for field access.

How does it work?

Protogetter analyzes your Go code and helps detect direct protobuf field accesses that could give rise to panic.
The linter suggests using getters:

m.GetFoo().GetBar().GetBaz()

instead of direct field access:

m.Foo.Bar.Baz

And you will then only need to perform a nil check after the final call:

if m.GetFoo().GetBar().GetBaz() != nil {
    // Do something with m.GetFoo().GetBar().GetBaz()
}

instead of:

if m.Foo != nil {
    if m.Foo.Bar != nil {
        if m.Foo.Bar.Baz != nil {
            // Do something with m.Foo.Bar.Baz
        }
    }
}

or use zero values:

// If one of the methods returns `nil` we will receive 0 instead of panic.
v := m.GetFoo().GetBar().GetBaz().GetInt() 

instead of panic:

// If at least one structure in the chains is not initialized, we will get a panic. 
v := m.Foo.Bar.Baz.Int

which simplifies the code and makes it more reliable.

Usage

Protogetter is integrated into golangci-lint and can be run together with other linters. This is the preferred way to use it in most projects.

Example minimal .golangci.yml configuration:

linters:
  enable:
    - protogetter

Run:

golangci-lint run ./...

Standalone usage

Installation
go install github.com/cofide/protogetter/cmd/protogetter@latest
Direct run

To run the linter:

protogetter ./...

Or to apply suggested fixes directly:

protogetter --fix ./...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewAnalyzer

func NewAnalyzer(cfg *Config) *analysis.Analyzer

func Run

func Run(pass *analysis.Pass, cfg *Config) error

Types

type Config

type Config struct {
	SkipGeneratedBy         []string
	SkipFiles               []string
	SkipAnyGenerated        bool
	ReplaceFirstArgInAppend bool
}

type PosFilter

type PosFilter struct {
	// contains filtered or unexported fields
}

func NewPosFilter

func NewPosFilter() *PosFilter

func (*PosFilter) AddAlreadyReplaced

func (f *PosFilter) AddAlreadyReplaced(fset *token.FileSet, pos, end token.Pos)

func (*PosFilter) AddPos

func (f *PosFilter) AddPos(pos token.Pos)

func (*PosFilter) IsAlreadyReplaced

func (f *PosFilter) IsAlreadyReplaced(fset *token.FileSet, pos, end token.Pos) bool

func (*PosFilter) IsFiltered

func (f *PosFilter) IsFiltered(pos token.Pos) bool

type Report

type Report struct {
	// contains filtered or unexported fields
}

func (*Report) ToDiagReport

func (r *Report) ToDiagReport() analysis.Diagnostic

type Result

type Result struct {
	From string
	To   string
}

Result contains source code (from) and suggested change (to)

func Process

func Process(info *types.Info, filter *PosFilter, n ast.Node, cfg *Config) (*Result, error)

func (*Result) Skipped

func (r *Result) Skipped() bool

Directories

Path Synopsis
cmd
protogetter command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL