1
2
3
4
5
6
7 package analysisutil
8
9 import (
10 "go/ast"
11 "go/token"
12 "go/types"
13 "os"
14
15 "golang.org/x/tools/go/analysis"
16 "golang.org/x/tools/internal/analysisinternal"
17 )
18
19
20 func HasSideEffects(info *types.Info, e ast.Expr) bool {
21 safe := true
22 ast.Inspect(e, func(node ast.Node) bool {
23 switch n := node.(type) {
24 case *ast.CallExpr:
25 typVal := info.Types[n.Fun]
26 switch {
27 case typVal.IsType():
28
29 case typVal.IsBuiltin():
30
31
32 safe = false
33 return false
34 default:
35
36
37
38 safe = false
39 return false
40 }
41 case *ast.UnaryExpr:
42 if n.Op == token.ARROW {
43 safe = false
44 return false
45 }
46 }
47 return true
48 })
49 return !safe
50 }
51
52
53
54 func ReadFile(pass *analysis.Pass, filename string) ([]byte, *token.File, error) {
55 readFile := pass.ReadFile
56 if readFile == nil {
57 readFile = os.ReadFile
58 }
59 content, err := readFile(filename)
60 if err != nil {
61 return nil, nil, err
62 }
63 tf := pass.Fset.AddFile(filename, -1, len(content))
64 tf.SetLinesForContent(content)
65 return content, tf, nil
66 }
67
68
69
70 func LineStart(f *token.File, line int) token.Pos {
71
72
73
74
75
76
77 min := 0
78 max := f.Size()
79 for {
80 offset := (min + max) / 2
81 pos := f.Pos(offset)
82 posn := f.Position(pos)
83 if posn.Line == line {
84 return pos - (token.Pos(posn.Column) - 1)
85 }
86
87 if min+1 >= max {
88 return token.NoPos
89 }
90
91 if posn.Line < line {
92 min = offset
93 } else {
94 max = offset
95 }
96 }
97 }
98
99 var MustExtractDoc = analysisinternal.MustExtractDoc
100
View as plain text