Skip to content

Repository files navigation

recvcheck

Build StatusGo Report CardCoverage StatusGo Reference

Go linter that detects mixing pointer and value method receivers.

Why

Mixing pointer and value receivers on the same type creates subtle, hard-to-detect bugs that can cause:

🐛 Data Races

When you copy a struct with a mutex, you copy the mutex state, leading to race conditions:

typeRPCstruct {
mu sync.Mutex// This is the problem!resultintdonechanstruct{}
}
func (rpc*RPC) compute() {
rpc.mu.Lock()
deferrpc.mu.Unlock()
rpc.result=42
}
func (RPC) version() int { // Value receiver copies the mutex!return1
}
funcmain() {
rpc:=&RPC{done: make(chanstruct{})}
gorpc.compute() // Locks original mutexversion:=rpc.version() // Uses copied mutex - RACE!// ...
}

🚨 Silent Bugs

Value receivers create copies, so modifications are lost:

typeCounterstruct {
valueint
}
func (c*Counter) Increment() { c.value++ } // pointer receiverfunc (cCounter) Reset() { c.value=0 } // value receiver - NO EFFECT!

🤔 Developer Confusion

Mixed receivers make code behavior unpredictable and harder to reason about.

✅ The Solution

Consistency is key: Go's official guidance says Don't mix receiver types. Choose either pointers or values for all methods on a type.

recvcheck automatically detects these issues before they reach production.

Installation

# Standalone
go install github.com/raeperd/recvcheck/cmd/recvcheck@latest
# With golangci-lint (recommended)# Add to .golangci.yml:
linters:
enable:
- recvcheck

Usage

recvcheck ./...
# or
golangci-lint run

Output:

main.go:8:1: the methods of "RPC" use pointer receiver and non-pointer receiver

Configuration

# .golangci.ymllinters-settings:
recvcheck:
# Disable default exclusions (MarshalJSON, etc.)disable-builtin: false# Custom exclusionsexclusions:
- "Server.Shutdown"# Specific method
- "*.String"# All String methods

Default Exclusions

Unmarshal methods are excluded by default as they must use pointer receivers:

  • *.UnmarshalText, *.UnmarshalJSON, *.UnmarshalYAML
  • *.UnmarshalXML, *.UnmarshalBinary, *.GobDecode

Examples

Bad - Mixed receivers:

func (u*User) SetName(namestring) { } // pointerfunc (uUser) GetName() string { } // value - inconsistent!

Good - Consistent receivers:

func (u*User) SetName(namestring) { } // pointerfunc (u*User) GetName() string { } // pointer - consistent!

Contributing

make test# Run tests
make lint # Run linter
make build # Build binary

License

MIT

About

Golang linter checks for receiver type consistency

Resources

Stars

13 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages