1
2
3
4
5
6
7 package analysisutil
8
9 import (
10 "bytes"
11 "go/ast"
12 "go/printer"
13 "go/token"
14 "go/types"
15 "os"
16
17 "golang.org/x/tools/go/analysis"
18 "golang.org/x/tools/internal/analysisinternal"
19 )
20
21
22 func Format(fset *token.FileSet, x ast.Expr) string {
23 var b bytes.Buffer
24 printer.Fprint(&b, fset, x)
25 return b.String()
26 }
27
28
29 func HasSideEffects(info *types.Info, e ast.Expr) bool {
30 safe := true
31 ast.Inspect(e, func(node ast.Node) bool {
32 switch n := node.(type) {
33 case *ast.CallExpr:
34 typVal := info.Types[n.Fun]
35 switch {
36 case typVal.IsType():
37
38 case typVal.IsBuiltin():
39
40
41 safe = false
42 return false
43 default:
44
45
46
47 safe = false
48 return false
49 }
50 case *ast.UnaryExpr:
51 if n.Op == token.ARROW {
52 safe = false
53 return false
54 }
55 }
56 return true
57 })
58 return !safe
59 }
60
61
62
63 func ReadFile(pass *analysis.Pass, filename string) ([]byte, *token.File, error) {
64 readFile := pass.ReadFile
65 if readFile == nil {
66 readFile = os.ReadFile
67 }
68 content, err := readFile(filename)
69 if err != nil {
70 return nil, nil, err
71 }
72 tf := pass.Fset.AddFile(filename, -1, len(content))
73 tf.SetLinesForContent(content)
74 return content, tf, nil
75 }
76
77
78
79 func LineStart(f *token.File, line int) token.Pos {
80
81
82
83
84
85
86 min := 0
87 max := f.Size()
88 for {
89 offset := (min + max) / 2
90 pos := f.Pos(offset)
91 posn := f.Position(pos)
92 if posn.Line == line {
93 return pos - (token.Pos(posn.Column) - 1)
94 }
95
96 if min+1 >= max {
97 return token.NoPos
98 }
99
100 if posn.Line < line {
101 min = offset
102 } else {
103 max = offset
104 }
105 }
106 }
107
108
109 func Imports(pkg *types.Package, path string) bool {
110 for _, imp := range pkg.Imports() {
111 if imp.Path() == path {
112 return true
113 }
114 }
115 return false
116 }
117
118
119
120
121
122 func IsNamedType(t types.Type, pkgPath string, names ...string) bool {
123 n, ok := types.Unalias(t).(*types.Named)
124 if !ok {
125 return false
126 }
127 obj := n.Obj()
128 if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != pkgPath {
129 return false
130 }
131 name := obj.Name()
132 for _, n := range names {
133 if name == n {
134 return true
135 }
136 }
137 return false
138 }
139
140
141
142
143 func IsFunctionNamed(f *types.Func, pkgPath string, names ...string) bool {
144 if f == nil {
145 return false
146 }
147 if f.Pkg() == nil || f.Pkg().Path() != pkgPath {
148 return false
149 }
150 if f.Type().(*types.Signature).Recv() != nil {
151 return false
152 }
153 for _, n := range names {
154 if f.Name() == n {
155 return true
156 }
157 }
158 return false
159 }
160
161 var MustExtractDoc = analysisinternal.MustExtractDoc
162
View as plain text