Skip to content

Commit 8179c75

Browse files
adonovangopherbot
authored andcommitted
internal/analysisinternal: factor useful helper functions
This CL refines, generalizes, and promotes a number of helper functions that have proven useful in go/analysis/passes/... and gopls' modernizer analyzer: package analysisinternal func Format func Imports func Is{Method,Type,Function}Named Details: - all the Is*Named functions accept a list of candidates, and a types.Object (that may be nil). This makes it much more convenient to use on the result of typeutil.Callee. Also, modernizations in passing: - info.PkgNameOf - interface{} -> any - slices.Contains - fmt.Appendf - etc Change-Id: Ib441af3eef9c5030f0ee2b38df69b4a25015ed97 Reviewed-on: https://go-review.googlesource.com/c/tools/+/639157 Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent a339e37 commit 8179c75

File tree

35 files changed

+239
-302
lines changed

35 files changed

+239
-302
lines changed

go/analysis/passes/assign/assign.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"golang.org/x/tools/go/analysis/passes/inspect"
2020
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
2121
"golang.org/x/tools/go/ast/inspector"
22+
"golang.org/x/tools/internal/analysisinternal"
2223
)
2324

2425
//go:embed doc.go
@@ -32,7 +33,7 @@ var Analyzer = &analysis.Analyzer{
3233
Run: run,
3334
}
3435

