GoPLS Viewer

Home|gopls/go/pointer/labels.go
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.
4
5package pointer
6
7import (
8    "fmt"
9    "go/token"
10    "go/types"
11    "strings"
12
13    "golang.org/x/tools/go/ssa"
14)
15
16// A Label is an entity that may be pointed to by a pointer, map,
17// channel, 'func', slice or interface.
18//
19// Labels include:
20//   - functions
21//   - globals
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"
29//
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.
34//
35// At most one of Value() or ReflectType() may return non-nil.
36type Label struct {
37    obj        *object    // the addressable memory location containing this label
38    subelement *fieldInfo // subelement path within obj, e.g. ".a.b[*].c"
39}
40
41// Value returns the ssa.Value that allocated this label's object, if any.
42func (l LabelValue() ssa.Value {
43    val_ := l.obj.data.(ssa.Value)
44    return val
45}
46
47// ReflectType returns the type represented by this label if it is an
48// reflect.rtype instance object or *reflect.rtype-tagged object.
49func (l LabelReflectType() types.Type {
50    rtype_ := l.obj.data.(types.Type)
51    return rtype
52}
53
54// Path returns the path to the subelement of the object containing
55// this label.  For example, ".x[*].y".
56func (l LabelPath() string {
57    return l.subelement.path()
58}
59
60// Pos returns the position of this label, if known, zero otherwise.
61func (l LabelPos() token.Pos {
62    switch data := l.obj.data.(type) {
63    case ssa.Value:
64        return data.Pos()
65    case types.Type:
66        if ntok := deref(data).(*types.Named); ok {
67            return nt.Obj().Pos()
68        }
69    }
70    if cgn := l.obj.cgncgn != nil {
71        return cgn.fn.Pos()
72    }
73    return token.NoPos
74}
75
76// String returns the printed form of this label.
77//
78// Examples:                                    Object type:
79//
80//    x                                       (a variable)
81//    (sync.Mutex).Lock                       (a function)
82//    convert                                 (array created by conversion)
83//    makemap                                 (map allocated via make)
84//    makechan                                (channel allocated via make)
85//    makeinterface                           (tagged object allocated by makeinterface)
86//    <alloc in reflect.Zero>                 (allocation in instrinsic)
87//    sync.Mutex                              (a reflect.rtype instance)
88//    <command-line arguments>                (an intrinsic object)
89//
90// Labels within compound objects have subelement paths:
91//
92//    x.y[*].z                                (a struct variable, x)
93//    append.y[*].z                           (array allocated by append)
94//    makeslice.y[*].z                        (array allocated via make)
95//
96// TODO(adonovan): expose func LabelString(*types.Package, Label).
97func (l LabelString() string {
98    var s string
99    switch v := l.obj.data.(type) {
100    case types.Type:
101        return v.String()
102
103    case string:
104        s = v // an intrinsic object (e.g. os.Args[*])
105
106    case nil:
107        if l.obj.cgn != nil {
108            // allocation by intrinsic or reflective operation
109            s = fmt.Sprintf("<alloc in %s>"l.obj.cgn.fn)
110        } else {
111            s = "<unknown>" // should be unreachable
112        }
113
114    case *ssa.Function:
115        s = v.String()
116
117    case *ssa.Global:
118        s = v.String()
119
120    case *ssa.Const:
121        s = v.Name()
122
123    case *ssa.Alloc:
124        s = v.Comment
125        if s == "" {
126            s = "alloc"
127        }
128
129    case *ssa.Call:
130        // Currently only calls to append can allocate objects.
131        if v.Call.Value.(*ssa.Builtin).Object().Name() != "append" {
132            panic("unhandled *ssa.Call label: " + v.Name())
133        }
134        s = "append"
135
136    case *ssa.MakeMap, *ssa.MakeChan, *ssa.MakeSlice, *ssa.Convert:
137        s = strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T"v), "*ssa."))
138
139    case *ssa.MakeInterface:
140        // MakeInterface is usually implicit in Go source (so
141        // Pos()==0), and tagged objects may be allocated
142        // synthetically (so no *MakeInterface data).
143        s = "makeinterface:" + v.X.Type().String()
144
145    default:
146        panic(fmt.Sprintf("unhandled object data type: %T"v))
147    }
148
149    return s + l.subelement.path()
150}
151
MembersX
Label.ReflectType.l
Label.Path
Label.Pos.cgn
Label.subelement
Label.Value.l
Label.String
Label
Label.Value
Label.ReflectType
Label.Pos.l
Label.Pos
Label.String.s
Label.obj
Label.Path.l
Label.String.l
Members
X