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/edge"
21 "golang.org/x/tools/go/ast/inspector"
22 "golang.org/x/tools/internal/analysis/analyzerutil"
23 "golang.org/x/tools/internal/astutil"
24 "golang.org/x/tools/internal/moreiters"
25 "golang.org/x/tools/internal/packagepath"
26 "golang.org/x/tools/internal/stdlib"
27 "golang.org/x/tools/internal/typesinternal"
28 )
29
30
31 var doc string
32
33
34 var Suite = []*analysis.Analyzer{
35 AnyAnalyzer,
36
37
38 FmtAppendfAnalyzer,
39 ForVarAnalyzer,
40 MapsLoopAnalyzer,
41 MinMaxAnalyzer,
42 NewExprAnalyzer,
43 OmitZeroAnalyzer,
44 plusBuildAnalyzer,
45 RangeIntAnalyzer,
46 ReflectTypeForAnalyzer,
47 SlicesContainsAnalyzer,
48
49 SlicesSortAnalyzer,
50 stditeratorsAnalyzer,
51 stringscutAnalyzer,
52 StringsCutPrefixAnalyzer,
53 StringsSeqAnalyzer,
54 StringsBuilderAnalyzer,
55 TestingContextAnalyzer,
56 unsafeFuncsAnalyzer,
57 WaitGroupAnalyzer,
58 }
59
60
61
62
63 func formatExprs(fset *token.FileSet, exprs []ast.Expr) string {
64 var buf strings.Builder
65 for i, e := range exprs {
66 if i > 0 {
67 buf.WriteString(", ")
68 }
69 format.Node(&buf, fset, e)
70 }
71 return buf.String()
72 }
73
74
75 func isZeroIntConst(info *types.Info, e ast.Expr) bool {
76 return isIntLiteral(info, e, 0)
77 }
78
79
80 func isIntLiteral(info *types.Info, e ast.Expr, n int64) bool {
81 return info.Types[e].Value == constant.MakeInt64(n)
82 }
83
84
85
86
87
88
89
90
91
92
93 func filesUsingGoVersion(pass *analysis.Pass, version string) iter.Seq[inspector.Cursor] {
94 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
95
96 return func(yield func(inspector.Cursor) bool) {
97 for curFile := range inspect.Root().Children() {
98 file := curFile.Node().(*ast.File)
99 if analyzerutil.FileUsesGoVersion(pass, file, version) && !yield(curFile) {
100 break
101 }
102 }
103 }
104 }
105
106
107
108 func within(pass *analysis.Pass, pkgs ...string) bool {
109 path := pass.Pkg.Path()
110 return packagepath.IsStdPackage(path) &&
111 moreiters.Contains(stdlib.Dependencies(pkgs...), path)
112 }
113
114
115
116 func unparenEnclosing(cur inspector.Cursor) inspector.Cursor {
117 for astutil.IsChildOf(cur, edge.ParenExpr_X) {
118 cur = cur.Parent()
119 }
120 return cur
121 }
122
123 var (
124 builtinAny = types.Universe.Lookup("any")
125 builtinAppend = types.Universe.Lookup("append")
126 builtinBool = types.Universe.Lookup("bool")
127 builtinInt = types.Universe.Lookup("int")
128 builtinFalse = types.Universe.Lookup("false")
129 builtinLen = types.Universe.Lookup("len")
130 builtinMake = types.Universe.Lookup("make")
131 builtinNew = types.Universe.Lookup("new")
132 builtinNil = types.Universe.Lookup("nil")
133 builtinString = types.Universe.Lookup("string")
134 builtinTrue = types.Universe.Lookup("true")
135 byteSliceType = types.NewSlice(types.Typ[types.Byte])
136 omitemptyRegex = regexp.MustCompile(`(?:^json| json):"[^"]*(,omitempty)(?:"|,[^"]*")\s?`)
137 )
138
139
140 func lookup(info *types.Info, cur inspector.Cursor, name string) types.Object {
141 scope := typesinternal.EnclosingScope(info, cur)
142 _, obj := scope.LookupParent(name, cur.Node().Pos())
143 return obj
144 }
145
146 func first[T any](x T, _ any) T { return x }
147
View as plain text