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  }