Skip to content

Commit 298450d

Browse files
committed
Move package to internal; minor refactoring; add tests
Signed-off-by: Oliver Eikemeier <[email protected]>
1 parent b596aae commit 298450d

37 files changed

+991
-401
lines changed

.github/workflows/test.yml

+10-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ name: Test
99
- main
1010
jobs:
1111
test:
12-
name: Test on Go ${{ matrix.go }}
12+
name: Test on Go ${{ matrix.go-version }}
1313
permissions:
1414
checks: write
1515
contents: read
@@ -18,26 +18,30 @@ jobs:
1818
runs-on: ubuntu-24.04
1919
strategy:
2020
matrix:
21-
go: ["1.23.3", "1.22.9"]
21+
go-version: ["1.24.0-rc.3", "1.23.6", "1.22.12"]
22+
include:
23+
- go-version: "1.23.6"
24+
update-coverage: true
2225
env:
2326
GOTOOLCHAIN: local
2427
steps:
2528
- name: ✔ Check out
2629
uses: actions/checkout@v4
27-
- name: 🐹 Set up Go ${{ matrix.go }}
30+
- name: 🐹 Set up Go ${{ matrix.go-version }}
2831
uses: actions/setup-go@v5
2932
with:
30-
go-version: ${{ matrix.go }}
33+
go-version: ${{ matrix.go-version }}
3134
- name: 🧸 golangci-lint
3235
uses: golangci/golangci-lint-action@v6
3336
with:
34-
version: v1.62.0
37+
version: v1.63.4
3538
- name: 🔨 Test
3639
run: |
3740
go get -C ./pkg/analyzer/testdata golang.org/x/exp/errors
3841
go test -coverprofile=cover.out ./...
3942
- name: 🧑🏻‍💻 codecov
40-
uses: codecov/codecov-action@v4
43+
uses: codecov/codecov-action@v5
44+
if: ${{ matrix.update-coverage }}
4145
with:
4246
files: ./cover.out
4347
token: ${{ secrets.CODECOV_TOKEN }}

go.mod

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
module fillmore-labs.com/zerolint
22

3-
go 1.22.9
3+
go 1.22.0
44

5-
toolchain go1.23.3
5+
toolchain go1.23.6
66

7-
require golang.org/x/tools v0.27.0
7+
require golang.org/x/tools v0.29.0
88

99
require (
10-
golang.org/x/mod v0.22.0 // indirect
11-
golang.org/x/sync v0.9.0 // indirect
10+
golang.org/x/mod v0.23.0 // indirect
11+
golang.org/x/sync v0.11.0 // indirect
1212
)

go.sum

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
22
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
3-
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
4-
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
5-
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
6-
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
7-
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
8-
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
3+
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
4+
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
5+
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
6+
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
7+
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
8+
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=

pkg/analyzer/analyzer.go

+9-15
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package analyzer
1818

1919
import (
20-
"fillmore-labs.com/zerolint/pkg/visitor"
20+
"fillmore-labs.com/zerolint/pkg/internal/excludes"
2121
"golang.org/x/tools/go/analysis"
2222
"golang.org/x/tools/go/analysis/passes/inspect"
2323
)
@@ -59,24 +59,18 @@ var (
5959
Generated bool //nolint:gochecknoglobals
6060
)
6161

62-
// Run applies the analyzer to a package.
62+
// run applies the analyzer to a package.
6363
func run(pass *analysis.Pass) (any, error) {
6464
// Read the list of excluded types from the file specified by the "excluded" flag.
65-
excludes, err := ReadExcludes(Excludes)
65+
ex, err := excludes.ReadExcludes(osFS{}, Excludes)
6666
if err != nil {
6767
return nil, err
6868
}
6969

70-
v := visitor.Run{
71-
Visitor: visitor.Visitor{
72-
Pass: pass,
73-
Excludes: excludes,
74-
},
75-
ZeroTrace: ZeroTrace,
76-
Basic: Basic,
77-
Generated: Generated,
78-
}
79-
v.Run()
80-
81-
return any(nil), nil
70+
return NewRun(
71+
WithExcludes(ex),
72+
WithZeroTrace(ZeroTrace),
73+
WithBasic(Basic),
74+
WithGenerated(Generated),
75+
)(pass)
8276
}

pkg/analyzer/analyzer_test.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,18 @@ func TestAnalyzer(t *testing.T) { //nolint:paralleltest
2727
dir := analysistest.TestData()
2828
a := analyzer.Analyzer
2929

30-
analyzer.Basic = true
31-
analysistest.RunWithSuggestedFixes(t, dir, a, "go.test/basic")
32-
3330
analyzer.Basic = false
3431
analyzer.Excludes = dir + "/excluded.txt"
32+
3533
analysistest.RunWithSuggestedFixes(t, dir, a, "go.test/a")
3634
}
35+
36+
func TestAnalyzerBasic(t *testing.T) { //nolint:paralleltest
37+
dir := analysistest.TestData()
38+
a := analyzer.Analyzer
39+
40+
analyzer.Basic = true
41+
analyzer.Excludes = ""
42+
43+
analysistest.RunWithSuggestedFixes(t, dir, a, "go.test/basic")
44+
}

