+++ /dev/null
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package pointer
-
-import (
- "fmt"
- "go/token"
- "go/types"
- "strings"
-
- "golang.org/x/tools/go/ssa"
-)
-
-// A Label is an entity that may be pointed to by a pointer, map,
-// channel, 'func', slice or interface.
-//
-// Labels include:
-// - functions
-// - globals
-// - tagged objects, representing interfaces and reflect.Values
-// - arrays created by conversions (e.g. []byte("foo"), []byte(s))
-// - stack- and heap-allocated variables (including composite literals)
-// - channels, maps and arrays created by make()
-// - intrinsic or reflective operations that allocate (e.g. append, reflect.New)
-// - intrinsic objects, e.g. the initial array behind os.Args.
-// - and their subelements, e.g. "alloc.y[*].z"
-//
-// Labels are so varied that they defy good generalizations;
-// some have no value, no callgraph node, or no position.
-// Many objects have types that are inexpressible in Go:
-// maps, channels, functions, tagged objects.
-//
-// At most one of Value() or ReflectType() may return non-nil.
-//
-type Label struct {
- obj *object // the addressable memory location containing this label
- subelement *fieldInfo // subelement path within obj, e.g. ".a.b[*].c"
-}
-
-// Value returns the ssa.Value that allocated this label's object, if any.
-func (l Label) Value() ssa.Value {
- val, _ := l.obj.data.(ssa.Value)
- return val
-}
-
-// ReflectType returns the type represented by this label if it is an
-// reflect.rtype instance object or *reflect.rtype-tagged object.
-//
-func (l Label) ReflectType() types.Type {
- rtype, _ := l.obj.data.(types.Type)
- return rtype
-}
-
-// Path returns the path to the subelement of the object containing
-// this label. For example, ".x[*].y".
-//
-func (l Label) Path() string {
- return l.subelement.path()
-}
-
-// Pos returns the position of this label, if known, zero otherwise.
-func (l Label) Pos() token.Pos {
- switch data := l.obj.data.(type) {
- case ssa.Value:
- return data.Pos()
- case types.Type:
- if nt, ok := deref(data).(*types.Named); ok {
- return nt.Obj().Pos()
- }
- }
- if cgn := l.obj.cgn; cgn != nil {
- return cgn.fn.Pos()
- }
- return token.NoPos
-}
-
-// String returns the printed form of this label.
-//
-// Examples: Object type:
-// x (a variable)
-// (sync.Mutex).Lock (a function)
-// convert (array created by conversion)
-// makemap (map allocated via make)
-// makechan (channel allocated via make)
-// makeinterface (tagged object allocated by makeinterface)
-// <alloc in reflect.Zero> (allocation in instrinsic)
-// sync.Mutex (a reflect.rtype instance)
-// <command-line arguments> (an intrinsic object)
-//
-// Labels within compound objects have subelement paths:
-// x.y[*].z (a struct variable, x)
-// append.y[*].z (array allocated by append)
-// makeslice.y[*].z (array allocated via make)
-//
-// TODO(adonovan): expose func LabelString(*types.Package, Label).
-//
-func (l Label) String() string {
- var s string
- switch v := l.obj.data.(type) {
- case types.Type:
- return v.String()
-
- case string:
- s = v // an intrinsic object (e.g. os.Args[*])
-
- case nil:
- if l.obj.cgn != nil {
- // allocation by intrinsic or reflective operation
- s = fmt.Sprintf("<alloc in %s>", l.obj.cgn.fn)
- } else {
- s = "<unknown>" // should be unreachable
- }
-
- case *ssa.Function:
- s = v.String()
-
- case *ssa.Global:
- s = v.String()
-
- case *ssa.Const:
- s = v.Name()
-
- case *ssa.Alloc:
- s = v.Comment
- if s == "" {
- s = "alloc"
- }
-
- case *ssa.Call:
- // Currently only calls to append can allocate objects.
- if v.Call.Value.(*ssa.Builtin).Object().Name() != "append" {
- panic("unhandled *ssa.Call label: " + v.Name())
- }
- s = "append"
-
- case *ssa.MakeMap, *ssa.MakeChan, *ssa.MakeSlice, *ssa.Convert:
- s = strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T", v), "*ssa."))
-
- case *ssa.MakeInterface:
- // MakeInterface is usually implicit in Go source (so
- // Pos()==0), and tagged objects may be allocated
- // synthetically (so no *MakeInterface data).
- s = "makeinterface:" + v.X.Type().String()
-
- default:
- panic(fmt.Sprintf("unhandled object data type: %T", v))
- }
-
- return s + l.subelement.path()
-}