...

Source file src/golang.org/x/tools/go/pointer/labels.go

Documentation: golang.org/x/tools/go/pointer

     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  }
   151  

View as plain text