github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/pointer/labels.go (about) 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 5 package pointer 6 7 import ( 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. 36 type 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. 42 func (l Label) Value() 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. 49 func (l Label) ReflectType() 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". 56 func (l Label) Path() string { 57 return l.subelement.path() 58 } 59 60 // Pos returns the position of this label, if known, zero otherwise. 61 func (l Label) Pos() token.Pos { 62 switch data := l.obj.data.(type) { 63 case ssa.Value: 64 return data.Pos() 65 case types.Type: 66 if nt, ok := deref(data).(*types.Named); ok { 67 return nt.Obj().Pos() 68 } 69 } 70 if cgn := l.obj.cgn; cgn != 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). 97 func (l Label) String() 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 }