1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
13 "golang.org/x/tools/go/ssa"
16 // A Label is an entity that may be pointed to by a pointer, map,
17 // channel, 'func', slice or interface.
22 // - tagged objects, representing interfaces and reflect.Values
23 // - arrays created by conversions (e.g. []byte("foo"), []byte(s))
24 // - stack- and heap-allocated variables (including composite literals)
25 // - channels, maps and arrays created by make()
26 // - intrinsic or reflective operations that allocate (e.g. append, reflect.New)
27 // - intrinsic objects, e.g. the initial array behind os.Args.
28 // - and their subelements, e.g. "alloc.y[*].z"
30 // Labels are so varied that they defy good generalizations;
31 // some have no value, no callgraph node, or no position.
32 // Many objects have types that are inexpressible in Go:
33 // maps, channels, functions, tagged objects.
35 // At most one of Value() or ReflectType() may return non-nil.
38 obj *object // the addressable memory location containing this label
39 subelement *fieldInfo // subelement path within obj, e.g. ".a.b[*].c"
42 // Value returns the ssa.Value that allocated this label's object, if any.
43 func (l Label) Value() ssa.Value {
44 val, _ := l.obj.data.(ssa.Value)
48 // ReflectType returns the type represented by this label if it is an
49 // reflect.rtype instance object or *reflect.rtype-tagged object.
51 func (l Label) ReflectType() types.Type {
52 rtype, _ := l.obj.data.(types.Type)
56 // Path returns the path to the subelement of the object containing
57 // this label. For example, ".x[*].y".
59 func (l Label) Path() string {
60 return l.subelement.path()
63 // Pos returns the position of this label, if known, zero otherwise.
64 func (l Label) Pos() token.Pos {
65 switch data := l.obj.data.(type) {
69 if nt, ok := deref(data).(*types.Named); ok {
73 if cgn := l.obj.cgn; cgn != nil {
79 // String returns the printed form of this label.
81 // Examples: Object type:
83 // (sync.Mutex).Lock (a function)
84 // convert (array created by conversion)
85 // makemap (map allocated via make)
86 // makechan (channel allocated via make)
87 // makeinterface (tagged object allocated by makeinterface)
88 // <alloc in reflect.Zero> (allocation in instrinsic)
89 // sync.Mutex (a reflect.rtype instance)
90 // <command-line arguments> (an intrinsic object)
92 // Labels within compound objects have subelement paths:
93 // x.y[*].z (a struct variable, x)
94 // append.y[*].z (array allocated by append)
95 // makeslice.y[*].z (array allocated via make)
97 // TODO(adonovan): expose func LabelString(*types.Package, Label).
99 func (l Label) String() string {
101 switch v := l.obj.data.(type) {
106 s = v // an intrinsic object (e.g. os.Args[*])
109 if l.obj.cgn != nil {
110 // allocation by intrinsic or reflective operation
111 s = fmt.Sprintf("<alloc in %s>", l.obj.cgn.fn)
113 s = "<unknown>" // should be unreachable
132 // Currently only calls to append can allocate objects.
133 if v.Call.Value.(*ssa.Builtin).Object().Name() != "append" {
134 panic("unhandled *ssa.Call label: " + v.Name())
138 case *ssa.MakeMap, *ssa.MakeChan, *ssa.MakeSlice, *ssa.Convert:
139 s = strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T", v), "*ssa."))
141 case *ssa.MakeInterface:
142 // MakeInterface is usually implicit in Go source (so
143 // Pos()==0), and tagged objects may be allocated
144 // synthetically (so no *MakeInterface data).
145 s = "makeinterface:" + v.X.Type().String()
148 panic(fmt.Sprintf("unhandled object data type: %T", v))
151 return s + l.subelement.path()