github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/callgraph/vta/graph.go (about)

     1  // Copyright 2021 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 vta
     6  
     7  import (
     8  	"fmt"
     9  	"go/token"
    10  	"go/types"
    11  
    12  	"golang.org/x/tools/go/callgraph"
    13  	"golang.org/x/tools/go/ssa"
    14  	"golang.org/x/tools/go/types/typeutil"
    15  	"golang.org/x/tools/internal/typeparams"
    16  )
    17  
    18  // node interface for VTA nodes.
    19  type node interface {
    20  	Type() types.Type
    21  	String() string
    22  }
    23  
    24  // constant node for VTA.
    25  type constant struct {
    26  	typ types.Type
    27  }
    28  
    29  func (c constant) Type() types.Type {
    30  	return c.typ
    31  }
    32  
    33  func (c constant) String() string {
    34  	return fmt.Sprintf("Constant(%v)", c.Type())
    35  }
    36  
    37  // pointer node for VTA.
    38  type pointer struct {
    39  	typ *types.Pointer
    40  }
    41  
    42  func (p pointer) Type() types.Type {
    43  	return p.typ
    44  }
    45  
    46  func (p pointer) String() string {
    47  	return fmt.Sprintf("Pointer(%v)", p.Type())
    48  }
    49  
    50  // mapKey node for VTA, modeling reachable map key types.
    51  type mapKey struct {
    52  	typ types.Type
    53  }
    54  
    55  func (mk mapKey) Type() types.Type {
    56  	return mk.typ
    57  }
    58  
    59  func (mk mapKey) String() string {
    60  	return fmt.Sprintf("MapKey(%v)", mk.Type())
    61  }
    62  
    63  // mapValue node for VTA, modeling reachable map value types.
    64  type mapValue struct {
    65  	typ types.Type
    66  }
    67  
    68  func (mv mapValue) Type() types.Type {
    69  	return mv.typ
    70  }
    71  
    72  func (mv mapValue) String() string {
    73  	return fmt.Sprintf("MapValue(%v)", mv.Type())
    74  }
    75  
    76  // sliceElem node for VTA, modeling reachable slice and array element types.
    77  type sliceElem struct {
    78  	typ types.Type
    79  }
    80  
    81  func (s sliceElem) Type() types.Type {
    82  	return s.typ
    83  }
    84  
    85  func (s sliceElem) String() string {
    86  	return fmt.Sprintf("Slice([]%v)", s.Type())
    87  }
    88  
    89  // channelElem node for VTA, modeling reachable channel element types.
    90  type channelElem struct {
    91  	typ types.Type
    92  }
    93  
    94  func (c channelElem) Type() types.Type {
    95  	return c.typ
    96  }
    97  
    98  func (c channelElem) String() string {
    99  	return fmt.Sprintf("Channel(chan %v)", c.Type())
   100  }
   101  
   102  // field node for VTA.
   103  type field struct {
   104  	StructType types.Type
   105  	index      int // index of the field in the struct
   106  }
   107  
   108  func (f field) Type() types.Type {
   109  	s := f.StructType.Underlying().(*types.Struct)
   110  	return s.Field(f.index).Type()
   111  }
   112  
   113  func (f field) String() string {
   114  	s := f.StructType.Underlying().(*types.Struct)
   115  	return fmt.Sprintf("Field(%v:%s)", f.StructType, s.Field(f.index).Name())
   116  }
   117  
   118  // global node for VTA.
   119  type global struct {
   120  	val *ssa.Global
   121  }
   122  
   123  func (g global) Type() types.Type {
   124  	return g.val.Type()
   125  }
   126  
   127  func (g global) String() string {
   128  	return fmt.Sprintf("Global(%s)", g.val.Name())
   129  }
   130  
   131  // local node for VTA modeling local variables
   132  // and function/method parameters.
   133  type local struct {
   134  	val ssa.Value
   135  }
   136  
   137  func (l local) Type() types.Type {
   138  	return l.val.Type()
   139  }
   140  
   141  func (l local) String() string {
   142  	return fmt.Sprintf("Local(%s)", l.val.Name())
   143  }
   144  
   145  // indexedLocal node for VTA node. Models indexed locals
   146  // related to the ssa extract instructions.
   147  type indexedLocal struct {
   148  	val   ssa.Value
   149  	index int
   150  	typ   types.Type
   151  }
   152  
   153  func (i indexedLocal) Type() types.Type {
   154  	return i.typ
   155  }
   156  
   157  func (i indexedLocal) String() string {
   158  	return fmt.Sprintf("Local(%s[%d])", i.val.Name(), i.index)
   159  }
   160  
   161  // function node for VTA.
   162  type function struct {
   163  	f *ssa.Function
   164  }
   165  
   166  func (f function) Type() types.Type {
   167  	return f.f.Type()
   168  }
   169  
   170  func (f function) String() string {
   171  	return fmt.Sprintf("Function(%s)", f.f.Name())
   172  }
   173  
   174  // nestedPtrInterface node represents all references and dereferences
   175  // of locals and globals that have a nested pointer to interface type.
   176  // We merge such constructs into a single node for simplicity and without
   177  // much precision sacrifice as such variables are rare in practice. Both
   178  // a and b would be represented as the same PtrInterface(I) node in:
   179  //
   180  //	type I interface
   181  //	var a ***I
   182  //	var b **I
   183  type nestedPtrInterface struct {
   184  	typ types.Type
   185  }
   186  
   187  func (l nestedPtrInterface) Type() types.Type {
   188  	return l.typ
   189  }
   190  
   191  func (l nestedPtrInterface) String() string {
   192  	return fmt.Sprintf("PtrInterface(%v)", l.typ)
   193  }
   194  
   195  // nestedPtrFunction node represents all references and dereferences of locals
   196  // and globals that have a nested pointer to function type. We merge such
   197  // constructs into a single node for simplicity and without much precision
   198  // sacrifice as such variables are rare in practice. Both a and b would be
   199  // represented as the same PtrFunction(func()) node in:
   200  //
   201  //	var a *func()
   202  //	var b **func()
   203  type nestedPtrFunction struct {
   204  	typ types.Type
   205  }
   206  
   207  func (p nestedPtrFunction) Type() types.Type {
   208  	return p.typ
   209  }
   210  
   211  func (p nestedPtrFunction) String() string {
   212  	return fmt.Sprintf("PtrFunction(%v)", p.typ)
   213  }
   214  
   215  // panicArg models types of all arguments passed to panic.
   216  type panicArg struct{}
   217  
   218  func (p panicArg) Type() types.Type {
   219  	return nil
   220  }
   221  
   222  func (p panicArg) String() string {
   223  	return "Panic"
   224  }
   225  
   226  // recoverReturn models types of all return values of recover().
   227  type recoverReturn struct{}
   228  
   229  func (r recoverReturn) Type() types.Type {
   230  	return nil
   231  }
   232  
   233  func (r recoverReturn) String() string {
   234  	return "Recover"
   235  }
   236  
   237  // vtaGraph remembers for each VTA node the set of its successors.
   238  // Tailored for VTA, hence does not support singleton (sub)graphs.
   239  type vtaGraph map[node]map[node]bool
   240  
   241  // addEdge adds an edge x->y to the graph.
   242  func (g vtaGraph) addEdge(x, y node) {
   243  	succs, ok := g[x]
   244  	if !ok {
   245  		succs = make(map[node]bool)
   246  		g[x] = succs
   247  	}
   248  	succs[y] = true
   249  }
   250  
   251  // successors returns all of n's immediate successors in the graph.
   252  // The order of successor nodes is arbitrary.
   253  func (g vtaGraph) successors(n node) []node {
   254  	var succs []node
   255  	for succ := range g[n] {
   256  		succs = append(succs, succ)
   257  	}
   258  	return succs
   259  }
   260  
   261  // typePropGraph builds a VTA graph for a set of `funcs` and initial
   262  // `callgraph` needed to establish interprocedural edges. Returns the
   263  // graph and a map for unique type representatives.
   264  func typePropGraph(funcs map[*ssa.Function]bool, callgraph *callgraph.Graph) (vtaGraph, *typeutil.Map) {
   265  	b := builder{graph: make(vtaGraph), callGraph: callgraph}
   266  	b.visit(funcs)
   267  	return b.graph, &b.canon
   268  }
   269  
   270  // Data structure responsible for linearly traversing the
   271  // code and building a VTA graph.
   272  type builder struct {
   273  	graph     vtaGraph
   274  	callGraph *callgraph.Graph // initial call graph for creating flows at unresolved call sites.
   275  
   276  	// Specialized type map for canonicalization of types.Type.
   277  	// Semantically equivalent types can have different implementations,
   278  	// i.e., they are different pointer values. The map allows us to
   279  	// have one unique representative. The keys are fixed and from the
   280  	// client perspective they are types. The values in our case are
   281  	// types too, in particular type representatives. Each value is a
   282  	// pointer so this map is not expected to take much memory.
   283  	canon typeutil.Map
   284  }
   285  
   286  func (b *builder) visit(funcs map[*ssa.Function]bool) {
   287  	// Add the fixed edge Panic -> Recover
   288  	b.graph.addEdge(panicArg{}, recoverReturn{})
   289  
   290  	for f, in := range funcs {
   291  		if in {
   292  			b.fun(f)
   293  		}
   294  	}
   295  }
   296  
   297  func (b *builder) fun(f *ssa.Function) {
   298  	for _, bl := range f.Blocks {
   299  		for _, instr := range bl.Instrs {
   300  			b.instr(instr)
   301  		}
   302  	}
   303  }
   304  
   305  func (b *builder) instr(instr ssa.Instruction) {
   306  	switch i := instr.(type) {
   307  	case *ssa.Store:
   308  		b.addInFlowAliasEdges(b.nodeFromVal(i.Addr), b.nodeFromVal(i.Val))
   309  	case *ssa.MakeInterface:
   310  		b.addInFlowEdge(b.nodeFromVal(i.X), b.nodeFromVal(i))
   311  	case *ssa.MakeClosure:
   312  		b.closure(i)
   313  	case *ssa.UnOp:
   314  		b.unop(i)
   315  	case *ssa.Phi:
   316  		b.phi(i)
   317  	case *ssa.ChangeInterface:
   318  		// Although in change interface a := A(b) command a and b are
   319  		// the same object, the only interesting flow happens when A
   320  		// is an interface. We create flow b -> a, but omit a -> b.
   321  		// The latter flow is not needed: if a gets assigned concrete
   322  		// type later on, that cannot be propagated back to b as b
   323  		// is a separate variable. The a -> b flow can happen when
   324  		// A is a pointer to interface, but then the command is of
   325  		// type ChangeType, handled below.
   326  		b.addInFlowEdge(b.nodeFromVal(i.X), b.nodeFromVal(i))
   327  	case *ssa.ChangeType:
   328  		// change type command a := A(b) results in a and b being the
   329  		// same value. For concrete type A, there is no interesting flow.
   330  		//
   331  		// When A is an interface, most interface casts are handled
   332  		// by the ChangeInterface instruction. The relevant case here is
   333  		// when converting a pointer to an interface type. This can happen
   334  		// when the underlying interfaces have the same method set.
   335  		//
   336  		//	type I interface{ foo() }
   337  		//	type J interface{ foo() }
   338  		//	var b *I
   339  		//	a := (*J)(b)
   340  		//
   341  		// When this happens we add flows between a <--> b.
   342  		b.addInFlowAliasEdges(b.nodeFromVal(i), b.nodeFromVal(i.X))
   343  	case *ssa.TypeAssert:
   344  		b.tassert(i)
   345  	case *ssa.Extract:
   346  		b.extract(i)
   347  	case *ssa.Field:
   348  		b.field(i)
   349  	case *ssa.FieldAddr:
   350  		b.fieldAddr(i)
   351  	case *ssa.Send:
   352  		b.send(i)
   353  	case *ssa.Select:
   354  		b.selekt(i)
   355  	case *ssa.Index:
   356  		b.index(i)
   357  	case *ssa.IndexAddr:
   358  		b.indexAddr(i)
   359  	case *ssa.Lookup:
   360  		b.lookup(i)
   361  	case *ssa.MapUpdate:
   362  		b.mapUpdate(i)
   363  	case *ssa.Next:
   364  		b.next(i)
   365  	case ssa.CallInstruction:
   366  		b.call(i)
   367  	case *ssa.Panic:
   368  		b.panic(i)
   369  	case *ssa.Return:
   370  		b.rtrn(i)
   371  	case *ssa.MakeChan, *ssa.MakeMap, *ssa.MakeSlice, *ssa.BinOp,
   372  		*ssa.Alloc, *ssa.DebugRef, *ssa.Convert, *ssa.Jump, *ssa.If,
   373  		*ssa.Slice, *ssa.SliceToArrayPointer, *ssa.Range, *ssa.RunDefers:
   374  		// No interesting flow here.
   375  		// Notes on individual instructions:
   376  		// SliceToArrayPointer: t1 = slice to array pointer *[4]T <- []T (t0)
   377  		// No interesting flow as sliceArrayElem(t1) == sliceArrayElem(t0).
   378  		return
   379  	case *ssa.MultiConvert:
   380  		b.multiconvert(i)
   381  	default:
   382  		panic(fmt.Sprintf("unsupported instruction %v\n", instr))
   383  	}
   384  }
   385  
   386  func (b *builder) unop(u *ssa.UnOp) {
   387  	switch u.Op {
   388  	case token.MUL:
   389  		// Multiplication operator * is used here as a dereference operator.
   390  		b.addInFlowAliasEdges(b.nodeFromVal(u), b.nodeFromVal(u.X))
   391  	case token.ARROW:
   392  		t := u.X.Type().Underlying().(*types.Chan).Elem()
   393  		b.addInFlowAliasEdges(b.nodeFromVal(u), channelElem{typ: t})
   394  	default:
   395  		// There is no interesting type flow otherwise.
   396  	}
   397  }
   398  
   399  func (b *builder) phi(p *ssa.Phi) {
   400  	for _, edge := range p.Edges {
   401  		b.addInFlowAliasEdges(b.nodeFromVal(p), b.nodeFromVal(edge))
   402  	}
   403  }
   404  
   405  func (b *builder) tassert(a *ssa.TypeAssert) {
   406  	if !a.CommaOk {
   407  		b.addInFlowEdge(b.nodeFromVal(a.X), b.nodeFromVal(a))
   408  		return
   409  	}
   410  	// The case where a is <a.AssertedType, bool> register so there
   411  	// is a flow from a.X to a[0]. Here, a[0] is represented as an
   412  	// indexedLocal: an entry into local tuple register a at index 0.
   413  	tup := a.Type().Underlying().(*types.Tuple)
   414  	t := tup.At(0).Type()
   415  
   416  	local := indexedLocal{val: a, typ: t, index: 0}
   417  	b.addInFlowEdge(b.nodeFromVal(a.X), local)
   418  }
   419  
   420  // extract instruction t1 := t2[i] generates flows between t2[i]
   421  // and t1 where the source is indexed local representing a value
   422  // from tuple register t2 at index i and the target is t1.
   423  func (b *builder) extract(e *ssa.Extract) {
   424  	tup := e.Tuple.Type().Underlying().(*types.Tuple)
   425  	t := tup.At(e.Index).Type()
   426  
   427  	local := indexedLocal{val: e.Tuple, typ: t, index: e.Index}
   428  	b.addInFlowAliasEdges(b.nodeFromVal(e), local)
   429  }
   430  
   431  func (b *builder) field(f *ssa.Field) {
   432  	fnode := field{StructType: f.X.Type(), index: f.Field}
   433  	b.addInFlowEdge(fnode, b.nodeFromVal(f))
   434  }
   435  
   436  func (b *builder) fieldAddr(f *ssa.FieldAddr) {
   437  	t := f.X.Type().Underlying().(*types.Pointer).Elem()
   438  
   439  	// Since we are getting pointer to a field, make a bidirectional edge.
   440  	fnode := field{StructType: t, index: f.Field}
   441  	b.addInFlowEdge(fnode, b.nodeFromVal(f))
   442  	b.addInFlowEdge(b.nodeFromVal(f), fnode)
   443  }
   444  
   445  func (b *builder) send(s *ssa.Send) {
   446  	t := s.Chan.Type().Underlying().(*types.Chan).Elem()
   447  	b.addInFlowAliasEdges(channelElem{typ: t}, b.nodeFromVal(s.X))
   448  }
   449  
   450  // selekt generates flows for select statement
   451  //
   452  //	a = select blocking/nonblocking [c_1 <- t_1, c_2 <- t_2, ..., <- o_1, <- o_2, ...]
   453  //
   454  // between receiving channel registers c_i and corresponding input register t_i. Further,
   455  // flows are generated between o_i and a[2 + i]. Note that a is a tuple register of type
   456  // <int, bool, r_1, r_2, ...> where the type of r_i is the element type of channel o_i.
   457  func (b *builder) selekt(s *ssa.Select) {
   458  	recvIndex := 0
   459  	for _, state := range s.States {
   460  		t := state.Chan.Type().Underlying().(*types.Chan).Elem()
   461  
   462  		if state.Dir == types.SendOnly {
   463  			b.addInFlowAliasEdges(channelElem{typ: t}, b.nodeFromVal(state.Send))
   464  		} else {
   465  			// state.Dir == RecvOnly by definition of select instructions.
   466  			tupEntry := indexedLocal{val: s, typ: t, index: 2 + recvIndex}
   467  			b.addInFlowAliasEdges(tupEntry, channelElem{typ: t})
   468  			recvIndex++
   469  		}
   470  	}
   471  }
   472  
   473  // index instruction a := b[c] on slices creates flows between a and
   474  // SliceElem(t) flow where t is an interface type of c. Arrays and
   475  // slice elements are both modeled as SliceElem.
   476  func (b *builder) index(i *ssa.Index) {
   477  	et := sliceArrayElem(i.X.Type())
   478  	b.addInFlowAliasEdges(b.nodeFromVal(i), sliceElem{typ: et})
   479  }
   480  
   481  // indexAddr instruction a := &b[c] fetches address of a index
   482  // into the field so we create bidirectional flow a <-> SliceElem(t)
   483  // where t is an interface type of c. Arrays and slice elements are
   484  // both modeled as SliceElem.
   485  func (b *builder) indexAddr(i *ssa.IndexAddr) {
   486  	et := sliceArrayElem(i.X.Type())
   487  	b.addInFlowEdge(sliceElem{typ: et}, b.nodeFromVal(i))
   488  	b.addInFlowEdge(b.nodeFromVal(i), sliceElem{typ: et})
   489  }
   490  
   491  // lookup handles map query commands a := m[b] where m is of type
   492  // map[...]V and V is an interface. It creates flows between `a`
   493  // and MapValue(V).
   494  func (b *builder) lookup(l *ssa.Lookup) {
   495  	t, ok := l.X.Type().Underlying().(*types.Map)
   496  	if !ok {
   497  		// No interesting flows for string lookups.
   498  		return
   499  	}
   500  	b.addInFlowAliasEdges(b.nodeFromVal(l), mapValue{typ: t.Elem()})
   501  }
   502  
   503  // mapUpdate handles map update commands m[b] = a where m is of type
   504  // map[K]V and K and V are interfaces. It creates flows between `a`
   505  // and MapValue(V) as well as between MapKey(K) and `b`.
   506  func (b *builder) mapUpdate(u *ssa.MapUpdate) {
   507  	t, ok := u.Map.Type().Underlying().(*types.Map)
   508  	if !ok {
   509  		// No interesting flows for string updates.
   510  		return
   511  	}
   512  
   513  	b.addInFlowAliasEdges(mapKey{typ: t.Key()}, b.nodeFromVal(u.Key))
   514  	b.addInFlowAliasEdges(mapValue{typ: t.Elem()}, b.nodeFromVal(u.Value))
   515  }
   516  
   517  // next instruction <ok, key, value> := next r, where r
   518  // is a range over map or string generates flow between
   519  // key and MapKey as well value and MapValue nodes.
   520  func (b *builder) next(n *ssa.Next) {
   521  	if n.IsString {
   522  		return
   523  	}
   524  	tup := n.Type().Underlying().(*types.Tuple)
   525  	kt := tup.At(1).Type()
   526  	vt := tup.At(2).Type()
   527  
   528  	b.addInFlowAliasEdges(indexedLocal{val: n, typ: kt, index: 1}, mapKey{typ: kt})
   529  	b.addInFlowAliasEdges(indexedLocal{val: n, typ: vt, index: 2}, mapValue{typ: vt})
   530  }
   531  
   532  // addInFlowAliasEdges adds an edge r -> l to b.graph if l is a node that can
   533  // have an inflow, i.e., a node that represents an interface or an unresolved
   534  // function value. Similarly for the edge l -> r with an additional condition
   535  // of that l and r can potentially alias.
   536  func (b *builder) addInFlowAliasEdges(l, r node) {
   537  	b.addInFlowEdge(r, l)
   538  
   539  	if canAlias(l, r) {
   540  		b.addInFlowEdge(l, r)
   541  	}
   542  }
   543  
   544  func (b *builder) closure(c *ssa.MakeClosure) {
   545  	f := c.Fn.(*ssa.Function)
   546  	b.addInFlowEdge(function{f: f}, b.nodeFromVal(c))
   547  
   548  	for i, fv := range f.FreeVars {
   549  		b.addInFlowAliasEdges(b.nodeFromVal(fv), b.nodeFromVal(c.Bindings[i]))
   550  	}
   551  }
   552  
   553  // panic creates a flow from arguments to panic instructions to return
   554  // registers of all recover statements in the program. Introduces a
   555  // global panic node Panic and
   556  //  1. for every panic statement p: add p -> Panic
   557  //  2. for every recover statement r: add Panic -> r (handled in call)
   558  //
   559  // TODO(zpavlinovic): improve precision by explicitly modeling how panic
   560  // values flow from callees to callers and into deferred recover instructions.
   561  func (b *builder) panic(p *ssa.Panic) {
   562  	// Panics often have, for instance, strings as arguments which do
   563  	// not create interesting flows.
   564  	if !canHaveMethods(p.X.Type()) {
   565  		return
   566  	}
   567  
   568  	b.addInFlowEdge(b.nodeFromVal(p.X), panicArg{})
   569  }
   570  
   571  // call adds flows between arguments/parameters and return values/registers
   572  // for both static and dynamic calls, as well as go and defer calls.
   573  func (b *builder) call(c ssa.CallInstruction) {
   574  	// When c is r := recover() call register instruction, we add Recover -> r.
   575  	if bf, ok := c.Common().Value.(*ssa.Builtin); ok && bf.Name() == "recover" {
   576  		if v, ok := c.(ssa.Value); ok {
   577  			b.addInFlowEdge(recoverReturn{}, b.nodeFromVal(v))
   578  		}
   579  		return
   580  	}
   581  
   582  	for _, f := range siteCallees(c, b.callGraph) {
   583  		addArgumentFlows(b, c, f)
   584  	}
   585  }
   586  
   587  func addArgumentFlows(b *builder, c ssa.CallInstruction, f *ssa.Function) {
   588  	// When f has no paremeters (including receiver), there is no type
   589  	// flow here. Also, f's body and parameters might be missing, such
   590  	// as when vta is used within the golang.org/x/tools/go/analysis
   591  	// framework (see github.com/golang/go/issues/50670).
   592  	if len(f.Params) == 0 {
   593  		return
   594  	}
   595  	cc := c.Common()
   596  	if cc.Method != nil {
   597  		// In principle we don't add interprocedural flows for receiver
   598  		// objects. At a call site, the receiver object is interface
   599  		// while the callee object is concrete. The flow from interface
   600  		// to concrete type in general does not make sense. The exception
   601  		// is when the concrete type is a named function type (see #57756).
   602  		//
   603  		// The flow other way around would bake in information from the
   604  		// initial call graph.
   605  		if isFunction(f.Params[0].Type()) {
   606  			b.addInFlowEdge(b.nodeFromVal(cc.Value), b.nodeFromVal(f.Params[0]))
   607  		}
   608  	}
   609  
   610  	offset := 0
   611  	if cc.Method != nil {
   612  		offset = 1
   613  	}
   614  	for i, v := range cc.Args {
   615  		// Parameters of f might not be available, as in the case
   616  		// when vta is used within the golang.org/x/tools/go/analysis
   617  		// framework (see github.com/golang/go/issues/50670).
   618  		//
   619  		// TODO: investigate other cases of missing body and parameters
   620  		if len(f.Params) <= i+offset {
   621  			return
   622  		}
   623  		b.addInFlowAliasEdges(b.nodeFromVal(f.Params[i+offset]), b.nodeFromVal(v))
   624  	}
   625  }
   626  
   627  // rtrn produces flows between values of r and c where
   628  // c is a call instruction that resolves to the enclosing
   629  // function of r based on b.callGraph.
   630  func (b *builder) rtrn(r *ssa.Return) {
   631  	n := b.callGraph.Nodes[r.Parent()]
   632  	// n != nil when b.callgraph is sound, but the client can
   633  	// pass any callgraph, including an underapproximate one.
   634  	if n == nil {
   635  		return
   636  	}
   637  
   638  	for _, e := range n.In {
   639  		if cv, ok := e.Site.(ssa.Value); ok {
   640  			addReturnFlows(b, r, cv)
   641  		}
   642  	}
   643  }
   644  
   645  func addReturnFlows(b *builder, r *ssa.Return, site ssa.Value) {
   646  	results := r.Results
   647  	if len(results) == 1 {
   648  		// When there is only one return value, the destination register does not
   649  		// have a tuple type.
   650  		b.addInFlowEdge(b.nodeFromVal(results[0]), b.nodeFromVal(site))
   651  		return
   652  	}
   653  
   654  	tup := site.Type().Underlying().(*types.Tuple)
   655  	for i, r := range results {
   656  		local := indexedLocal{val: site, typ: tup.At(i).Type(), index: i}
   657  		b.addInFlowEdge(b.nodeFromVal(r), local)
   658  	}
   659  }
   660  
   661  func (b *builder) multiconvert(c *ssa.MultiConvert) {
   662  	// TODO(zpavlinovic): decide what to do on MultiConvert long term.
   663  	// TODO(zpavlinovic): add unit tests.
   664  	typeSetOf := func(typ types.Type) []*typeparams.Term {
   665  		// This is a adaptation of x/exp/typeparams.NormalTerms which x/tools cannot depend on.
   666  		var terms []*typeparams.Term
   667  		var err error
   668  		switch typ := typ.(type) {
   669  		case *typeparams.TypeParam:
   670  			terms, err = typeparams.StructuralTerms(typ)
   671  		case *typeparams.Union:
   672  			terms, err = typeparams.UnionTermSet(typ)
   673  		case *types.Interface:
   674  			terms, err = typeparams.InterfaceTermSet(typ)
   675  		default:
   676  			// Common case.
   677  			// Specializing the len=1 case to avoid a slice
   678  			// had no measurable space/time benefit.
   679  			terms = []*typeparams.Term{typeparams.NewTerm(false, typ)}
   680  		}
   681  
   682  		if err != nil {
   683  			return nil
   684  		}
   685  		return terms
   686  	}
   687  	// isValuePreserving returns true if a conversion from ut_src to
   688  	// ut_dst is value-preserving, i.e. just a change of type.
   689  	// Precondition: neither argument is a named type.
   690  	isValuePreserving := func(ut_src, ut_dst types.Type) bool {
   691  		// Identical underlying types?
   692  		if types.IdenticalIgnoreTags(ut_dst, ut_src) {
   693  			return true
   694  		}
   695  
   696  		switch ut_dst.(type) {
   697  		case *types.Chan:
   698  			// Conversion between channel types?
   699  			_, ok := ut_src.(*types.Chan)
   700  			return ok
   701  
   702  		case *types.Pointer:
   703  			// Conversion between pointers with identical base types?
   704  			_, ok := ut_src.(*types.Pointer)
   705  			return ok
   706  		}
   707  		return false
   708  	}
   709  	dst_terms := typeSetOf(c.Type())
   710  	src_terms := typeSetOf(c.X.Type())
   711  	for _, s := range src_terms {
   712  		us := s.Type().Underlying()
   713  		for _, d := range dst_terms {
   714  			ud := d.Type().Underlying()
   715  			if isValuePreserving(us, ud) {
   716  				// This is equivalent to a ChangeType.
   717  				b.addInFlowAliasEdges(b.nodeFromVal(c), b.nodeFromVal(c.X))
   718  				return
   719  			}
   720  			// This is equivalent to either: SliceToArrayPointer,,
   721  			// SliceToArrayPointer+Deref, Size 0 Array constant, or a Convert.
   722  		}
   723  	}
   724  }
   725  
   726  // addInFlowEdge adds s -> d to g if d is node that can have an inflow, i.e., a node
   727  // that represents an interface or an unresolved function value. Otherwise, there
   728  // is no interesting type flow so the edge is omitted.
   729  func (b *builder) addInFlowEdge(s, d node) {
   730  	if hasInFlow(d) {
   731  		b.graph.addEdge(b.representative(s), b.representative(d))
   732  	}
   733  }
   734  
   735  // Creates const, pointer, global, func, and local nodes based on register instructions.
   736  func (b *builder) nodeFromVal(val ssa.Value) node {
   737  	if p, ok := val.Type().(*types.Pointer); ok && !types.IsInterface(p.Elem()) && !isFunction(p.Elem()) {
   738  		// Nested pointer to interfaces are modeled as a special
   739  		// nestedPtrInterface node.
   740  		if i := interfaceUnderPtr(p.Elem()); i != nil {
   741  			return nestedPtrInterface{typ: i}
   742  		}
   743  		// The same goes for nested function types.
   744  		if f := functionUnderPtr(p.Elem()); f != nil {
   745  			return nestedPtrFunction{typ: f}
   746  		}
   747  		return pointer{typ: p}
   748  	}
   749  
   750  	switch v := val.(type) {
   751  	case *ssa.Const:
   752  		return constant{typ: val.Type()}
   753  	case *ssa.Global:
   754  		return global{val: v}
   755  	case *ssa.Function:
   756  		return function{f: v}
   757  	case *ssa.Parameter, *ssa.FreeVar, ssa.Instruction:
   758  		// ssa.Param, ssa.FreeVar, and a specific set of "register" instructions,
   759  		// satisifying the ssa.Value interface, can serve as local variables.
   760  		return local{val: v}
   761  	default:
   762  		panic(fmt.Errorf("unsupported value %v in node creation", val))
   763  	}
   764  }
   765  
   766  // representative returns a unique representative for node `n`. Since
   767  // semantically equivalent types can have different implementations,
   768  // this method guarantees the same implementation is always used.
   769  func (b *builder) representative(n node) node {
   770  	if n.Type() == nil {
   771  		// panicArg and recoverReturn do not have
   772  		// types and are unique by definition.
   773  		return n
   774  	}
   775  	t := canonicalize(n.Type(), &b.canon)
   776  
   777  	switch i := n.(type) {
   778  	case constant:
   779  		return constant{typ: t}
   780  	case pointer:
   781  		return pointer{typ: t.(*types.Pointer)}
   782  	case sliceElem:
   783  		return sliceElem{typ: t}
   784  	case mapKey:
   785  		return mapKey{typ: t}
   786  	case mapValue:
   787  		return mapValue{typ: t}
   788  	case channelElem:
   789  		return channelElem{typ: t}
   790  	case nestedPtrInterface:
   791  		return nestedPtrInterface{typ: t}
   792  	case nestedPtrFunction:
   793  		return nestedPtrFunction{typ: t}
   794  	case field:
   795  		return field{StructType: canonicalize(i.StructType, &b.canon), index: i.index}
   796  	case indexedLocal:
   797  		return indexedLocal{typ: t, val: i.val, index: i.index}
   798  	case local, global, panicArg, recoverReturn, function:
   799  		return n
   800  	default:
   801  		panic(fmt.Errorf("canonicalizing unrecognized node %v", n))
   802  	}
   803  }
   804  
   805  // canonicalize returns a type representative of `t` unique subject
   806  // to type map `canon`.
   807  func canonicalize(t types.Type, canon *typeutil.Map) types.Type {
   808  	rep := canon.At(t)
   809  	if rep != nil {
   810  		return rep.(types.Type)
   811  	}
   812  	canon.Set(t, t)
   813  	return t
   814  }