Skip to content

Commit cd16050

Browse files
committed
refactor: Permit matching on full paths of allowed errors
1 parent ae40071 commit cd16050

File tree

3 files changed

+40
-42
lines changed

3 files changed

+40
-42
lines changed

errorlint/allowed.go

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ var allowedErrors = []struct {
3434
{err: "io.EOF", fun: "(*bytes.Reader).ReadRune"},
3535
{err: "io.EOF", fun: "(*bytes.Reader).ReadString"},
3636
// pkg/database/sql
37-
{err: "sql.ErrNoRows", fun: "(*database/sql.Row).Scan"},
37+
{err: "database/sql.ErrNoRows", fun: "(*database/sql.Row).Scan"},
3838
// pkg/debug/elf
39-
{err: "io.EOF", fun: "elf.Open"},
40-
{err: "io.EOF", fun: "elf.NewFile"},
39+
{err: "io.EOF", fun: "debug/elf.Open"},
40+
{err: "io.EOF", fun: "debug/elf.NewFile"},
4141
// pkg/io
4242
{err: "io.EOF", fun: "(io.Reader).Read"},
4343
{err: "io.EOF", fun: "(io.ReaderAt).ReadAt"},
@@ -50,14 +50,14 @@ var allowedErrors = []struct {
5050
{err: "io.EOF", fun: "io.ReadFull"},
5151
{err: "io.ErrUnexpectedEOF", fun: "io.ReadFull"},
5252
// pkg/net/http
53-
{err: "http.ErrServerClosed", fun: "(*net/http.Server).ListenAndServe"},
54-
{err: "http.ErrServerClosed", fun: "(*net/http.Server).ListenAndServeTLS"},
55-
{err: "http.ErrServerClosed", fun: "(*net/http.Server).Serve"},
56-
{err: "http.ErrServerClosed", fun: "(*net/http.Server).ServeTLS"},
57-
{err: "http.ErrServerClosed", fun: "http.ListenAndServe"},
58-
{err: "http.ErrServerClosed", fun: "http.ListenAndServeTLS"},
59-
{err: "http.ErrServerClosed", fun: "http.Serve"},
60-
{err: "http.ErrServerClosed", fun: "http.ServeTLS"},
53+
{err: "net/http.ErrServerClosed", fun: "(*net/http.Server).ListenAndServe"},
54+
{err: "net/http.ErrServerClosed", fun: "(*net/http.Server).ListenAndServeTLS"},
55+
{err: "net/http.ErrServerClosed", fun: "(*net/http.Server).Serve"},
56+
{err: "net/http.ErrServerClosed", fun: "(*net/http.Server).ServeTLS"},
57+
{err: "net/http.ErrServerClosed", fun: "net/http.ListenAndServe"},
58+
{err: "net/http.ErrServerClosed", fun: "net/http.ListenAndServeTLS"},
59+
{err: "net/http.ErrServerClosed", fun: "net/http.Serve"},
60+
{err: "net/http.ErrServerClosed", fun: "net/http.ServeTLS"},
6161
// pkg/os
6262
{err: "io.EOF", fun: "(*os.File).Read"},
6363
{err: "io.EOF", fun: "(*os.File).ReadAt"},
@@ -80,7 +80,7 @@ func isAllowedErrAndFunc(err, fun string) bool {
8080
return false
8181
}
8282

83-
func isAllowedErrorComparison(info *TypesInfoExt, binExpr *ast.BinaryExpr) bool {
83+
func isAllowedErrorComparison(pass *TypesInfoExt, binExpr *ast.BinaryExpr) bool {
8484
var errName string // `<package>.<name>`, e.g. `io.EOF`
8585
var callExprs []*ast.CallExpr
8686

@@ -91,11 +91,11 @@ func isAllowedErrorComparison(info *TypesInfoExt, binExpr *ast.BinaryExpr) bool
9191
case *ast.SelectorExpr:
9292
// A selector which we assume refers to a staticaly declared error
9393
// in a package.
94-
errName = selectorToString(t)
94+
errName = selectorToString(pass, t)
9595
case *ast.Ident:
9696
// Identifier, most likely to be the `err` variable or whatever
9797
// produces it.
98-
callExprs = assigningCallExprs(info, t)
98+
callExprs = assigningCallExprs(pass, t)
9999
case *ast.CallExpr:
100100
callExprs = append(callExprs, t)
101101
}
@@ -115,11 +115,11 @@ func isAllowedErrorComparison(info *TypesInfoExt, binExpr *ast.BinaryExpr) bool
115115
// allowed.
116116
return false
117117
}
118-
if sel, ok := info.Selections[functionSelector]; ok {
118+
if sel, ok := pass.TypesInfo.Selections[functionSelector]; ok {
119119
functionNames[i] = fmt.Sprintf("(%s).%s", sel.Recv(), sel.Obj().Name())
120120
} else {
121121
// If there is no selection, assume it is a package.
122-
functionNames[i] = selectorToString(callExpr.Fun.(*ast.SelectorExpr))
122+
functionNames[i] = selectorToString(pass, callExpr.Fun.(*ast.SelectorExpr))
123123
}
124124
}
125125

@@ -134,17 +134,17 @@ func isAllowedErrorComparison(info *TypesInfoExt, binExpr *ast.BinaryExpr) bool
134134

135135
// assigningCallExprs finds all *ast.CallExpr nodes that are part of an
136136
// *ast.AssignStmt that assign to the subject identifier.
137-
func assigningCallExprs(info *TypesInfoExt, subject *ast.Ident) []*ast.CallExpr {
137+
func assigningCallExprs(pass *TypesInfoExt, subject *ast.Ident) []*ast.CallExpr {
138138
if subject.Obj == nil {
139139
return nil
140140
}
141141

142142
// Find other identifiers that reference this same object. Make sure to
143143
// exclude the subject identifier as it will cause an infinite recursion
144144
// and is being used in a read operation anyway.
145-
sobj := info.ObjectOf(subject)
145+
sobj := pass.TypesInfo.ObjectOf(subject)
146146
identifiers := []*ast.Ident{}
147-
for _, ident := range info.IdentifiersForObject[sobj] {
147+
for _, ident := range pass.IdentifiersForObject[sobj] {
148148
if subject.Pos() != ident.Pos() {
149149
identifiers = append(identifiers, ident)
150150
}
@@ -153,7 +153,7 @@ func assigningCallExprs(info *TypesInfoExt, subject *ast.Ident) []*ast.CallExpr
153153
// Find out whether the identifiers are part of an assignment statement.
154154
var callExprs []*ast.CallExpr
155155
for _, ident := range identifiers {
156-
parent := info.NodeParent[ident]
156+
parent := pass.NodeParent[ident]
157157
switch declT := parent.(type) {
158158
case *ast.AssignStmt:
159159
// The identifier is LHS of an assignment.
@@ -181,7 +181,7 @@ func assigningCallExprs(info *TypesInfoExt, subject *ast.Ident) []*ast.CallExpr
181181
continue
182182
}
183183
// The subject was the result of assigning from another identifier.
184-
callExprs = append(callExprs, assigningCallExprs(info, assignT)...)
184+
callExprs = append(callExprs, assigningCallExprs(pass, assignT)...)
185185
default:
186186
// TODO: inconclusive?
187187
}
@@ -190,9 +190,7 @@ func assigningCallExprs(info *TypesInfoExt, subject *ast.Ident) []*ast.CallExpr
190190
return callExprs
191191
}
192192

193-
func selectorToString(selExpr *ast.SelectorExpr) string {
194-
if ident, ok := selExpr.X.(*ast.Ident); ok {
195-
return ident.Name + "." + selExpr.Sel.Name
196-
}
197-
return ""
193+
func selectorToString(pass *TypesInfoExt, selExpr *ast.SelectorExpr) string {
194+
o := pass.TypesInfo.Uses[selExpr.Sel]
195+
return fmt.Sprintf("%s.%s", o.Pkg().Path(), o.Name())
198196
}

errorlint/analysis.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ func init() {
3535

3636
func run(pass *analysis.Pass) (interface{}, error) {
3737
lints := []analysis.Diagnostic{}
38-
extInfo := newTypesInfoExt(pass.TypesInfo)
38+
extInfo := newTypesInfoExt(pass)
3939
if checkComparison {
40-
l := LintErrorComparisons(pass.Fset, extInfo)
40+
l := LintErrorComparisons(extInfo)
4141
lints = append(lints, l...)
4242
}
4343
if checkAsserts {
@@ -57,7 +57,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
5757
}
5858

5959
type TypesInfoExt struct {
60-
types.Info
60+
*analysis.Pass
6161

6262
// Maps AST nodes back to the node they are contained within.
6363
NodeParent map[ast.Node]ast.Node
@@ -66,9 +66,9 @@ type TypesInfoExt struct {
6666
IdentifiersForObject map[types.Object][]*ast.Ident
6767
}
6868

69-
func newTypesInfoExt(info *types.Info) *TypesInfoExt {
69+
func newTypesInfoExt(pass *analysis.Pass) *TypesInfoExt {
7070
nodeParent := map[ast.Node]ast.Node{}
71-
for node := range info.Scopes {
71+
for node := range pass.TypesInfo.Scopes {
7272
file, ok := node.(*ast.File)
7373
if !ok {
7474
continue
@@ -86,15 +86,15 @@ func newTypesInfoExt(info *types.Info) *TypesInfoExt {
8686
}
8787

8888
identifiersForObject := map[types.Object][]*ast.Ident{}
89-
for node, obj := range info.Defs {
89+
for node, obj := range pass.TypesInfo.Defs {
9090
identifiersForObject[obj] = append(identifiersForObject[obj], node)
9191
}
92-
for node, obj := range info.Uses {
92+
for node, obj := range pass.TypesInfo.Uses {
9393
identifiersForObject[obj] = append(identifiersForObject[obj], node)
9494
}
9595

9696
return &TypesInfoExt{
97-
Info: *info,
97+
Pass: pass,
9898
NodeParent: nodeParent,
9999
IdentifiersForObject: identifiersForObject,
100100
}

errorlint/lint.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,10 @@ func isFmtErrorfCallExpr(info types.Info, expr ast.Expr) (*ast.CallExpr, bool) {
158158
return nil, false
159159
}
160160

161-
func LintErrorComparisons(fset *token.FileSet, info *TypesInfoExt) []analysis.Diagnostic {
161+
func LintErrorComparisons(info *TypesInfoExt) []analysis.Diagnostic {
162162
lints := []analysis.Diagnostic{}
163163

164-
for expr := range info.Types {
164+
for expr := range info.TypesInfo.Types {
165165
// Find == and != operations.
166166
binExpr, ok := expr.(*ast.BinaryExpr)
167167
if !ok {
@@ -175,7 +175,7 @@ func LintErrorComparisons(fset *token.FileSet, info *TypesInfoExt) []analysis.Di
175175
continue
176176
}
177177
// Find comparisons of which one side is a of type error.
178-
if !isErrorComparison(info.Info, binExpr) {
178+
if !isErrorComparison(info.TypesInfo, binExpr) {
179179
continue
180180
}
181181
// Some errors that are returned from some functions are exempt.
@@ -193,7 +193,7 @@ func LintErrorComparisons(fset *token.FileSet, info *TypesInfoExt) []analysis.Di
193193
})
194194
}
195195

196-
for scope := range info.Scopes {
196+
for scope := range info.TypesInfo.Scopes {
197197
// Find value switch blocks.
198198
switchStmt, ok := scope.(*ast.SwitchStmt)
199199
if !ok {
@@ -203,7 +203,7 @@ func LintErrorComparisons(fset *token.FileSet, info *TypesInfoExt) []analysis.Di
203203
if switchStmt.Tag == nil {
204204
continue
205205
}
206-
tagType := info.Types[switchStmt.Tag]
206+
tagType := info.TypesInfo.Types[switchStmt.Tag]
207207
if tagType.Type.String() != "error" {
208208
continue
209209
}
@@ -233,7 +233,7 @@ func isNilComparison(binExpr *ast.BinaryExpr) bool {
233233
return false
234234
}
235235

236-
func isErrorComparison(info types.Info, binExpr *ast.BinaryExpr) bool {
236+
func isErrorComparison(info *types.Info, binExpr *ast.BinaryExpr) bool {
237237
tx := info.Types[binExpr.X]
238238
ty := info.Types[binExpr.Y]
239239
return tx.Type.String() == "error" || ty.Type.String() == "error"
@@ -252,11 +252,11 @@ func isNodeInErrorIsFunc(info *TypesInfoExt, node ast.Node) bool {
252252
return false
253253
}
254254
// There should be 1 argument of type error.
255-
if ii := funcDecl.Type.Params.List; len(ii) != 1 || info.Types[ii[0].Type].Type.String() != "error" {
255+
if ii := funcDecl.Type.Params.List; len(ii) != 1 || info.TypesInfo.Types[ii[0].Type].Type.String() != "error" {
256256
return false
257257
}
258258
// The return type should be bool.
259-
if ii := funcDecl.Type.Results.List; len(ii) != 1 || info.Types[ii[0].Type].Type.String() != "bool" {
259+
if ii := funcDecl.Type.Results.List; len(ii) != 1 || info.TypesInfo.Types[ii[0].Type].Type.String() != "bool" {
260260
return false
261261
}
262262

0 commit comments

Comments
 (0)