mirror of
https://github.com/golang/go
synced 2024-11-18 21:54:49 -07:00
go.tools/pointer: replace Pointer, PointsToSet interfaces with their sole implementations.
(Elminate premature abstraction.) The test probes used Pointer!=nil for the "is pointerlike" predicate. Now that Pointer is a struct, they check the type of the expression, which is more accurate. Two probes on non-pointerlike values have beem removed. R=crawshaw CC=golang-dev https://golang.org/cl/38420043
This commit is contained in:
parent
2d324f247c
commit
6b75c15eec
@ -88,7 +88,7 @@ func peers(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||
var sends, receives []token.Pos
|
||||
for _, op := range ops {
|
||||
for _, ptr := range ptares.Queries[op.ch] {
|
||||
if ptr != nil && ptr.PointsTo().Intersects(queryChanPts) {
|
||||
if ptr.PointsTo().Intersects(queryChanPts) {
|
||||
if op.dir == ast.SEND {
|
||||
sends = append(sends, op.pos)
|
||||
} else {
|
||||
|
118
pointer/api.go
118
pointer/api.go
@ -40,7 +40,10 @@ type Config struct {
|
||||
// Pointer p may be saved until the analysis is complete, at
|
||||
// which point its methods provide access to the analysis
|
||||
// (The result of callings its methods within the Print
|
||||
// callback is undefined.) p is nil if x is non-pointerlike.
|
||||
// callback is undefined.)
|
||||
//
|
||||
// CanPoint(site.Args[0].Type()) reports whether p is
|
||||
// pointerlike.
|
||||
//
|
||||
Print func(site *ssa.CallCommon, p Pointer)
|
||||
|
||||
@ -117,53 +120,26 @@ type Result struct {
|
||||
}
|
||||
|
||||
// A Pointer is an equivalence class of pointerlike values.
|
||||
type Pointer interface {
|
||||
// PointsTo returns the points-to set of this pointer.
|
||||
PointsTo() PointsToSet
|
||||
|
||||
// MayAlias reports whether the receiver pointer may alias
|
||||
// the argument pointer.
|
||||
MayAlias(Pointer) bool
|
||||
|
||||
// Context returns the context of this pointer,
|
||||
// if it corresponds to a local variable.
|
||||
Context() call.GraphNode
|
||||
|
||||
String() string
|
||||
//
|
||||
// A pointer doesn't have a unique type because pointers of distinct
|
||||
// types may alias the same object.
|
||||
//
|
||||
type Pointer struct {
|
||||
a *analysis
|
||||
cgn *cgnode
|
||||
n nodeid // non-zero
|
||||
}
|
||||
|
||||
// A PointsToSet is a set of labels (locations or allocations).
|
||||
//
|
||||
type PointsToSet interface {
|
||||
// PointsTo returns the set of labels that this points-to set
|
||||
// contains.
|
||||
Labels() []*Label
|
||||
|
||||
// Intersects reports whether this points-to set and the
|
||||
// argument points-to set contain common members.
|
||||
Intersects(PointsToSet) bool
|
||||
|
||||
// If this PointsToSet came from a Pointer of interface kind
|
||||
// or a reflect.Value, DynamicTypes returns the set of dynamic
|
||||
// types that it may contain. (For an interface, they will
|
||||
// always be concrete types.)
|
||||
//
|
||||
// The result is a mapping whose keys are the dynamic types to
|
||||
// which it may point. For each pointer-like key type, the
|
||||
// corresponding map value is a set of pointer abstractions of
|
||||
// that dynamic type, represented as a []Pointer slice. Use
|
||||
// PointsToCombined to merge them.
|
||||
//
|
||||
// The result is empty unless CanHaveDynamicTypes(T).
|
||||
//
|
||||
DynamicTypes() *typemap.M
|
||||
type PointsToSet struct {
|
||||
a *analysis // may be nil if pts is nil
|
||||
pts nodeset
|
||||
}
|
||||
|
||||
// Union returns the set containing all the elements of each set in sets.
|
||||
func Union(sets ...PointsToSet) PointsToSet {
|
||||
var union ptset
|
||||
var union PointsToSet
|
||||
for _, set := range sets {
|
||||
set := set.(ptset)
|
||||
union.a = set.a
|
||||
union.pts.addAll(set.pts)
|
||||
}
|
||||
@ -180,14 +156,7 @@ func PointsToCombined(ptrs []Pointer) PointsToSet {
|
||||
return Union(ptsets...)
|
||||
}
|
||||
|
||||
// ---- PointsToSet public interface
|
||||
|
||||
type ptset struct {
|
||||
a *analysis // may be nil if pts is nil
|
||||
pts nodeset
|
||||
}
|
||||
|
||||
func (s ptset) String() string {
|
||||
func (s PointsToSet) String() string {
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintf(&buf, "[")
|
||||
sep := ""
|
||||
@ -199,7 +168,9 @@ func (s ptset) String() string {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (s ptset) Labels() []*Label {
|
||||
// PointsTo returns the set of labels that this points-to set
|
||||
// contains.
|
||||
func (s PointsToSet) Labels() []*Label {
|
||||
var labels []*Label
|
||||
for l := range s.pts {
|
||||
labels = append(labels, s.a.labelFor(l))
|
||||
@ -207,7 +178,20 @@ func (s ptset) Labels() []*Label {
|
||||
return labels
|
||||
}
|
||||
|
||||
func (s ptset) DynamicTypes() *typemap.M {
|
||||
// If this PointsToSet came from a Pointer of interface kind
|
||||
// or a reflect.Value, DynamicTypes returns the set of dynamic
|
||||
// types that it may contain. (For an interface, they will
|
||||
// always be concrete types.)
|
||||
//
|
||||
// The result is a mapping whose keys are the dynamic types to
|
||||
// which it may point. For each pointer-like key type, the
|
||||
// corresponding map value is a set of pointer abstractions of
|
||||
// that dynamic type, represented as a []Pointer slice. Use
|
||||
// PointsToCombined to merge them.
|
||||
//
|
||||
// The result is empty unless CanHaveDynamicTypes(T).
|
||||
//
|
||||
func (s PointsToSet) DynamicTypes() *typemap.M {
|
||||
var tmap typemap.M
|
||||
tmap.SetHasher(s.a.hasher)
|
||||
for ifaceObjId := range s.pts {
|
||||
@ -219,13 +203,14 @@ func (s ptset) DynamicTypes() *typemap.M {
|
||||
panic("indirect tagged object") // implement later
|
||||
}
|
||||
prev, _ := tmap.At(tDyn).([]Pointer)
|
||||
tmap.Set(tDyn, append(prev, ptr{s.a, nil, v}))
|
||||
tmap.Set(tDyn, append(prev, Pointer{s.a, nil, v}))
|
||||
}
|
||||
return &tmap
|
||||
}
|
||||
|
||||
func (x ptset) Intersects(y_ PointsToSet) bool {
|
||||
y := y_.(ptset)
|
||||
// Intersects reports whether this points-to set and the
|
||||
// argument points-to set contain common members.
|
||||
func (x PointsToSet) Intersects(y PointsToSet) bool {
|
||||
for l := range x.pts {
|
||||
if _, ok := y.pts[l]; ok {
|
||||
return true
|
||||
@ -234,31 +219,28 @@ func (x ptset) Intersects(y_ PointsToSet) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ---- Pointer public interface
|
||||
|
||||
// ptr adapts a node to the Pointer interface.
|
||||
type ptr struct {
|
||||
a *analysis
|
||||
cgn *cgnode
|
||||
n nodeid // non-zero
|
||||
}
|
||||
|
||||
func (p ptr) String() string {
|
||||
func (p Pointer) String() string {
|
||||
return fmt.Sprintf("n%d", p.n)
|
||||
}
|
||||
|
||||
func (p ptr) Context() call.GraphNode {
|
||||
// Context returns the context of this pointer,
|
||||
// if it corresponds to a local variable.
|
||||
func (p Pointer) Context() call.GraphNode {
|
||||
return p.cgn
|
||||
}
|
||||
|
||||
func (p ptr) PointsTo() PointsToSet {
|
||||
return ptset{p.a, p.a.nodes[p.n].pts}
|
||||
// PointsTo returns the points-to set of this pointer.
|
||||
func (p Pointer) PointsTo() PointsToSet {
|
||||
return PointsToSet{p.a, p.a.nodes[p.n].pts}
|
||||
}
|
||||
|
||||
func (p ptr) MayAlias(q Pointer) bool {
|
||||
// MayAlias reports whether the receiver pointer may alias
|
||||
// the argument pointer.
|
||||
func (p Pointer) MayAlias(q Pointer) bool {
|
||||
return p.PointsTo().Intersects(q.PointsTo())
|
||||
}
|
||||
|
||||
func (p ptr) DynamicTypes() *typemap.M {
|
||||
// DynamicTypes returns p.PointsTo().DynamicTypes().
|
||||
func (p Pointer) DynamicTypes() *typemap.M {
|
||||
return p.PointsTo().DynamicTypes()
|
||||
}
|
||||
|
@ -82,14 +82,14 @@ func (a *analysis) setValueNode(v ssa.Value, id nodeid, cgn *cgnode) {
|
||||
|
||||
// Record the (v, id) relation if the client has queried pts(v).
|
||||
if _, ok := a.config.Queries[v]; ok {
|
||||
a.result.Queries[v] = append(a.result.Queries[v], ptr{a, cgn, id})
|
||||
a.result.Queries[v] = append(a.result.Queries[v], Pointer{a, cgn, id})
|
||||
}
|
||||
|
||||
// Record the (*v, id) relation if the client has queried pts(*v).
|
||||
if _, ok := a.config.IndirectQueries[v]; ok {
|
||||
indirect := a.addNodes(v.Type(), "query.indirect")
|
||||
a.genLoad(cgn, indirect, v, 0, a.sizeof(v.Type()))
|
||||
a.result.IndirectQueries[v] = append(a.result.IndirectQueries[v], ptr{a, cgn, indirect})
|
||||
a.result.IndirectQueries[v] = append(a.result.IndirectQueries[v], Pointer{a, cgn, indirect})
|
||||
}
|
||||
}
|
||||
|
||||
@ -539,7 +539,7 @@ func (a *analysis) genBuiltinCall(instr ssa.CallInstruction, cgn *cgnode) {
|
||||
if probe == 0 {
|
||||
probe = a.addNodes(t, "print")
|
||||
a.probes[call] = probe
|
||||
Print(call, ptr{a, nil, probe}) // notify client
|
||||
Print(call, Pointer{a, nil, probe}) // notify client
|
||||
}
|
||||
|
||||
a.copy(probe, a.valueNode(call.Args[0]), a.sizeof(t))
|
||||
|
@ -309,9 +309,9 @@ func doOneInput(input, filename string) bool {
|
||||
e.errorf("unreachable print() statement has expectation %s", e)
|
||||
continue
|
||||
}
|
||||
if pr.arg0 == nil {
|
||||
if tArg := pr.instr.Args[0].Type(); !pointer.CanPoint(tArg) {
|
||||
ok = false
|
||||
e.errorf("expectation on non-pointerlike operand: %s", pr.instr.Args[0].Type())
|
||||
e.errorf("expectation on non-pointerlike operand: %s", tArg)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
1
pointer/testdata/another.go
vendored
1
pointer/testdata/another.go
vendored
@ -31,5 +31,4 @@ func main() {
|
||||
// labels, even though it may contain pointers that do.
|
||||
print(i) // @pointsto makeinterface:func(x int) int | makeinterface:func(x int, y int) | makeinterface:func(int, int) | makeinterface:int | makeinterface:main.S
|
||||
print(i.(func(int) int)) // @pointsto main.incr
|
||||
print(i.(S)) // @pointsto
|
||||
}
|
||||
|
1
pointer/testdata/structs.go
vendored
1
pointer/testdata/structs.go
vendored
@ -87,7 +87,6 @@ func structs2() {
|
||||
|
||||
var s3 S // @line s2s3
|
||||
s3.c[2] = new(T) // @line s2s3c
|
||||
print(s3.c) // @pointsto
|
||||
print(&s3.c) // @pointsto s3.c@s2s3:6
|
||||
print(s3.c[1]) // @pointsto new@s2s3c:15
|
||||
print(&s3.c[1]) // @pointsto s3.c[*]@s2s3:6
|
||||
|
Loading…
Reference in New Issue
Block a user