func (a *analysis) shouldTrack(T types.Type) bool {
	if a.track == trackAll {
		return true  
	}
	track, ok := a.trackTypes[T]
	if !ok {
		a.trackTypes[T] = true  
		for _, fi := range a.flatten(T) {
			switch ft := fi.typ.Underlying().(type) {
			case *types.Interface, *types.Signature:
				track = true  
			case *types.Basic:
			case *types.Chan:
				track = a.track&trackChan != 0 || a.shouldTrack(ft.Elem())
			case *types.Map:
				track = a.track&trackMap != 0 || a.shouldTrack(ft.Key()) || a.shouldTrack(ft.Elem())
			case *types.Slice:
				track = a.track&trackSlice != 0 || a.shouldTrack(ft.Elem())
			case *types.Pointer:
				track = a.track&trackPtr != 0 || a.shouldTrack(ft.Elem())
			case *types.Array, *types.Struct:
			default:
				panic(ft)
			}
			if track {
				break
			}
		}
		a.trackTypes[T] = track
		if !track && a.log != nil {
			fmt.Fprintf(a.log, "\ttype not tracked: %s\n", T)
		}
	}
	return track
}
shouldTrack reports whether object type T contains (recursively)
any fields whose addresses should be tracked.
package pointer
import (
	"bytes"
	"fmt"
	"go/types"
	"log"
	"os"
	"os/exec"
	"runtime"
	"time"
	"golang.org/x/tools/container/intsets"
)
func CanPoint(T types.Type) bool {
	switch T := T.(type) {
	case *types.Named:
		if obj := T.Obj(); obj.Name() == "Value" && obj.Pkg().Path() == "reflect" {
			return true  
		}
		return CanPoint(T.Underlying())
	case *types.Pointer, *types.Interface, *types.Map, *types.Chan, *types.Signature, *types.Slice:
		return true
	}
	return false  
}
func CanHaveDynamicTypes(T types.Type) bool {
	switch T := T.(type) {
	case *types.Named:
		if obj := T.Obj(); obj.Name() == "Value" && obj.Pkg().Path() == "reflect" {
			return true  
		}
		return CanHaveDynamicTypes(T.Underlying())
	case *types.Interface:
		return true
	}
	return false
}
func isInterface(T types.Type) bool { return types.IsInterface(T) }
func mustDeref(typ types.Type) types.Type {
	return typ.Underlying().(*types.Pointer).Elem()
}
func deref(typ types.Type) types.Type {
	if p, ok := typ.Underlying().(*types.Pointer); ok {
		return p.Elem()
	}
	return typ
}
type fieldInfo struct {
	typ types.Type
	op   interface{}  
	tail *fieldInfo
}
func (fi *fieldInfo) path() string {
	var buf bytes.Buffer
	for p := fi; p != nil; p = p.tail {
		switch op := p.op.(type) {
		case bool:
			fmt.Fprintf(&buf, "[*]")
		case int:
			fmt.Fprintf(&buf, "#%d", op)
		case *types.Var:
			fmt.Fprintf(&buf, ".%s", op.Name())
		}
	}
	return buf.String()
}
func (a *analysis) flatten(t types.Type) []*fieldInfo {
	fl, ok := a.flattenMemo[t]
	if !ok {
		switch t := t.(type) {
		case *types.Named:
			u := t.Underlying()
			if isInterface(u) {
				fl = append(fl, &fieldInfo{typ: t})
			} else {
				fl = a.flatten(u)
			}
		case *types.Basic,
			*types.Signature,
			*types.Chan,
			*types.Map,
			*types.Interface,
			*types.Slice,
			*types.Pointer:
			fl = append(fl, &fieldInfo{typ: t})
		case *types.Array:
			fl = append(fl, &fieldInfo{typ: t})  
			for _, fi := range a.flatten(t.Elem()) {
				fl = append(fl, &fieldInfo{typ: fi.typ, op: true, tail: fi})
			}
		case *types.Struct:
			fl = append(fl, &fieldInfo{typ: t})  
			for i, n := 0, t.NumFields(); i < n; i++ {
				f := t.Field(i)
				for _, fi := range a.flatten(f.Type()) {
					fl = append(fl, &fieldInfo{typ: fi.typ, op: f, tail: fi})
				}
			}
		case *types.Tuple:
			n := t.Len()
			if n == 1 {
				fl = append(fl, a.flatten(t.At(0).Type())...)
			} else {
				for i := 0; i < n; i++ {
					f := t.At(i)
					for _, fi := range a.flatten(f.Type()) {
						fl = append(fl, &fieldInfo{typ: fi.typ, op: i, tail: fi})
					}
				}
			}
		default:
			panic(fmt.Sprintf("cannot flatten unsupported type %T", t))
		}
		a.flattenMemo[t] = fl
	}
	return fl
}
func (a *analysis) sizeof(t types.Type) uint32 {
	return uint32(len(a.flatten(t)))
}