github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/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 "github.com/powerman/golang-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 // 37 type Label struct { 38 obj *object // the addressable memory location containing this label 39 subelement *fieldInfo // subelement path within obj, e.g. ".a.b[*].c" 40 } 41 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) 45 return val 46 } 47 48 // ReflectType returns the type represented by this label if it is an 49 // reflect.rtype instance object or *reflect.rtype-tagged object. 50 // 51 func (l Label) ReflectType() types.Type { 52 rtype, _ := l.obj.data.(types.Type) 53 return rtype 54 } 55 56 // Path returns the path to the subelement of the object containing 57 // this label. For example, ".x[*].y". 58 // 59 func (l Label) Path() string { 60 return l.subelement.path() 61 } 62 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) { 66 case ssa.Value: 67 return data.Pos() 68 case types.Type: 69 if nt, ok := deref(data).(*types.Named); ok { 70 return nt.Obj().Pos() 71 } 72 } 73 if cgn := l.obj.cgn; cgn != nil { 74 return cgn.fn.Pos() 75 } 76 return token.NoPos 77 } 78 79 // String returns the printed form of this label. 80 // 81 // Examples: Object type: 82 // x (a variable) 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) 91 // 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) 96 // 97 // TODO(adonovan): expose func LabelString(*types.Package, Label). 98 // 99 func (l Label) String() string { 100 var s string 101 switch v := l.obj.data.(type) { 102 case types.Type: 103 return v.String() 104 105 case string: 106 s = v // an intrinsic object (e.g. os.Args[*]) 107 108 case nil: 109 if l.obj.cgn != nil { 110 // allocation by intrinsic or reflective operation 111 s = fmt.Sprintf("<alloc in %s>", l.obj.cgn.fn) 112 } else { 113 s = "<unknown>" // should be unreachable 114 } 115 116 case *ssa.Function: 117 s = v.String() 118 119 case *ssa.Global: 120 s = v.String() 121 122 case *ssa.Const: 123 s = v.Name() 124 125 case *ssa.Alloc: 126 s = v.Comment 127 if s == "" { 128 s = "alloc" 129 } 130 131 case *ssa.Call: 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()) 135 } 136 s = "append" 137 138 case *ssa.MakeMap, *ssa.MakeChan, *ssa.MakeSlice, *ssa.Convert: 139 s = strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T", v), "*ssa.")) 140 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() 146 147 default: 148 panic(fmt.Sprintf("unhandled object data type: %T", v)) 149 } 150 151 return s + l.subelement.path() 152 }