1
2
3
4
5 package pointer
6
7 import (
8 "errors"
9 "fmt"
10 "go/ast"
11 "go/parser"
12 "go/token"
13 "go/types"
14 "strconv"
15 )
16
17
18
19 type extendedQuery struct {
20 ops []interface{}
21 ptr *Pointer
22 }
23
24
25
26 func indexValue(expr ast.Expr) (int, error) {
27 lit, ok := expr.(*ast.BasicLit)
28 if !ok {
29 return 0, fmt.Errorf("non-integer index (%T)", expr)
30 }
31 if lit.Kind != token.INT {
32 return 0, fmt.Errorf("non-integer index %s", lit.Value)
33 }
34 return strconv.Atoi(lit.Value)
35 }
36
37
38
39
40 func parseExtendedQuery(typ types.Type, query string) ([]interface{}, types.Type, error) {
41 expr, err := parser.ParseExpr(query)
42 if err != nil {
43 return nil, nil, err
44 }
45 ops, typ, err := destructuringOps(typ, expr)
46 if err != nil {
47 return nil, nil, err
48 }
49 if len(ops) == 0 {
50 return nil, nil, errors.New("invalid query: must not be empty")
51 }
52 if ops[0] != "x" {
53 return nil, nil, fmt.Errorf("invalid query: query operand must be named x")
54 }
55 if !CanPoint(typ) {
56 return nil, nil, fmt.Errorf("query does not describe a pointer-like value: %s", typ)
57 }
58 return ops, typ, nil
59 }
60
61
62
63
64
65 func destructuringOps(typ types.Type, expr ast.Expr) ([]interface{}, types.Type, error) {
66 switch expr := expr.(type) {
67 case *ast.SelectorExpr:
68 out, typ, err := destructuringOps(typ, expr.X)
69 if err != nil {
70 return nil, nil, err
71 }
72
73 var structT *types.Struct
74 switch typ := typ.Underlying().(type) {
75 case *types.Pointer:
76 var ok bool
77 structT, ok = typ.Elem().Underlying().(*types.Struct)
78 if !ok {
79 return nil, nil, fmt.Errorf("cannot access field %s of pointer to type %s", expr.Sel.Name, typ.Elem())
80 }
81
82 out = append(out, "load")
83 case *types.Struct:
84 structT = typ
85 default:
86 return nil, nil, fmt.Errorf("cannot access field %s of type %s", expr.Sel.Name, typ)
87 }
88
89 for i := 0; i < structT.NumFields(); i++ {
90 field := structT.Field(i)
91 if field.Name() == expr.Sel.Name {
92 out = append(out, "field", i)
93 return out, field.Type().Underlying(), nil
94 }
95 }
96
97
98
99
100
101
102
103
104 return nil, nil, fmt.Errorf("no field %s in %s (embedded fields must be resolved manually)", expr.Sel.Name, structT)
105 case *ast.Ident:
106 return []interface{}{expr.Name}, typ, nil
107 case *ast.BasicLit:
108 return []interface{}{expr.Value}, nil, nil
109 case *ast.IndexExpr:
110 out, typ, err := destructuringOps(typ, expr.X)
111 if err != nil {
112 return nil, nil, err
113 }
114 switch typ := typ.Underlying().(type) {
115 case *types.Array:
116 out = append(out, "arrayelem")
117 return out, typ.Elem().Underlying(), nil
118 case *types.Slice:
119 out = append(out, "sliceelem")
120 return out, typ.Elem().Underlying(), nil
121 case *types.Map:
122 out = append(out, "mapelem")
123 return out, typ.Elem().Underlying(), nil
124 case *types.Tuple:
125 out = append(out, "index")
126 idx, err := indexValue(expr.Index)
127 if err != nil {
128 return nil, nil, err
129 }
130 out = append(out, idx)
131 if idx >= typ.Len() || idx < 0 {
132 return nil, nil, fmt.Errorf("tuple index %d out of bounds", idx)
133 }
134 return out, typ.At(idx).Type().Underlying(), nil
135 default:
136 return nil, nil, fmt.Errorf("cannot index type %s", typ)
137 }
138
139 case *ast.UnaryExpr:
140 if expr.Op != token.ARROW {
141 return nil, nil, fmt.Errorf("unsupported unary operator %s", expr.Op)
142 }
143 out, typ, err := destructuringOps(typ, expr.X)
144 if err != nil {
145 return nil, nil, err
146 }
147 ch, ok := typ.(*types.Chan)
148 if !ok {
149 return nil, nil, fmt.Errorf("cannot receive from value of type %s", typ)
150 }
151 out = append(out, "recv")
152 return out, ch.Elem().Underlying(), err
153 case *ast.ParenExpr:
154 return destructuringOps(typ, expr.X)
155 case *ast.StarExpr:
156 out, typ, err := destructuringOps(typ, expr.X)
157 if err != nil {
158 return nil, nil, err
159 }
160 ptr, ok := typ.(*types.Pointer)
161 if !ok {
162 return nil, nil, fmt.Errorf("cannot dereference type %s", typ)
163 }
164 out = append(out, "load")
165 return out, ptr.Elem().Underlying(), err
166 default:
167 return nil, nil, fmt.Errorf("unsupported expression %T", expr)
168 }
169 }
170
171 func (a *analysis) evalExtendedQuery(t types.Type, id nodeid, ops []interface{}) (types.Type, nodeid) {
172 pid := id
173
174
175
176 for i := 1; i < len(ops); i++ {
177 var nid nodeid
178 switch ops[i] {
179 case "recv":
180 t = t.(*types.Chan).Elem().Underlying()
181 nid = a.addNodes(t, "query.extended")
182 a.load(nid, pid, 0, a.sizeof(t))
183 case "field":
184 i++
185 tt := t.(*types.Struct)
186 idx := ops[i].(int)
187 offset := a.offsetOf(t, idx)
188 t = tt.Field(idx).Type().Underlying()
189 nid = a.addNodes(t, "query.extended")
190 a.copy(nid, pid+nodeid(offset), a.sizeof(t))
191 case "arrayelem":
192 t = t.(*types.Array).Elem().Underlying()
193 nid = a.addNodes(t, "query.extended")
194 a.copy(nid, 1+pid, a.sizeof(t))
195 case "sliceelem":
196 t = t.(*types.Slice).Elem().Underlying()
197 nid = a.addNodes(t, "query.extended")
198 a.load(nid, pid, 1, a.sizeof(t))
199 case "mapelem":
200 tt := t.(*types.Map)
201 t = tt.Elem()
202 ksize := a.sizeof(tt.Key())
203 vsize := a.sizeof(tt.Elem())
204 nid = a.addNodes(t, "query.extended")
205 a.load(nid, pid, ksize, vsize)
206 case "index":
207 i++
208 tt := t.(*types.Tuple)
209 idx := ops[i].(int)
210 t = tt.At(idx).Type().Underlying()
211 nid = a.addNodes(t, "query.extended")
212 a.copy(nid, pid+nodeid(idx), a.sizeof(t))
213 case "load":
214 t = t.(*types.Pointer).Elem().Underlying()
215 nid = a.addNodes(t, "query.extended")
216 a.load(nid, pid, 0, a.sizeof(t))
217 default:
218
219 panic(fmt.Sprintf("unknown op %q", ops[i]))
220 }
221 pid = nid
222 }
223
224 return t, pid
225 }
226
View as plain text