1
2
3
4
5 package modernize
6
7 import (
8 _ "embed"
9 "go/ast"
10 "go/constant"
11 "go/format"
12 "go/token"
13 "go/types"
14 "iter"
15 "regexp"
16 "strings"
17
18 "golang.org/x/tools/go/analysis"
19 "golang.org/x/tools/go/analysis/passes/inspect"
20 "golang.org/x/tools/go/ast/inspector"
21 "golang.org/x/tools/internal/analysis/analyzerutil"
22 "golang.org/x/tools/internal/refactor"
23 "golang.org/x/tools/internal/typesinternal/typeindex"
24
25 "golang.org/x/tools/internal/moreiters"
26 "golang.org/x/tools/internal/packagepath"
27 "golang.org/x/tools/internal/stdlib"
28 "golang.org/x/tools/internal/typesinternal"
29 )
30
31
32 var doc string
33
34
35 var Suite = []*analysis.Analyzer{
36 AnyAnalyzer,
37 AtomicTypesAnalyzer,
38
39
40 EmbedLitAnalyzer,
41 ErrorsAsTypeAnalyzer,
42
43 ForVarAnalyzer,
44 MapsLoopAnalyzer,
45 MinMaxAnalyzer,
46 NewExprAnalyzer,
47 OmitZeroAnalyzer,
48 PlusBuildAnalyzer,
49 RangeIntAnalyzer,
50 ReflectTypeForAnalyzer,
51 slicesBackwardAnalyzer,
52 SlicesContainsAnalyzer,
53
54 SlicesSortAnalyzer,
55 StdIteratorsAnalyzer,
56 StringsCutAnalyzer,
57 StringsCutPrefixAnalyzer,
58 StringsSeqAnalyzer,
59 StringsBuilderAnalyzer,
60 TestingContextAnalyzer,
61 unsafeFuncsAnalyzer,
62 WaitGroupGoAnalyzer,
63 }
64
65
66
67
68 func formatExprs(fset *token.FileSet, exprs []ast.Expr) string {
69 var buf strings.Builder
70 for i, e := range exprs {
71 if i > 0 {
72 buf.WriteString(", ")
73 }
74 format.Node(&buf, fset, e)
75 }
76 return buf.String()
77 }
78
79
80 func isZeroIntConst(info *types.Info, e ast.Expr) bool {
81 return isIntLiteral(info, e, 0)
82 }
83
84
85 func isIntLiteral(info *types.Info, e ast.Expr, n int64) bool {
86 return info.Types[e].Value == constant.MakeInt64(n)
87 }
88
89
90 func isInteger(t types.Type) bool {
91 basic, ok := t.Underlying().(*types.Basic)
92 return ok && basic.Info()&types.IsInteger != 0
93 }
94
95
96
97
98
99
100
101
102
103
104 func filesUsingGoVersion(pass *analysis.Pass, version string) iter.Seq[inspector.Cursor] {
105 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
106
107 return func(yield func(inspector.Cursor) bool) {
108 for curFile := range inspect.Root().Children() {
109 file := curFile.Node().(*ast.File)
110 if analyzerutil.FileUsesGoVersion(pass, file, version) && !yield(curFile) {
111 break
112 }
113 }
114 }
115 }
116
117
118
119 func within(pass *analysis.Pass, pkgs ...string) bool {
120 path := pass.Pkg.Path()
121 return packagepath.IsStdPackage(path) &&
122 moreiters.Contains(stdlib.Dependencies(pkgs...), path)
123 }
124
125 var (
126 builtinAny = types.Universe.Lookup("any")
127 builtinAppend = types.Universe.Lookup("append")
128 builtinBool = types.Universe.Lookup("bool")
129 builtinInt = types.Universe.Lookup("int")
130 builtinFalse = types.Universe.Lookup("false")
131 builtinLen = types.Universe.Lookup("len")
132 builtinMake = types.Universe.Lookup("make")
133 builtinNew = types.Universe.Lookup("new")
134 builtinNil = types.Universe.Lookup("nil")
135 builtinString = types.Universe.Lookup("string")
136 builtinTrue = types.Universe.Lookup("true")
137 byteSliceType = types.NewSlice(types.Typ[types.Byte])
138 omitemptyRegex = regexp.MustCompile(`(?:^json| json):"[^"]*(,omitempty)(?:"|,[^"]*")\s?`)
139 errorType = types.Universe.Lookup("error").Type()
140 )
141
142
143 func lookup(info *types.Info, cur inspector.Cursor, name string) types.Object {
144 scope := typesinternal.EnclosingScope(info, cur)
145 _, obj := scope.LookupParent(name, cur.Node().Pos())
146 return obj
147 }
148
149 func first[T any](x T, _ any) T { return x }
150
151
152
153
154
155
156
157
158
159 func freshName(info *types.Info, index *typeindex.Index, scope *types.Scope, pos token.Pos, defCur inspector.Cursor, useCur inspector.Cursor, useAfterPos token.Pos, preferredName string) string {
160 obj := lookup(info, defCur, preferredName)
161 if obj == nil {
162
163 return preferredName
164 }
165 for use := range index.Uses(obj) {
166 if useCur.Contains(use) && use.Node().Pos() >= useAfterPos {
167 return refactor.FreshName(scope, pos, preferredName)
168 }
169 }
170
171 return preferredName
172 }
173
174
175
176 func isLocal(obj types.Object) bool {
177
178 var depth int
179 for scope := obj.Parent(); scope != nil; scope = scope.Parent() {
180 depth++
181 }
182 return depth >= 4
183 }
184
185 func is[T any](x any) bool {
186 _, ok := x.(T)
187 return ok
188 }
189
190 func cond[T any](cond bool, t, f T) T {
191 if cond {
192 return t
193 } else {
194 return f
195 }
196 }
197
View as plain text