pkg/analyzer/osfs.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2024 Oliver Eikemeier. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
package analyzer
18+
19+
import (
20+
"io/fs"
21+
"os"
22+
)
23+
24+
type osFS struct{}
25+
26+
var _ fs.FS = osFS{}
27+
28+
func (osFS) Open(name string) (fs.File, error) {
29+
return os.Open(name)
30+
}

pkg/analyzer/run.go

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright 2024 Oliver Eikemeier. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
package analyzer
18+
19+
import (
20+
"log"
21+
22+
"fillmore-labs.com/zerolint/pkg/internal/set"
23+
"fillmore-labs.com/zerolint/pkg/internal/visitor"
24+
"golang.org/x/tools/go/analysis"
25+
)
26+
27+
// NewRun returns a configurable function for the Run field of [Analyzer].
28+
func NewRun(opts ...Option) func(*analysis.Pass) (any, error) {
29+
option := options{
30+
logger: log.Default(),
31+
}
32+
for _, opt := range opts {
33+
opt.apply(&option)
34+
}
35+
36+
return func(pass *analysis.Pass) (any, error) {
37+
visitor.Run(
38+
option.logger,
39+
visitor.Visitor{
40+
Pass: pass,
41+
Excludes: option.excludes,
42+
},
43+
option.zeroTrace,
44+
option.basic,
45+
option.generated,
46+
)
47+
48+
return any(nil), nil
49+
}
50+
}
51+
52+
// options defines configurable parameters for the linter.
53+
type options struct {
54+
logger *log.Logger
55+
excludes set.Set[string]
56+
zeroTrace bool
57+
basic bool
58+
generated bool
59+
}
60+
61+
// Option defines configurations for [NewRun].
62+
type Option interface {
63+
apply(opts *options)
64+
}
65+
66+
// WithLogger is an [Option] to configure the used logger.
67+
func WithLogger(logger *log.Logger) Option { //nolint:ireturn
68+
return loggerOption{logger: logger}
69+
}
70+
71+
type loggerOption struct {
72+
logger *log.Logger
73+
}
74+
75+
func (o loggerOption) apply(opts *options) {
76+
opts.logger = o.logger
77+
}
78+
79+
// WithExcludes is an [Option] to configure the excluded types.
80+
func WithExcludes(excludes []string) Option { //nolint:ireturn
81+
return excludesOption{excludes: excludes}
82+
}
83+
84+
type excludesOption struct {
85+
excludes []string
86+
}
87+
88+
func (o excludesOption) apply(opts *options) {
89+
if opts.excludes == nil {
90+
opts.excludes = set.New[string]()
91+
}
92+
for _, exclude := range o.excludes {
93+
opts.excludes.Insert(exclude)
94+
}
95+
}
96+
97+
// WithZeroTrace is an [Option] to configure tracing of zero sized types.
98+
func WithZeroTrace(zeroTrace bool) Option { //nolint:ireturn
99+
return zeroTraceOption{zeroTrace: zeroTrace}
100+
}
101+
102+
type zeroTraceOption struct {
103+
zeroTrace bool
104+
}
105+
106+
func (o zeroTraceOption) apply(opts *options) {
107+
opts.zeroTrace = o.zeroTrace
108+
}
109+
110+
// WithBasic is an [Option] to configure only basic linting.
111+
func WithBasic(basic bool) Option { //nolint:ireturn
112+
return basicOption{basic: basic}
113+
}
114+
115+
type basicOption struct {
116+
basic bool
117+
}
118+
119+
func (o basicOption) apply(opts *options) {
120+
opts.basic = o.basic
121+
}
122+
123+
// WithGenerated is an [Option] to configure linting of generated files.
124+
func WithGenerated(generated bool) Option { //nolint:ireturn
125+
return generatedOption{generated: generated}
126+
}
127+
128+
type generatedOption struct {
129+
generated bool
130+
}
131+
132+
func (o generatedOption) apply(opts *options) {
133+
opts.generated = o.generated
134+
}

pkg/analyzer/testdata/a/errors.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2024 Oliver Eikemeier. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
package a
18+
19+
import (
20+
"errors"
21+
"fmt"
22+
23+
xerrors "golang.org/x/exp/errors"
24+
)
25+
26+
type empty struct{}
27+
28+
type myErrors struct{}
29+
30+
func (myErrors) Is(_, _ error) bool {
31+
return false
32+
}
33+
34+
var myErrs = myErrors{}
35+
36+
func IgnoreErrors() {
37+
if errors.Is(ErrOne, nil) {
38+
fmt.Println("nil")
39+
}
40+
41+
var oneErr *typedError[int] // want "pointer to zero-sized type"
42+
if errors.As(ErrOne, &oneErr) {
43+
fmt.Println("ErrOne is typedError[int]")
44+
}
45+
46+
func() {
47+
errors := myErrs
48+
if errors.Is(ErrOne, ErrTwo) {
49+
fmt.Println("one is two")
50+
}
51+
}()
52+
53+
if xerrors.Is(func() error { // want "comparison of pointer to zero-size variable"
54+
return ErrOne
55+
}(), ErrTwo) {
56+
fmt.Println("equal")
57+
}
58+
59+
var err *typedError[int] // want "pointer to zero-sized type"
60+
_ = errors.As(ErrOne, &err)
61+
}

0 commit comments

Comments
 (0)