Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(797)

Delta Between Two Patch Sets: oracle/peers.go

Issue 13270045: code review 13270045: go.tools/oracle: add option to output results in JSON s... (Closed)
Left Patch Set: diff -r 7c53df5c9267 https://code.google.com/p/go.tools Created 10 years, 7 months ago
Right Patch Set: diff -r 07183b5c385c https://code.google.com/p/go.tools Created 10 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « oracle/oracle_test.go ('k') | oracle/testdata/src/main/callgraph.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2013 The Go Authors. All rights reserved. 1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package oracle 5 package oracle
6 6
7 import ( 7 import (
8 "go/ast" 8 "go/ast"
9 "go/token" 9 "go/token"
10 "sort"
10 11
11 "code.google.com/p/go.tools/go/types" 12 "code.google.com/p/go.tools/go/types"
13 "code.google.com/p/go.tools/oracle/json"
12 "code.google.com/p/go.tools/pointer" 14 "code.google.com/p/go.tools/pointer"
13 "code.google.com/p/go.tools/ssa" 15 "code.google.com/p/go.tools/ssa"
14 ) 16 )
15 17
16 // peers enumerates, for a given channel send (or receive) operation, 18 // peers enumerates, for a given channel send (or receive) operation,
17 // the set of possible receives (or sends) that correspond to it. 19 // the set of possible receives (or sends) that correspond to it.
18 // 20 //
19 // TODO(adonovan): support reflect.{Select,Recv,Send}. 21 // TODO(adonovan): support reflect.{Select,Recv,Send}.
20 // TODO(adonovan): permit the user to query based on a MakeChan (not send/recv), 22 // TODO(adonovan): permit the user to query based on a MakeChan (not send/recv),
21 // or the implicit receive in "for v := range ch". 23 // or the implicit receive in "for v := range ch".
(...skipping 23 matching lines...) Expand all
45 } 47 }
46 } 48 }
47 } 49 }
48 } 50 }
49 if queryOp.ch == nil { 51 if queryOp.ch == nil {
50 return nil, o.errorf(arrowPos, "ssa.Instruction for send/receive not found") 52 return nil, o.errorf(arrowPos, "ssa.Instruction for send/receive not found")
51 } 53 }
52 54
53 // Discard operations of wrong channel element type. 55 // Discard operations of wrong channel element type.
54 // Build set of channel ssa.Values as query to pointer analysis. 56 // Build set of channel ssa.Values as query to pointer analysis.
55 » queryElemType := queryOp.ch.Type().Underlying().(*types.Chan).Elem() 57 » // We compare channels by element types, not channel types, to
58 » // ignore both directionality and type names.
59 » queryType := queryOp.ch.Type()
60 » queryElemType := queryType.Underlying().(*types.Chan).Elem()
56 channels := map[ssa.Value][]pointer.Pointer{queryOp.ch: nil} 61 channels := map[ssa.Value][]pointer.Pointer{queryOp.ch: nil}
57 i := 0 62 i := 0
58 for _, op := range ops { 63 for _, op := range ops {
59 if types.IsIdentical(op.ch.Type().Underlying().(*types.Chan).Ele m(), queryElemType) { 64 if types.IsIdentical(op.ch.Type().Underlying().(*types.Chan).Ele m(), queryElemType) {
60 channels[op.ch] = nil 65 channels[op.ch] = nil
61 ops[i] = op 66 ops[i] = op
62 i++ 67 i++
63 } 68 }
64 } 69 }
65 ops = ops[:i] 70 ops = ops[:i]
66 71
67 // Run the pointer analysis. 72 // Run the pointer analysis.
68 o.config.QueryValues = channels 73 o.config.QueryValues = channels
69 ptrAnalysis(o) 74 ptrAnalysis(o)
70 75
71 // Combine the PT sets from all contexts. 76 // Combine the PT sets from all contexts.
72 queryChanPts := pointer.PointsToCombined(channels[queryOp.ch]) 77 queryChanPts := pointer.PointsToCombined(channels[queryOp.ch])
73 78
79 // Ascertain which make(chan) labels the query's channel can alias.
80 var makes []token.Pos
81 for _, label := range queryChanPts.Labels() {
82 makes = append(makes, label.Pos())
83 }
84 sort.Sort(byPos(makes))
85
86 // Ascertain which send/receive operations can alias the same make(chan) labels.
87 var sends, receives []token.Pos
88 for _, op := range ops {
89 for _, ptr := range o.config.QueryValues[op.ch] {
90 if ptr != nil && ptr.PointsTo().Intersects(queryChanPts) {
91 if op.dir == ast.SEND {
92 sends = append(sends, op.pos)
93 } else {
94 receives = append(receives, op.pos)
95 }
96 }
97 }
98 }
99 sort.Sort(byPos(sends))
100 sort.Sort(byPos(receives))
101
74 return &peersResult{ 102 return &peersResult{
75 » » queryOp: queryOp, 103 » » queryPos: arrowPos,
76 » » ops: ops, 104 » » queryType: queryType,
77 » » queryChanPts: queryChanPts, 105 » » makes: makes,
106 » » sends: sends,
107 » » receives: receives,
78 }, nil 108 }, nil
79 } 109 }
80 110
81 // findArrow returns the position of the enclosing send/receive op 111 // findArrow returns the position of the enclosing send/receive op
82 // (<-) for the query position, or token.NoPos if not found. 112 // (<-) for the query position, or token.NoPos if not found.
83 // 113 //
84 func findArrow(o *oracle) token.Pos { 114 func findArrow(o *oracle) token.Pos {
85 for _, n := range o.queryPath { 115 for _, n := range o.queryPath {
86 switch n := n.(type) { 116 switch n := n.(type) {
87 case *ast.UnaryExpr: 117 case *ast.UnaryExpr:
(...skipping 27 matching lines...) Expand all
115 ops = append(ops, chanOp{instr.Chan, ast.SEND, instr.Pos()}) 145 ops = append(ops, chanOp{instr.Chan, ast.SEND, instr.Pos()})
116 case *ssa.Select: 146 case *ssa.Select:
117 for _, st := range instr.States { 147 for _, st := range instr.States {
118 ops = append(ops, chanOp{st.Chan, st.Dir, st.Pos}) 148 ops = append(ops, chanOp{st.Chan, st.Dir, st.Pos})
119 } 149 }
120 } 150 }
121 return ops 151 return ops
122 } 152 }
123 153
124 type peersResult struct { 154 type peersResult struct {
125 » queryOp chanOp 155 » queryPos token.Pos // of queried '<-' token
126 » ops []chanOp 156 » queryType types.Type // type of queried channel
127 » queryChanPts pointer.PointsToSet 157 » makes, sends, receives []token.Pos // positions of alisaed makechan/send /receive instrs
128 } 158 }
129 159
130 func (r *peersResult) display(o *oracle) { 160 func (r *peersResult) display(printf printfFunc) {
131 » // Report which make(chan) labels the query's channel can alias. 161 » if len(r.makes) == 0 {
132 » labels := r.queryChanPts.Labels() 162 » » printf(r.queryPos, "This channel can't point to anything.")
133 » if len(labels) == 0 {
134 » » o.printf(r.queryOp.pos, "This channel can't point to anything.")
135 return 163 return
136 } 164 }
137 » o.printf(r.queryOp.pos, "This channel of type %s may be:", r.queryOp.ch. Type()) 165 » printf(r.queryPos, "This channel of type %s may be:", r.queryType)
138 » // TODO(adonovan): sort, to ensure test determinism. 166 » for _, alloc := range r.makes {
139 » for _, label := range labels { 167 » » printf(alloc, "\tallocated here")
140 » » o.printf(label, "\tallocated here") 168 » }
141 » } 169 » for _, send := range r.sends {
142 170 » » printf(send, "\tsent to, here")
143 » // Report which send/receive operations can alias the same make(chan) la bels. 171 » }
144 » for _, op := range r.ops { 172 » for _, receive := range r.receives {
145 » » // TODO(adonovan): sort, to ensure test determinism. 173 » » printf(receive, "\treceived from, here")
146 » » for _, ptr := range o.config.QueryValues[op.ch] { 174 » }
147 » » » if ptr != nil && ptr.PointsTo().Intersects(r.queryChanPt s) { 175 }
148 » » » » verb := "received from" 176
149 » » » » if op.dir == ast.SEND { 177 func (r *peersResult) toJSON(res *json.Result, fset *token.FileSet) {
150 » » » » » verb = "sent to" 178 » peers := &json.Peers{
151 » » » » } 179 » » Pos: fset.Position(r.queryPos).String(),
152 » » » » o.printf(op.pos, "\t%s, here", verb) 180 » » Type: r.queryType.String(),
153 » » » } 181 » }
154 » » } 182 » for _, alloc := range r.makes {
155 » } 183 » » peers.Allocs = append(peers.Allocs, fset.Position(alloc).String( ))
156 } 184 » }
185 » for _, send := range r.sends {
186 » » peers.Sends = append(peers.Sends, fset.Position(send).String())
187 » }
188 » for _, receive := range r.receives {
189 » » peers.Receives = append(peers.Receives, fset.Position(receive).S tring())
190 » }
191 » res.Peers = peers
192 }
193
194 // -------- utils --------
195
196 type byPos []token.Pos
197
198 func (p byPos) Len() int { return len(p) }
199 func (p byPos) Less(i, j int) bool { return p[i] < p[j] }
200 func (p byPos) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b