35-
func run(pass *analysis.Pass) (interface{}, error) {
36+
func run(pass *analysis.Pass) (any, error) {
3637
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
3738

3839
nodeFilter := []ast.Node{
@@ -57,8 +58,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
5758
if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
5859
continue // short-circuit the heavy-weight gofmt check
5960
}
60-
le := analysisutil.Format(pass.Fset, lhs)
61-
re := analysisutil.Format(pass.Fset, rhs)
61+
le := analysisinternal.Format(pass.Fset, lhs)
62+
re := analysisinternal.Format(pass.Fset, rhs)
6263
if le == re {
6364
pass.Report(analysis.Diagnostic{
6465
Pos: stmt.Pos(), Message: fmt.Sprintf("self-assignment of %s to %s", re, le),

go/analysis/passes/atomic/atomic.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
1515
"golang.org/x/tools/go/ast/inspector"
1616
"golang.org/x/tools/go/types/typeutil"
17+
"golang.org/x/tools/internal/analysisinternal"
1718
)
1819

1920
//go:embed doc.go
@@ -28,8 +29,8 @@ var Analyzer = &analysis.Analyzer{
2829
Run: run,
2930
}
3031

31-
func run(pass *analysis.Pass) (interface{}, error) {
32-
if !analysisutil.Imports(pass.Pkg, "sync/atomic") {
32+
func run(pass *analysis.Pass) (any, error) {
33+
if !analysisinternal.Imports(pass.Pkg, "sync/atomic") {
3334
return nil, nil // doesn't directly import sync/atomic
3435
}
3536

@@ -52,8 +53,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
5253
if !ok {
5354
continue
5455
}
55-
fn := typeutil.StaticCallee(pass.TypesInfo, call)
56-
if analysisutil.IsFunctionNamed(fn, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") {
56+
obj := typeutil.Callee(pass.TypesInfo, call)
57+
if analysisinternal.IsFunctionNamed(obj, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") {
5758
checkAtomicAddAssignment(pass, n.Lhs[i], call)
5859
}
5960
}
@@ -71,7 +72,7 @@ func checkAtomicAddAssignment(pass *analysis.Pass, left ast.Expr, call *ast.Call
7172
arg := call.Args[0]
7273
broken := false
7374

74-
gofmt := func(e ast.Expr) string { return analysisutil.Format(pass.Fset, e) }
75+
gofmt := func(e ast.Expr) string { return analysisinternal.Format(pass.Fset, e) }
7576

7677
if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
7778
broken = gofmt(left) == gofmt(uarg.X)

go/analysis/passes/atomicalign/atomicalign.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ import (
1616

1717
"golang.org/x/tools/go/analysis"
1818
"golang.org/x/tools/go/analysis/passes/inspect"
19-
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
2019
"golang.org/x/tools/go/ast/inspector"
2120
"golang.org/x/tools/go/types/typeutil"
21+
"golang.org/x/tools/internal/analysisinternal"
2222
)
2323

2424
const Doc = "check for non-64-bits-aligned arguments to sync/atomic functions"
@@ -31,11 +31,11 @@ var Analyzer = &analysis.Analyzer{
3131
Run: run,
3232
}
3333

34-
func run(pass *analysis.Pass) (interface{}, error) {
34+
func run(pass *analysis.Pass) (any, error) {
3535
if 8*pass.TypesSizes.Sizeof(types.Typ[types.Uintptr]) == 64 {
3636
return nil, nil // 64-bit platform
3737
}
38-
if !analysisutil.Imports(pass.Pkg, "sync/atomic") {
38+
if !analysisinternal.Imports(pass.Pkg, "sync/atomic") {
3939
return nil, nil // doesn't directly import sync/atomic
4040
}
4141

@@ -53,10 +53,10 @@ func run(pass *analysis.Pass) (interface{}, error) {
5353

5454
inspect.Preorder(nodeFilter, func(node ast.Node) {
5555
call := node.(*ast.CallExpr)
56-
fn := typeutil.StaticCallee(pass.TypesInfo, call)
57-
if analysisutil.IsFunctionNamed(fn, "sync/atomic", funcNames...) {
56+
obj := typeutil.Callee(pass.TypesInfo, call)
57+
if analysisinternal.IsFunctionNamed(obj, "sync/atomic", funcNames...) {
5858
// For all the listed functions, the expression to check is always the first function argument.
59-
check64BitAlignment(pass, fn.Name(), call.Args[0])
59+
check64BitAlignment(pass, obj.Name(), call.Args[0])
6060
}
6161
})
6262

go/analysis/passes/bools/bools.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"golang.org/x/tools/go/analysis/passes/inspect"
1616
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
1717
"golang.org/x/tools/go/ast/inspector"
18+
"golang.org/x/tools/internal/analysisinternal"
1819
)
1920

2021
const Doc = "check for common mistakes involving boolean operators"
@@ -27,7 +28,7 @@ var Analyzer = &analysis.Analyzer{
2728
Run: run,
2829
}
2930

30-
func run(pass *analysis.Pass) (interface{}, error) {
31+
func run(pass *analysis.Pass) (any, error) {
3132
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
3233

3334
nodeFilter := []ast.Node{
@@ -103,7 +104,7 @@ func (op boolOp) commutativeSets(info *types.Info, e *ast.BinaryExpr, seen map[*
103104
func (op boolOp) checkRedundant(pass *analysis.Pass, exprs []ast.Expr) {
104105
seen := make(map[string]bool)
105106
for _, e := range exprs {
106-
efmt := analysisutil.Format(pass.Fset, e)
107+
efmt := analysisinternal.Format(pass.Fset, e)
107108
if seen[efmt] {
108109
pass.ReportRangef(e, "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt)
109110
} else {
@@ -149,8 +150,8 @@ func (op boolOp) checkSuspect(pass *analysis.Pass, exprs []ast.Expr) {
149150
}
150151

151152
// e is of the form 'x != c' or 'x == c'.
152-
xfmt := analysisutil.Format(pass.Fset, x)
153-
efmt := analysisutil.Format(pass.Fset, e)
153+
xfmt := analysisinternal.Format(pass.Fset, x)
154+
efmt := analysisinternal.Format(pass.Fset, e)
154155
if prev, found := seen[xfmt]; found {
155156
// checkRedundant handles the case in which efmt == prev.
156157
if efmt != prev {

go/analysis/passes/cgocall/cgocall.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
"strconv"
1919

2020
"golang.org/x/tools/go/analysis"
21-
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
21+
"golang.org/x/tools/internal/analysisinternal"
2222
)
2323

2424
const debug = false
@@ -40,8 +40,8 @@ var Analyzer = &analysis.Analyzer{
4040
Run: run,
4141
}
4242

43-
func run(pass *analysis.Pass) (interface{}, error) {
44-
if !analysisutil.Imports(pass.Pkg, "runtime/cgo") {
43+
func run(pass *analysis.Pass) (any, error) {
44+
if !analysisinternal.Imports(pass.Pkg, "runtime/cgo") {
4545
return nil, nil // doesn't use cgo
4646
}
4747

go/analysis/passes/copylock/copylock.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import (
1515

1616
"golang.org/x/tools/go/analysis"
1717
"golang.org/x/tools/go/analysis/passes/inspect"
18-
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
1918
"golang.org/x/tools/go/ast/inspector"
19+
"golang.org/x/tools/internal/analysisinternal"
2020
"golang.org/x/tools/internal/typeparams"
2121
"golang.org/x/tools/internal/versions"
2222
)
@@ -86,7 +86,7 @@ func checkCopyLocksAssign(pass *analysis.Pass, assign *ast.AssignStmt, goversion
8686
lhs := assign.Lhs
8787
for i, x := range assign.Rhs {
8888
if path := lockPathRhs(pass, x); path != nil {
89-
pass.ReportRangef(x, "assignment copies lock value to %v: %v", analysisutil.Format(pass.Fset, assign.Lhs[i]), path)
89+
pass.ReportRangef(x, "assignment copies lock value to %v: %v", analysisinternal.Format(pass.Fset, assign.Lhs[i]), path)
9090
lhs = nil // An lhs has been reported. We prefer the assignment warning and do not report twice.
9191
}
9292
}
@@ -100,7 +100,7 @@ func checkCopyLocksAssign(pass *analysis.Pass, assign *ast.AssignStmt, goversion
100100
if id, ok := l.(*ast.Ident); ok && id.Name != "_" {
101101
if obj := pass.TypesInfo.Defs[id]; obj != nil && obj.Type() != nil {
102102
if path := lockPath(pass.Pkg, obj.Type(), nil); path != nil {
103-
pass.ReportRangef(l, "for loop iteration copies lock value to %v: %v", analysisutil.Format(pass.Fset, l), path)
103+
pass.ReportRangef(l, "for loop iteration copies lock value to %v: %v", analysisinternal.Format(pass.Fset, l), path)
104104
}
105105
}
106106
}
@@ -132,7 +132,7 @@ func checkCopyLocksCompositeLit(pass *analysis.Pass, cl *ast.CompositeLit) {
132132
x = node.Value
133133
}
134134
if path := lockPathRhs(pass, x); path != nil {
135-
pass.ReportRangef(x, "literal copies lock value from %v: %v", analysisutil.Format(pass.Fset, x), path)
135+
pass.ReportRangef(x, "literal copies lock value from %v: %v", analysisinternal.Format(pass.Fset, x), path)
136136
}
137137
}
138138
}
@@ -163,7 +163,7 @@ func checkCopyLocksCallExpr(pass *analysis.Pass, ce *ast.CallExpr) {
163163
}
164164
for _, x := range ce.Args {
165165
if path := lockPathRhs(pass, x); path != nil {
166-
pass.ReportRangef(x, "call of %s copies lock value: %v", analysisutil.Format(pass.Fset, ce.Fun), path)
166+
pass.ReportRangef(x, "call of %s copies lock value: %v", analysisinternal.Format(pass.Fset, ce.Fun), path)
167167
}
168168
}
169169
}
@@ -230,7 +230,7 @@ func checkCopyLocksRangeVar(pass *analysis.Pass, rtok token.Token, e ast.Expr) {
230230
return
231231
}
232232
if path := lockPath(pass.Pkg, typ, nil); path != nil {
233-
pass.Reportf(e.Pos(), "range var %s copies lock: %v", analysisutil.Format(pass.Fset, e), path)
233+
pass.Reportf(e.Pos(), "range var %s copies lock: %v", analysisinternal.Format(pass.Fset, e), path)
234234
}
235235
}
236236

@@ -350,7 +350,7 @@ func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typ
350350
// In go1.10, sync.noCopy did not implement Locker.
351351
// (The Unlock method was added only in CL 121876.)
352352
// TODO(adonovan): remove workaround when we drop go1.10.
353-
if analysisutil.IsNamedType(typ, "sync", "noCopy") {
353+
if analysisinternal.IsTypeNamed(typ, "sync", "noCopy") {
354354
return []string{typ.String()}
355355
}
356356

go/analysis/passes/deepequalerrors/deepequalerrors.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import (
1212

1313
"golang.org/x/tools/go/analysis"
1414
"golang.org/x/tools/go/analysis/passes/inspect"
15-
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
1615
"golang.org/x/tools/go/ast/inspector"
1716
"golang.org/x/tools/go/types/typeutil"
17+
"golang.org/x/tools/internal/analysisinternal"
1818
)
1919

2020
const Doc = `check for calls of reflect.DeepEqual on error values
@@ -34,8 +34,8 @@ var Analyzer = &analysis.Analyzer{
3434
Run: run,
3535
}
3636

37-
func run(pass *analysis.Pass) (interface{}, error) {
38-
if !analysisutil.Imports(pass.Pkg, "reflect") {
37+
func run(pass *analysis.Pass) (any, error) {
38+
if !analysisinternal.Imports(pass.Pkg, "reflect") {
3939
return nil, nil // doesn't directly import reflect
4040
}
4141

@@ -46,8 +46,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
4646
}
4747
inspect.Preorder(nodeFilter, func(n ast.Node) {
4848
call := n.(*ast.CallExpr)
49-
fn, _ := typeutil.Callee(pass.TypesInfo, call).(*types.Func)
50-
if analysisutil.IsFunctionNamed(fn, "reflect", "DeepEqual") && hasError(pass, call.Args[0]) && hasError(pass, call.Args[1]) {
49+
obj := typeutil.Callee(pass.TypesInfo, call)
50+
if analysisinternal.IsFunctionNamed(obj, "reflect", "DeepEqual") && hasError(pass, call.Args[0]) && hasError(pass, call.Args[1]) {
5151
pass.ReportRangef(call, "avoid using reflect.DeepEqual with errors")
5252
}
5353
})

go/analysis/passes/defers/defers.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
1414
"golang.org/x/tools/go/ast/inspector"
1515
"golang.org/x/tools/go/types/typeutil"
16+
"golang.org/x/tools/internal/analysisinternal"
1617
)
1718

1819
//go:embed doc.go
@@ -27,15 +28,15 @@ var Analyzer = &analysis.Analyzer{
2728
Run: run,
2829
}
2930

30-
func run(pass *analysis.Pass) (interface{}, error) {
31-
if !analysisutil.Imports(pass.Pkg, "time") {
31+
func run(pass *analysis.Pass) (any, error) {
32+
if !analysisinternal.Imports(pass.Pkg, "time") {
3233
return nil, nil
3334
}
3435

3536
checkDeferCall := func(node ast.Node) bool {
3637
switch v := node.(type) {
3738
case *ast.CallExpr:
38-
if analysisutil.IsFunctionNamed(typeutil.StaticCallee(pass.TypesInfo, v), "time", "Since") {
39+
if analysisinternal.IsFunctionNamed(typeutil.Callee(pass.TypesInfo, v), "time", "Since") {
3940
pass.Reportf(v.Pos(), "call to time.Since is not deferred")
4041
}
4142
case *ast.FuncLit:

go/analysis/passes/errorsas/errorsas.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import (
1313

1414
"golang.org/x/tools/go/analysis"
1515
"golang.org/x/tools/go/analysis/passes/inspect"
16-
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
1716
"golang.org/x/tools/go/ast/inspector"
1817
"golang.org/x/tools/go/types/typeutil"
18+
"golang.org/x/tools/internal/analysisinternal"
1919
)
2020

2121
const Doc = `report passing non-pointer or non-error values to errors.As
@@ -31,15 +31,15 @@ var Analyzer = &analysis.Analyzer{
3131
Run: run,
3232
}
3333

34-
func run(pass *analysis.Pass) (interface{}, error) {
34+
func run(pass *analysis.Pass) (any, error) {
3535
switch pass.Pkg.Path() {
3636
case "errors", "errors_test":
3737
// These packages know how to use their own APIs.
3838
// Sometimes they are testing what happens to incorrect programs.
3939
return nil, nil
4040
}
4141

42-
if !analysisutil.Imports(pass.Pkg, "errors") {
42+
if !analysisinternal.Imports(pass.Pkg, "errors") {
4343
return nil, nil // doesn't directly import errors
4444
}
4545

@@ -50,8 +50,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
5050
}
5151
inspect.Preorder(nodeFilter, func(n ast.Node) {
5252
call := n.(*ast.CallExpr)
53-
fn := typeutil.StaticCallee(pass.TypesInfo, call)
54-
if !analysisutil.IsFunctionNamed(fn, "errors", "As") {
53+
obj := typeutil.Callee(pass.TypesInfo, call)
54+
if !analysisinternal.IsFunctionNamed(obj, "errors", "As") {
5555
return
5656
}
5757
if len(call.Args) < 2 {

go/analysis/passes/httpmux/httpmux.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import (
1414
"golang.org/x/mod/semver"
1515
"golang.org/x/tools/go/analysis"
1616
"golang.org/x/tools/go/analysis/passes/inspect"
17-
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
1817
"golang.org/x/tools/go/ast/inspector"
1918
"golang.org/x/tools/go/types/typeutil"
19+
"golang.org/x/tools/internal/analysisinternal"
2020
"golang.org/x/tools/internal/typesinternal"
2121
)
2222

@@ -45,7 +45,7 @@ func run(pass *analysis.Pass) (any, error) {
4545
return nil, nil
4646
}
4747
}
48-
if !analysisutil.Imports(pass.Pkg, "net/http") {
48+
if !analysisinternal.Imports(pass.Pkg, "net/http") {
4949
return nil, nil
5050
}
5151
// Look for calls to ServeMux.Handle or ServeMux.HandleFunc.
@@ -78,19 +78,21 @@ func isServeMuxRegisterCall(pass *analysis.Pass, call *ast.CallExpr) bool {
7878
if fn == nil {
7979
return false
8080
}
81-
if analysisutil.IsFunctionNamed(fn, "net/http", "Handle", "HandleFunc") {
81+
if analysisinternal.IsFunctionNamed(fn, "net/http", "Handle", "HandleFunc") {
8282
return true
8383
}
8484
if !isMethodNamed(fn, "net/http", "Handle", "HandleFunc") {
8585
return false
8686
}
8787
recv := fn.Type().(*types.Signature).Recv() // isMethodNamed() -> non-nil
8888
isPtr, named := typesinternal.ReceiverNamed(recv)
89-
return isPtr && analysisutil.IsNamedType(named, "net/http", "ServeMux")
89+
return isPtr && analysisinternal.IsTypeNamed(named, "net/http", "ServeMux")
9090
}
9191

9292
// isMethodNamed reports when a function f is a method,
9393
// in a package with the path pkgPath and the name of f is in names.
94+
//
95+
// (Unlike [analysisinternal.IsMethodNamed], it ignores the receiver type name.)
9496
func isMethodNamed(f *types.Func, pkgPath string, names ...string) bool {
9597
if f == nil {
9698
return false

0 commit comments

Comments
 (0)