You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
4.6 KiB

  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. package pointer
  5. import (
  6. "fmt"
  7. "go/token"
  8. "go/types"
  9. "strings"
  10. "golang.org/x/tools/go/ssa"
  11. )
  12. // A Label is an entity that may be pointed to by a pointer, map,
  13. // channel, 'func', slice or interface.
  14. //
  15. // Labels include:
  16. // - functions
  17. // - globals
  18. // - tagged objects, representing interfaces and reflect.Values
  19. // - arrays created by conversions (e.g. []byte("foo"), []byte(s))
  20. // - stack- and heap-allocated variables (including composite literals)
  21. // - channels, maps and arrays created by make()
  22. // - intrinsic or reflective operations that allocate (e.g. append, reflect.New)
  23. // - intrinsic objects, e.g. the initial array behind os.Args.
  24. // - and their subelements, e.g. "alloc.y[*].z"
  25. //
  26. // Labels are so varied that they defy good generalizations;
  27. // some have no value, no callgraph node, or no position.
  28. // Many objects have types that are inexpressible in Go:
  29. // maps, channels, functions, tagged objects.
  30. //
  31. // At most one of Value() or ReflectType() may return non-nil.
  32. //
  33. type Label struct {
  34. obj *object // the addressable memory location containing this label
  35. subelement *fieldInfo // subelement path within obj, e.g. ".a.b[*].c"
  36. }
  37. // Value returns the ssa.Value that allocated this label's object, if any.
  38. func (l Label) Value() ssa.Value {
  39. val, _ := l.obj.data.(ssa.Value)
  40. return val
  41. }
  42. // ReflectType returns the type represented by this label if it is an
  43. // reflect.rtype instance object or *reflect.rtype-tagged object.
  44. //
  45. func (l Label) ReflectType() types.Type {
  46. rtype, _ := l.obj.data.(types.Type)
  47. return rtype
  48. }
  49. // Path returns the path to the subelement of the object containing
  50. // this label. For example, ".x[*].y".
  51. //
  52. func (l Label) Path() string {
  53. return l.subelement.path()
  54. }
  55. // Pos returns the position of this label, if known, zero otherwise.
  56. func (l Label) Pos() token.Pos {
  57. switch data := l.obj.data.(type) {
  58. case ssa.Value:
  59. return data.Pos()
  60. case types.Type:
  61. if nt, ok := deref(data).(*types.Named); ok {
  62. return nt.Obj().Pos()
  63. }
  64. }
  65. if cgn := l.obj.cgn; cgn != nil {
  66. return cgn.fn.Pos()
  67. }
  68. return token.NoPos
  69. }
  70. // String returns the printed form of this label.
  71. //
  72. // Examples: Object type:
  73. // x (a variable)
  74. // (sync.Mutex).Lock (a function)
  75. // convert (array created by conversion)
  76. // makemap (map allocated via make)
  77. // makechan (channel allocated via make)
  78. // makeinterface (tagged object allocated by makeinterface)
  79. // <alloc in reflect.Zero> (allocation in instrinsic)
  80. // sync.Mutex (a reflect.rtype instance)
  81. // <command-line arguments> (an intrinsic object)
  82. //
  83. // Labels within compound objects have subelement paths:
  84. // x.y[*].z (a struct variable, x)
  85. // append.y[*].z (array allocated by append)
  86. // makeslice.y[*].z (array allocated via make)
  87. //
  88. // TODO(adonovan): expose func LabelString(*types.Package, Label).
  89. //
  90. func (l Label) String() string {
  91. var s string
  92. switch v := l.obj.data.(type) {
  93. case types.Type:
  94. return v.String()
  95. case string:
  96. s = v // an intrinsic object (e.g. os.Args[*])
  97. case nil:
  98. if l.obj.cgn != nil {
  99. // allocation by intrinsic or reflective operation
  100. s = fmt.Sprintf("<alloc in %s>", l.obj.cgn.fn)
  101. } else {
  102. s = "<unknown>" // should be unreachable
  103. }
  104. case *ssa.Function:
  105. s = v.String()
  106. case *ssa.Global:
  107. s = v.String()
  108. case *ssa.Const:
  109. s = v.Name()
  110. case *ssa.Alloc:
  111. s = v.Comment
  112. if s == "" {
  113. s = "alloc"
  114. }
  115. case *ssa.Call:
  116. // Currently only calls to append can allocate objects.
  117. if v.Call.Value.(*ssa.Builtin).Object().Name() != "append" {
  118. panic("unhandled *ssa.Call label: " + v.Name())
  119. }
  120. s = "append"
  121. case *ssa.MakeMap, *ssa.MakeChan, *ssa.MakeSlice, *ssa.Convert:
  122. s = strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T", v), "*ssa."))
  123. case *ssa.MakeInterface:
  124. // MakeInterface is usually implicit in Go source (so
  125. // Pos()==0), and tagged objects may be allocated
  126. // synthetically (so no *MakeInterface data).
  127. s = "makeinterface:" + v.X.Type().String()
  128. default:
  129. panic(fmt.Sprintf("unhandled object data type: %T", v))
  130. }
  131. return s + l.subelement.path()
  132. }