Skip to content

Commit 69d6cc9

Browse files
alecthomasldez
andauthored
feat: add gochecksumtype linter (#3671)
Co-authored-by: Fernandez Ludovic <[email protected]>
1 parent 8c178d3 commit 69d6cc9

File tree

6 files changed

+131
-0
lines changed

6 files changed

+131
-0
lines changed

.golangci.reference.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2214,6 +2214,7 @@ linters:
22142214
- gocheckcompilerdirectives
22152215
- gochecknoglobals
22162216
- gochecknoinits
2217+
- gochecksumtype
22172218
- gocognit
22182219
- goconst
22192220
- gocritic
@@ -2330,6 +2331,7 @@ linters:
23302331
- gocheckcompilerdirectives
23312332
- gochecknoglobals
23322333
- gochecknoinits
2334+
- gochecksumtype
23332335
- gocognit
23342336
- goconst
23352337
- gocritic

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24
1515
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.1.0
1616
github.com/OpenPeeDeeP/depguard/v2 v2.1.0
17+
github.com/alecthomas/go-check-sumtype v0.1.3
1718
github.com/alexkohler/nakedret/v2 v2.0.2
1819
github.com/alexkohler/prealloc v1.0.0
1920
github.com/alingse/asasalint v0.0.11

go.sum

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/golinters/gochecksumtype.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package golinters
2+
3+
import (
4+
"strings"
5+
"sync"
6+
7+
gochecksumtype "github.com/alecthomas/go-check-sumtype"
8+
"golang.org/x/tools/go/analysis"
9+
"golang.org/x/tools/go/packages"
10+
11+
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
12+
"github.com/golangci/golangci-lint/pkg/lint/linter"
13+
"github.com/golangci/golangci-lint/pkg/result"
14+
)
15+
16+
const goCheckSumTypeName = "gochecksumtype"
17+
18+
func NewGoCheckSumType() *goanalysis.Linter {
19+
var mu sync.Mutex
20+
var resIssues []goanalysis.Issue
21+
22+
analyzer := &analysis.Analyzer{
23+
Name: goCheckSumTypeName,
24+
Doc: goanalysis.TheOnlyanalyzerDoc,
25+
Run: func(pass *analysis.Pass) (any, error) {
26+
issues, err := runGoCheckSumType(pass)
27+
if err != nil {
28+
return nil, err
29+
}
30+
31+
if len(issues) == 0 {
32+
return nil, nil
33+
}
34+
35+
mu.Lock()
36+
resIssues = append(resIssues, issues...)
37+
mu.Unlock()
38+
39+
return nil, nil
40+
},
41+
}
42+
43+
return goanalysis.NewLinter(
44+
goCheckSumTypeName,
45+
`Run exhaustiveness checks on Go "sum types"`,
46+
[]*analysis.Analyzer{analyzer},
47+
nil,
48+
).WithIssuesReporter(func(ctx *linter.Context) []goanalysis.Issue {
49+
return resIssues
50+
}).WithLoadMode(goanalysis.LoadModeTypesInfo)
51+
}
52+
53+
func runGoCheckSumType(pass *analysis.Pass) ([]goanalysis.Issue, error) {
54+
var resIssues []goanalysis.Issue
55+
56+
pkg := &packages.Package{
57+
Fset: pass.Fset,
58+
Syntax: pass.Files,
59+
Types: pass.Pkg,
60+
TypesInfo: pass.TypesInfo,
61+
}
62+
63+
var unknownError error
64+
errors := gochecksumtype.Run([]*packages.Package{pkg})
65+
for _, err := range errors {
66+
err, ok := err.(gochecksumtype.Error)
67+
if !ok {
68+
unknownError = err
69+
continue
70+
}
71+
72+
resIssues = append(resIssues, goanalysis.NewIssue(&result.Issue{
73+
FromLinter: goCheckSumTypeName,
74+
Text: strings.TrimPrefix(err.Error(), err.Pos().String()+": "),
75+
Pos: err.Pos(),
76+
}, pass))
77+
}
78+
79+
return resIssues, unknownError
80+
}

pkg/lint/lintersdb/manager.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
441441
WithSince("v1.12.0").
442442
WithPresets(linter.PresetStyle),
443443

444+
linter.NewConfig(golinters.NewGoCheckSumType()).
445+
WithSince("v1.55.0").
446+
WithPresets(linter.PresetBugs).
447+
WithLoadForGoAnalysis().
448+
WithURL("https://github.com/alecthomas/go-check-sumtype"),
449+
444450
linter.NewConfig(golinters.NewGocognit(gocognitCfg)).
445451
WithSince("v1.20.0").
446452
WithPresets(linter.PresetComplexity).

test/testdata/gochecksumtype.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//golangcitest:args -Egochecksumtype
2+
package testdata
3+
4+
import (
5+
"log"
6+
)
7+
8+
//sumtype:decl
9+
type SumType interface{ isSumType() }
10+
11+
//sumtype:decl
12+
type One struct{} // want "type 'One' is not an interface"
13+
14+
func (One) isSumType() {}
15+
16+
type Two struct{}
17+
18+
func (Two) isSumType() {}
19+
20+
func sumTypeTest() {
21+
var sum SumType = One{}
22+
switch sum.(type) { // want "exhaustiveness check failed for sum type.*SumType.*missing cases for Two"
23+
case One:
24+
}
25+
26+
switch sum.(type) { // want "exhaustiveness check failed for sum type.*SumType.*missing cases for Two"
27+
case One:
28+
default:
29+
panic("??")
30+
}
31+
32+
log.Println("??")
33+
34+
switch sum.(type) {
35+
case One:
36+
case Two:
37+
}
38+
}

0 commit comments

Comments
 (0)