Skip to content

Commit e23fcdb

Browse files
authored
refactor: modifies linting machinery to use Failure as a mean to signal erros in rules application (#1178)
1 parent f6a3820 commit e23fcdb

File tree

7 files changed

+50
-22
lines changed

7 files changed

+50
-22
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/olekukonko/tablewriter v0.0.5
1414
github.com/spf13/afero v1.11.0
1515
golang.org/x/mod v0.22.0
16+
golang.org/x/sync v0.10.0
1617
golang.org/x/tools v0.28.0
1718
)
1819

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
4242
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
4343
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
4444
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
45+
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
46+
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
4547
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4648
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4749
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=

lint/failure.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,18 @@ type Failure struct {
3737
func (f *Failure) GetFilename() string {
3838
return f.Position.Start.Filename
3939
}
40+
41+
const internalFailure = "REVIVE_INTERNAL"
42+
43+
// IsInternal returns true if this failure is internal, false otherwise.
44+
func (f *Failure) IsInternal() bool {
45+
return f.Category == internalFailure
46+
}
47+
48+
// NewInternalFailure yields an internal failure with the given message as failure message.
49+
func NewInternalFailure(message string) Failure {
50+
return Failure{
51+
Category: internalFailure,
52+
Failure: message,
53+
}
54+
}

lint/file.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package lint
22

33
import (
44
"bytes"
5+
"errors"
56
"go/ast"
67
"go/parser"
78
"go/printer"
@@ -96,7 +97,7 @@ func (f *File) isMain() bool {
9697

9798
const directiveSpecifyDisableReason = "specify-disable-reason"
9899

99-
func (f *File) lint(rules []Rule, config Config, failures chan Failure) {
100+
func (f *File) lint(rules []Rule, config Config, failures chan Failure) error {
100101
rulesConfig := config.Rules
101102
_, mustSpecifyDisableReason := config.Directives[directiveSpecifyDisableReason]
102103
disabledIntervals := f.disabledIntervals(rules, mustSpecifyDisableReason, failures)
@@ -107,6 +108,10 @@ func (f *File) lint(rules []Rule, config Config, failures chan Failure) {
107108
}
108109
currentFailures := currentRule.Apply(f, ruleConfig.Arguments)
109110
for idx, failure := range currentFailures {
111+
if failure.IsInternal() {
112+
return errors.New(failure.Failure)
113+
}
114+
110115
if failure.RuleName == "" {
111116
failure.RuleName = currentRule.Name()
112117
}
@@ -122,6 +127,7 @@ func (f *File) lint(rules []Rule, config Config, failures chan Failure) {
122127
}
123128
}
124129
}
130+
return nil
125131
}
126132

127133
type enableDisableConfig struct {

lint/linter.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,7 @@ func (l *Linter) lintPackage(filenames []string, gover *goversion.Version, ruleS
152152
return nil
153153
}
154154

155-
pkg.lint(ruleSet, config, failures)
156-
157-
return nil
155+
return pkg.lint(ruleSet, config, failures)
158156
}
159157

160158
func detectGoMod(dir string) (rootDir string, ver *goversion.Version, err error) {

lint/package.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"sync"
1010

1111
goversion "github.com/hashicorp/go-version"
12+
"golang.org/x/sync/errgroup"
1213

1314
"github.com/mgechev/revive/internal/astutils"
1415
"github.com/mgechev/revive/internal/typeparams"
@@ -181,17 +182,16 @@ func (p *Package) scanSortable() {
181182
}
182183
}
183184

184-
func (p *Package) lint(rules []Rule, config Config, failures chan Failure) {
185+
func (p *Package) lint(rules []Rule, config Config, failures chan Failure) error {
185186
p.scanSortable()
186-
var wg sync.WaitGroup
187+
var eg errgroup.Group
187188
for _, file := range p.files {
188-
wg.Add(1)
189-
go (func(file *File) {
190-
file.lint(rules, config, failures)
191-
wg.Done()
192-
})(file)
189+
eg.Go(func() error {
190+
return file.lint(rules, config, failures)
191+
})
193192
}
194-
wg.Wait()
193+
194+
return eg.Wait()
195195
}
196196

197197
// IsAtLeastGo121 returns true if the Go version for this package is 1.21 or higher, false otherwise

rule/add_constant.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ type AddConstantRule struct {
4242

4343
// Apply applies the rule to given file.
4444
func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
45-
r.configureOnce.Do(func() { r.configure(arguments) })
45+
var configureErr error
46+
r.configureOnce.Do(func() { configureErr = r.configure(arguments) })
47+
if configureErr != nil {
48+
return []lint.Failure{lint.NewInternalFailure(configureErr.Error())}
49+
}
4650

4751
var failures []lint.Failure
4852

@@ -201,15 +205,15 @@ func (w *lintAddConstantRule) isStructTag(n *ast.BasicLit) bool {
201205
return ok
202206
}
203207

204-
func (r *AddConstantRule) configure(arguments lint.Arguments) {
208+
func (r *AddConstantRule) configure(arguments lint.Arguments) error {
205209
r.strLitLimit = defaultStrLitLimit
206210
r.allowList = newAllowList()
207211
if len(arguments) == 0 {
208-
return
212+
return nil
209213
}
210214
args, ok := arguments[0].(map[string]any)
211215
if !ok {
212-
panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting a k,v map. Got %T", arguments[0]))
216+
return fmt.Errorf("invalid argument to the add-constant rule, expecting a k,v map. Got %T", arguments[0])
213217
}
214218
for k, v := range args {
215219
kind := ""
@@ -228,39 +232,41 @@ func (r *AddConstantRule) configure(arguments lint.Arguments) {
228232
}
229233
list, ok := v.(string)
230234
if !ok {
231-
panic(fmt.Sprintf("Invalid argument to the add-constant rule, string expected. Got '%v' (%T)", v, v))
235+
fmt.Errorf("invalid argument to the add-constant rule, string expected. Got '%v' (%T)", v, v)
232236
}
233237
r.allowList.add(kind, list)
234238
case "maxLitCount":
235239
sl, ok := v.(string)
236240
if !ok {
237-
panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v' (%T)", v, v))
241+
fmt.Errorf("invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v' (%T)", v, v)
238242
}
239243

240244
limit, err := strconv.Atoi(sl)
241245
if err != nil {
242-
panic(fmt.Sprintf("Invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v'", v))
246+
fmt.Errorf("invalid argument to the add-constant rule, expecting string representation of an integer. Got '%v'", v)
243247
}
244248
r.strLitLimit = limit
245249
case "ignoreFuncs":
246250
excludes, ok := v.(string)
247251
if !ok {
248-
panic(fmt.Sprintf("Invalid argument to the ignoreFuncs parameter of add-constant rule, string expected. Got '%v' (%T)", v, v))
252+
fmt.Errorf("invalid argument to the ignoreFuncs parameter of add-constant rule, string expected. Got '%v' (%T)", v, v)
249253
}
250254

251255
for _, exclude := range strings.Split(excludes, ",") {
252256
exclude = strings.Trim(exclude, " ")
253257
if exclude == "" {
254-
panic("Invalid argument to the ignoreFuncs parameter of add-constant rule, expected regular expression must not be empty.")
258+
fmt.Errorf("invalid argument to the ignoreFuncs parameter of add-constant rule, expected regular expression must not be empty.")
255259
}
256260

257261
exp, err := regexp.Compile(exclude)
258262
if err != nil {
259-
panic(fmt.Sprintf("Invalid argument to the ignoreFuncs parameter of add-constant rule: regexp %q does not compile: %v", exclude, err))
263+
fmt.Errorf("invalid argument to the ignoreFuncs parameter of add-constant rule: regexp %q does not compile: %v", exclude, err)
260264
}
261265

262266
r.ignoreFunctions = append(r.ignoreFunctions, exp)
263267
}
264268
}
265269
}
270+
271+
return nil
266272
}

0 commit comments

Comments
 (0)