Skip to content

Commit ec57966

Browse files
committed
Support GODEBUG=gotypesalias=1
Currently, the go/types.Type for a declared type alias is the same type as the that which it is aliased too. In Go 1.23, when GODEBUG=gotypesalias=1 is enabled by default, it is a go/types.Alias instead, which is a unique type node for aliases that points to the type it is aliased to via go/types.Unalias(). (see golang/go#63223 for more details). errcheck's tests do not currently fail with GODEBUG=gotypesalias=1, but that is because the tests themselves do not exercise the problematic situations, such as the following: ```go type t struct{} func (x t) a() error { /* ... */ } type embedt struct { t } type embedtalias = embedt func foo() { embedtalias.a() } ``` With GODEBUG=gotypesalias=1, errcheck will panic when inspecting `embedtalias.a()` to see if it should be excluded from checking: ``` panic: cannot get Field of a type that is not a struct, got _/home/user/go/src/github.com/kisielk/errcheck/errcheck/testdata/src/a.embedtalias (*types.Alias) goroutine 2962 [running]: github.com/kisielk/errcheck/errcheck.getTypeAtFieldIndex({0x7779c0?, 0xc002eceab0?}, 0x4c?) /home/user/go/src/github.com/kisielk/errcheck/errcheck/embedded_walker.go:96 +0xf9 github.com/kisielk/errcheck/errcheck.walkThroughEmbeddedInterfaces(0x6b83a0?) /home/user/go/src/github.com/kisielk/errcheck/errcheck/embedded_walker.go:53 +0x8e github.com/kisielk/errcheck/errcheck.(*visitor).namesForExcludeCheck(0xc0025eeff0, 0xc002596140?) /home/user/go/src/github.com/kisielk/errcheck/errcheck/errcheck.go:364 +0x165 github.com/kisielk/errcheck/errcheck.(*visitor).excludeCall(0xc0025eeff0, 0x4d?) /home/user/go/src/github.com/kisielk/errcheck/errcheck/errcheck.go:403 +0x72 github.com/kisielk/errcheck/errcheck.(*visitor).ignoreCall(0xc0025eeff0, 0xc002596140) /home/user/go/src/github.com/kisielk/errcheck/errcheck/errcheck.go:415 +0x2c github.com/kisielk/errcheck/errcheck.(*visitor).Visit(0xc0025eeff0, {0x776d48?, 0xc0066e08a0}) /home/user/go/src/github.com/kisielk/errcheck/errcheck/errcheck.go:564 +0x137 ``` This change uses `types.Unalias` to follow through this extra level of indirection, which fixes the panic and ensures the same behavior with both settings. This change also adds these cases to the test suite, and runs the tests using both settings of gotypesalias. Without the calls to `types.Unalias`, the tests fail.
1 parent b65821b commit ec57966

File tree

4 files changed

+50
-17
lines changed

4 files changed

+50
-17
lines changed

errcheck/analyzer_test.go

+27-16
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,33 @@ import (
88
)
99

1010
func TestAnalyzer(t *testing.T) {
11-
t.Run("default flags", func(t *testing.T) {
12-
packageDir := filepath.Join(analysistest.TestData(), "src/a/")
13-
_ = analysistest.Run(t, packageDir, Analyzer)
14-
})
11+
// Test with and without the gotypesalias flag,
12+
// which will be set to 1 by default in Go 1.23.
13+
for _, tt := range []string{
14+
"gotypesalias=0",
15+
"gotypesalias=1",
16+
} {
17+
t.Run(tt, func(t *testing.T) {
18+
t.Setenv("GODEBUG", tt)
1519

16-
t.Run("check blanks", func(t *testing.T) {
17-
packageDir := filepath.Join(analysistest.TestData(), "src/blank/")
18-
_ = Analyzer.Flags.Set("blank", "true")
19-
_ = analysistest.Run(t, packageDir, Analyzer)
20-
_ = Analyzer.Flags.Set("blank", "false") // reset it
21-
})
20+
t.Run("default flags", func(t *testing.T) {
21+
packageDir := filepath.Join(analysistest.TestData(), "src/a/")
22+
_ = analysistest.Run(t, packageDir, Analyzer)
23+
})
2224

23-
t.Run("check asserts", func(t *testing.T) {
24-
packageDir := filepath.Join(analysistest.TestData(), "src/assert/")
25-
_ = Analyzer.Flags.Set("assert", "true")
26-
_ = analysistest.Run(t, packageDir, Analyzer)
27-
_ = Analyzer.Flags.Set("assert", "false") // reset it
28-
})
25+
t.Run("check blanks", func(t *testing.T) {
26+
packageDir := filepath.Join(analysistest.TestData(), "src/blank/")
27+
_ = Analyzer.Flags.Set("blank", "true")
28+
_ = analysistest.Run(t, packageDir, Analyzer)
29+
_ = Analyzer.Flags.Set("blank", "false") // reset it
30+
})
31+
32+
t.Run("check asserts", func(t *testing.T) {
33+
packageDir := filepath.Join(analysistest.TestData(), "src/assert/")
34+
_ = Analyzer.Flags.Set("assert", "true")
35+
_ = analysistest.Run(t, packageDir, Analyzer)
36+
_ = Analyzer.Flags.Set("assert", "false") // reset it
37+
})
38+
})
39+
}
2940
}

errcheck/embedded_walker.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ func walkThroughEmbeddedInterfaces(sel *types.Selection) ([]types.Type, bool) {
8484
}
8585

8686
func getTypeAtFieldIndex(startingAt types.Type, fieldIndex int) types.Type {
87-
t := maybeUnname(maybeDereference(startingAt))
87+
t := maybeDereference(types.Unalias(startingAt))
88+
t = maybeUnname(types.Unalias(t))
8889
s, ok := t.(*types.Struct)
8990
if !ok {
9091
panic(fmt.Sprintf("cannot get Field of a type that is not a struct, got a %T", t))

errcheck/testdata/src/a/main.go

+13
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ func main() {
105105
_ = x.a() // ok, assigned to blank
106106
x.a() // want "unchecked error"
107107

108+
// Methods on alias types and pointers to alias types
109+
x2 := embedtalias{}
110+
_ = x2.a() // ok, assigned to blank
111+
x2.a() // want "unchecked error"
112+
113+
x3 := &embedtalias{}
114+
_ = x3.a() // ok, assigned to blank
115+
x3.a() // want "unchecked error"
116+
117+
var x4 embedtptralias
118+
_ = x4.a() // ok, assigned to blank
119+
x4.a() // want "unchecked error"
120+
108121
// Method call on a struct member
109122
y := u{x}
110123
_ = y.t.a() // ok, assigned to blank

errcheck/testdata/src/a/t.go

+8
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,11 @@ func (x t) a() error {
1515
type u struct {
1616
t t
1717
}
18+
19+
type embedt struct {
20+
t
21+
}
22+
23+
type embedtalias = embedt
24+
25+
type embedtptralias = *embedt

0 commit comments

Comments
 (0)