// 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()
}
