1
2
3
4
5 package modernize
6
7 import (
8 "fmt"
9 "go/ast"
10 "go/token"
11 "go/types"
12
13 "golang.org/x/tools/go/analysis"
14 "golang.org/x/tools/go/analysis/passes/inspect"
15 "golang.org/x/tools/go/ast/edge"
16 "golang.org/x/tools/go/ast/inspector"
17 "golang.org/x/tools/internal/analysis/analyzerutil"
18 "golang.org/x/tools/internal/astutil"
19 "golang.org/x/tools/internal/goplsexport"
20 "golang.org/x/tools/internal/refactor"
21 "golang.org/x/tools/internal/typesinternal"
22 "golang.org/x/tools/internal/versions"
23 )
24
25
26
27
28
29
30
31
32 var unsafeFuncsAnalyzer = &analysis.Analyzer{
33 Name: "unsafefuncs",
34 Doc: analyzerutil.MustExtractDoc(doc, "unsafefuncs"),
35 Requires: []*analysis.Analyzer{inspect.Analyzer},
36 Run: unsafefuncs,
37 URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#unsafefuncs",
38 }
39
40 func init() {
41
42 goplsexport.UnsafeFuncsModernizer = unsafeFuncsAnalyzer
43 }
44
45 func unsafefuncs(pass *analysis.Pass) (any, error) {
46
47
48
49 if !typesinternal.Imports(pass.Pkg, "unsafe") {
50 return nil, nil
51 }
52
53 var (
54 inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
55 info = pass.TypesInfo
56 tUnsafePointer = types.Typ[types.UnsafePointer]
57 )
58
59
60
61 isConversion := func(curExpr inspector.Cursor) (t types.Type, x inspector.Cursor) {
62 e := curExpr.Node().(ast.Expr)
63 if conv, ok := ast.Unparen(e).(*ast.CallExpr); ok && len(conv.Args) == 1 {
64 if tv := pass.TypesInfo.Types[conv.Fun]; tv.IsType() {
65 return tv.Type, curExpr.ChildAt(edge.CallExpr_Args, 0)
66 }
67 }
68 return
69 }
70
71
72
73
74
75
76
77
78
79
80
81
82 for curSum := range inspect.Root().Preorder((*ast.BinaryExpr)(nil)) {
83 if sum, ok := curSum.Node().(*ast.BinaryExpr); ok &&
84 sum.Op == token.ADD &&
85 types.Identical(info.TypeOf(sum.X), types.Typ[types.Uintptr]) &&
86 curSum.ParentEdgeKind() == edge.CallExpr_Args {
87
88 curX := curSum.ChildAt(edge.BinaryExpr_X, -1)
89 curY := curSum.ChildAt(edge.BinaryExpr_Y, -1)
90
91
92 curResult := curSum.Parent()
93 if t, _ := isConversion(curResult); !(t != nil && types.Identical(t, tUnsafePointer)) {
94 continue
95 }
96
97
98
99 _, curPtr := isConversion(curX)
100 if !curPtr.Valid() {
101 continue
102 }
103 ptr := curPtr.Node().(ast.Expr)
104 if !types.Identical(info.TypeOf(ptr), tUnsafePointer) {
105 continue
106 }
107
108
109 file := astutil.EnclosingFile(curSum)
110 if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_17) {
111 continue
112 }
113
114
115 unsafedot, edits := refactor.AddImport(info, file, "unsafe", "unsafe", "Add", sum.Pos())
116
117
118
119
120 edits = append(edits, deleteConv(curResult)...)
121
122
123
124
125 edits = append(edits, []analysis.TextEdit{
126 {
127 Pos: sum.Pos(),
128 End: ptr.Pos(),
129 NewText: fmt.Appendf(nil, "%sAdd(", unsafedot),
130 },
131 {
132 Pos: ptr.End(),
133 End: sum.Y.Pos(),
134 NewText: []byte(", "),
135 },
136 {
137 Pos: sum.Y.End(),
138 End: sum.Y.End(),
139 NewText: []byte(")"),
140 },
141 }...)
142
143
144
145
146
147
148
149 if t, _ := isConversion(curY); t != nil && isInteger(t) {
150 edits = append(edits, deleteConv(curY)...)
151 }
152
153 pass.Report(analysis.Diagnostic{
154 Pos: sum.Pos(),
155 End: sum.End(),
156 Message: "pointer + integer can be simplified using unsafe.Add",
157 SuggestedFixes: []analysis.SuggestedFix{{
158 Message: "Simplify pointer addition using unsafe.Add",
159 TextEdits: edits,
160 }},
161 })
162 }
163 }
164
165 return nil, nil
166 }
167
168
169 func deleteConv(cur inspector.Cursor) []analysis.TextEdit {
170 conv := cur.Node().(*ast.CallExpr)
171
172 usesPrec := func(n ast.Node) bool {
173 switch n.(type) {
174 case *ast.BinaryExpr, *ast.UnaryExpr:
175 return true
176 }
177 return false
178 }
179
180
181
182 if usesPrec(cur.Parent().Node()) && usesPrec(conv.Args[0]) {
183
184
185
186 return []analysis.TextEdit{{
187 Pos: conv.Fun.Pos(),
188 End: conv.Fun.End(),
189 }}
190 }
191
192
193
194
195 return []analysis.TextEdit{
196 {
197 Pos: conv.Pos(),
198 End: conv.Args[0].Pos(),
199 },
200 {
201 Pos: conv.Args[0].End(),
202 End: conv.End(),
203 },
204 }
205 }
206
View as plain text