Skip to content

Commit

Permalink
Upgrade dependency to Go 1.22; add check for errors.As and basic chec…
Browse files Browse the repository at this point in the history
…k for ZST pointer receivers

Signed-off-by: Oliver Eikemeier <[email protected]>
  • Loading branch information
eikemeier committed Sep 2, 2024
1 parent 0ab2d38 commit 3a9780e
Show file tree
Hide file tree
Showing 25 changed files with 491 additions and 253 deletions.
2 changes: 2 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ checks:
enabled: false
identical-code:
enabled: false
return-statements:
enabled: false
exclude_patterns:
- "**/.*"
- "**/*_test.go"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
go: ["1.23", "1.22", "1.21"]
go: ["1.23", "1.22"]
env:
GOTOOLCHAIN: local
steps:
Expand All @@ -32,7 +32,7 @@ jobs:
- name: 🧸 golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.60.1
version: v1.60.3
- name: 🔨 Test
run: |
go get -C ./pkg/analyzer/testdata golang.org/x/exp/errors
Expand Down
4 changes: 1 addition & 3 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ linters:
disable:
# deprecated
- execinquery
- exportloopref
- gomnd
# disabled
- depguard
Expand All @@ -16,9 +17,6 @@ linters:
- varnamelen
- wrapcheck
- wsl
# Go 1.22
- copyloopvar
- intrange
linters-settings:
govet:
enable-all: true
Expand Down
6 changes: 6 additions & 0 deletions .prettierrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ overrides:
- files: "*.md"
options:
tabWidth: 2
- files: "*.yaml"
options:
tabWidth: 2
- files: "*.yml"
options:
tabWidth: 2
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![Go Report Card](https://goreportcard.com/badge/fillmore-labs.com/zerolint)](https://goreportcard.com/report/fillmore-labs.com/zerolint)
[![License](https://img.shields.io/github/license/fillmore-labs/zerolint)](https://www.apache.org/licenses/LICENSE-2.0)

The `zerolint` linter checks usage patterns of pointers to zero-sized variables in Go.
The `zerolint` linter checks usage patterns of pointers to zero-size variables in Go.

## Usage

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module fillmore-labs.com/zerolint

go 1.21
go 1.22

toolchain go1.23.0

Expand Down
22 changes: 16 additions & 6 deletions pkg/analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const (
Doc = `checks for usage of pointers to zero-length variables
Pointer to zero-length variables carry very little information and
can be avoided in most cases.`
can often be avoided.`
)

var Analyzer = &analysis.Analyzer{ //nolint:gochecknoglobals
Expand All @@ -44,19 +44,29 @@ func init() { //nolint:gochecknoinits
}

var (
// Excludes is a list of types to exclude from the analysis.
Excludes string //nolint:gochecknoglobals

// ZeroTrace enables tracing of found zero-sized types.
ZeroTrace bool //nolint:gochecknoglobals
Basic bool //nolint:gochecknoglobals

// Basic enables basic analysis only.
Basic bool //nolint:gochecknoglobals
)

// Run applies the analyzer to a package.
func run(pass *analysis.Pass) (any, error) {
excludes, err := ReadExcludes()
// Read the list of excluded types from the file specified by the "excluded" flag.
excludes, err := ReadExcludes(Excludes)
if err != nil {
return nil, err
}

v := visitor.Visitor{
Pass: pass,
Excludes: excludes,
v := visitor.Run{
Visitor: visitor.Visitor{
Pass: pass,
Excludes: excludes,
},
ZeroTrace: ZeroTrace,
Basic: Basic,
}
Expand Down
13 changes: 7 additions & 6 deletions pkg/analyzer/excludes.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,19 @@ package analyzer
import (
"bufio"
"os"
)

var Excludes string //nolint:gochecknoglobals
"fillmore-labs.com/zerolint/pkg/set"
)

func ReadExcludes() (map[string]struct{}, error) {
excludes := make(map[string]struct{})
// ReadExcludes reads zero-sized types excluded from analysis from a file and returns them as a set.
func ReadExcludes(name string) (set.Set[string], error) {
excludes := set.New[string]()

if Excludes == "" {
return excludes, nil
}

file, err := os.Open(Excludes)
file, err := os.Open(name)
if err != nil {
return nil, err
}
Expand All @@ -42,7 +43,7 @@ func ReadExcludes() (map[string]struct{}, error) {
if len(expr) == 0 || expr[0] == '#' {
continue
}
excludes[string(expr)] = struct{}{}
excludes.Insert(string(expr))
}
if err2 := scanner.Err(); err2 != nil {
return nil, err2
Expand Down
31 changes: 16 additions & 15 deletions pkg/analyzer/testdata/a/testdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ type typedError[T any] struct {
_ [0]T
}

func (*typedError[_]) Error() string { // want "pointer to zero-size type"
func (*typedError[_]) Error() string { // want "pointer to zero-sized type"
return "an error"
}

var (
_ error = &typedError[any]{} // want "address of zero-size variable"
ErrOne = &(typedError[int]{}) // want "address of zero-size variable"
ErrTwo = (new)(typedError[float64]) // want "new called on zero-size type"
ErrTwo = (new)(typedError[float64]) // want "new called on zero-sized type"
)

type myErrors struct{}
Expand All @@ -55,6 +55,11 @@ func Exported() {
fmt.Println("nil")
}

var oneErr *typedError[int] // want "pointer to zero-sized type"
if errors.As(ErrOne, &oneErr) {
fmt.Println("ErrOne is typedError[int]")
}

func() {
errors := myErrs
if errors.Is(ErrOne, ErrTwo) {
Expand All @@ -68,12 +73,12 @@ func Exported() {
fmt.Println("equal")
}

var err *typedError[int] // want "pointer to zero-size type"
var err *typedError[int] // want "pointer to zero-sized type"
_ = errors.As(ErrOne, &err)

_ = (new)(struct{}) // want "new called on zero-size type"
_ = (new)(struct{}) // want "new called on zero-sized type"

_ = new(empty) // want "new called on zero-size type"
_ = new(empty) // want "new called on zero-sized type"

xp, yp := &x, &y // want "address of zero-size variable" "address of zero-size variable"

Expand All @@ -87,14 +92,10 @@ func Exported() {
fmt.Println("not equal")
}

if xp == nil {
fmt.Println("nil")
}

_, _ = any(xp).((*[0]string)) // want "pointer to zero-size type"
_, _ = any(xp).((*[0]string)) // want "pointer to zero-sized type"

switch any(xp).(type) {
case (*[0]string): // want "pointer to zero-size type"
case (*[0]string): // want "pointer to zero-sized type"
case string:
}
}
Expand All @@ -113,15 +114,15 @@ type A [0]string

type B = A

func (*B) Combine(_ *B) *B { // want "pointer to zero-size type" "pointer to zero-size type" "pointer to zero-size type"
func (*B) Combine(_ *B) *B { // want "pointer to zero-sized type" "pointer to zero-sized type" "pointer to zero-sized type"
return &B{} // want "address of zero-size variable"
}

func Ptr[T any](v T) *T { return &v }

type greeter [5][5]struct{}

type greeterAlias = *greeter // want "pointer to zero-size type"
type greeterAlias = *greeter // want "pointer to zero-sized type"

func (g greeterAlias) String() string {
return "hello, world"
Expand All @@ -131,11 +132,11 @@ var _ fmt.Stringer = &greeter{} // want "address of zero-size variable"

var _ fmt.Stringer = (*greeter)(nil) // want "cast of nil to pointer to zero-size variable"

var _ fmt.Stringer = new(greeter) // want "new called on zero-size type"
var _ fmt.Stringer = new(greeter) // want "new called on zero-sized type"

type greeter2[T any] [5][5][0]T

func (g *greeter2[T]) String() string { // want "pointer to zero-size type"
func (g *greeter2[T]) String() string { // want "pointer to zero-sized type"
return "hello, world"
}

Expand Down
31 changes: 16 additions & 15 deletions pkg/analyzer/testdata/a/testdata.go.golden
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ type typedError[T any] struct {
_ [0]T
}

func (typedError[_]) Error() string { // want "pointer to zero-size type"
func (typedError[_]) Error() string { // want "pointer to zero-sized type"
return "an error"
}

var (
_ error = typedError[any]{} // want "address of zero-size variable"
ErrOne = (typedError[int]{}) // want "address of zero-size variable"
ErrTwo = typedError[float64]{} // want "new called on zero-size type"
ErrTwo = typedError[float64]{} // want "new called on zero-sized type"
)

type myErrors struct{}
Expand All @@ -55,6 +55,11 @@ func Exported() {
fmt.Println("nil")
}

var oneErr typedError[int] // want "pointer to zero-sized type"
if errors.As(ErrOne, &oneErr) {
fmt.Println("ErrOne is typedError[int]")
}

func() {
errors := myErrs
if errors.Is(ErrOne, ErrTwo) {
Expand All @@ -68,12 +73,12 @@ func Exported() {
fmt.Println("equal")
}

var err typedError[int] // want "pointer to zero-size type"
var err typedError[int] // want "pointer to zero-sized type"
_ = errors.As(ErrOne, &err)

_ = struct{}{} // want "new called on zero-size type"
_ = struct{}{} // want "new called on zero-sized type"

_ = empty{} // want "new called on zero-size type"
_ = empty{} // want "new called on zero-sized type"

xp, yp := x, y // want "address of zero-size variable" "address of zero-size variable"

Expand All @@ -87,14 +92,10 @@ func Exported() {
fmt.Println("not equal")
}

if xp == nil {
fmt.Println("nil")
}

_, _ = any(xp).(([0]string)) // want "pointer to zero-size type"
_, _ = any(xp).(([0]string)) // want "pointer to zero-sized type"

switch any(xp).(type) {
case ([0]string): // want "pointer to zero-size type"
case ([0]string): // want "pointer to zero-sized type"
case string:
}
}
Expand All @@ -113,15 +114,15 @@ type A [0]string

type B = A

func (B) Combine(_ B) B { // want "pointer to zero-size type" "pointer to zero-size type" "pointer to zero-size type"
func (B) Combine(_ B) B { // want "pointer to zero-sized type" "pointer to zero-sized type" "pointer to zero-sized type"
return B{} // want "address of zero-size variable"
}

func Ptr[T any](v T) *T { return &v }

type greeter [5][5]struct{}

type greeterAlias = greeter // want "pointer to zero-size type"
type greeterAlias = greeter // want "pointer to zero-sized type"

func (g greeterAlias) String() string {
return "hello, world"
Expand All @@ -131,11 +132,11 @@ var _ fmt.Stringer = greeter{} // want "address of zero-size variable"

var _ fmt.Stringer = greeter{} // want "cast of nil to pointer to zero-size variable"

var _ fmt.Stringer = greeter{} // want "new called on zero-size type"
var _ fmt.Stringer = greeter{} // want "new called on zero-sized type"

type greeter2[T any] [5][5][0]T

func (g greeter2[T]) String() string { // want "pointer to zero-size type"
func (g greeter2[T]) String() string { // want "pointer to zero-sized type"
return "hello, world"
}

Expand Down
18 changes: 13 additions & 5 deletions pkg/analyzer/testdata/basic/testdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ import (
"fmt"
)

type nyError struct{}
type myError struct{}

func (*nyError) Error() string {
func (*myError) Error() string { // want "method receiver is pointer to zero-size variable"
return "my error"
}

var (
ErrOne = &nyError{}
ErrTwo = new(nyError)
ErrOne = &myError{}
ErrTwo = new(myError)
)

func Exported() {
Expand All @@ -43,7 +43,7 @@ func Exported() {
fmt.Println("equal")
}

var err *nyError
var err *myError
_ = errors.As(ErrOne, &err)

if ErrOne == ErrTwo { // want "comparison of pointers to zero-size variables"
Expand All @@ -54,3 +54,11 @@ func Exported() {
fmt.Println("not equal")
}
}

type D struct{ _ int }

func (*D) String() string {
return "hello, world"
}

var _ fmt.Stringer = (*D)(nil)
4 changes: 2 additions & 2 deletions pkg/analyzer/testdata/go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module go.test

go 1.21
go 1.22

require golang.org/x/exp/errors v0.0.0-20240719175910-8a7402abbf56
require golang.org/x/exp/errors v0.0.0-20240823005443-9b4947da3948
4 changes: 2 additions & 2 deletions pkg/analyzer/testdata/go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
golang.org/x/exp/errors v0.0.0-20240719175910-8a7402abbf56 h1:wWtjcEP22Momq1fphl8WkZCnFX615H/yPDX494o7PtU=
golang.org/x/exp/errors v0.0.0-20240719175910-8a7402abbf56/go.mod h1:YgqsNsAu4fTvlab/7uiYK9LJrCIzKg/NiZUIH1/ayqo=
golang.org/x/exp/errors v0.0.0-20240823005443-9b4947da3948 h1:IE9ZGXGK0A3EhE/vajvqwjYT5JsrZfxtVwBflW/O2vU=
golang.org/x/exp/errors v0.0.0-20240823005443-9b4947da3948/go.mod h1:YgqsNsAu4fTvlab/7uiYK9LJrCIzKg/NiZUIH1/ayqo=
Loading

0 comments on commit 3a9780e

Please sign in to comment.