...

Source file src/golang.org/x/tools/go/callgraph/static/static_test.go

Documentation: golang.org/x/tools/go/callgraph/static

     1  // Copyright 2014 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 static_test
     6  
     7  import (
     8  	"fmt"
     9  	"go/parser"
    10  	"reflect"
    11  	"sort"
    12  	"testing"
    13  
    14  	"golang.org/x/tools/go/callgraph"
    15  	"golang.org/x/tools/go/callgraph/static"
    16  	"golang.org/x/tools/go/loader"
    17  	"golang.org/x/tools/go/ssa"
    18  	"golang.org/x/tools/go/ssa/ssautil"
    19  )
    20  
    21  const input = `package P
    22  
    23  type C int
    24  func (C) f()
    25  
    26  type I interface{f()}
    27  
    28  func f() {
    29  	p := func() {}
    30  	g()
    31  	p() // SSA constant propagation => static
    32  
    33  	if unknown {
    34  		p = h
    35  	}
    36  	p() // dynamic
    37  
    38  	C(0).f()
    39  }
    40  
    41  func g() {
    42  	var i I = C(0)
    43  	i.f()
    44  }
    45  
    46  func h()
    47  
    48  var unknown bool
    49  `
    50  
    51  const genericsInput = `package P
    52  
    53  type I interface {
    54  	F()
    55  }
    56  
    57  type A struct{}
    58  
    59  func (a A) F() {}
    60  
    61  type B struct{}
    62  
    63  func (b B) F() {}
    64  
    65  func instantiated[X I](x X) {
    66  	x.F()
    67  }
    68  
    69  func Bar() {}
    70  
    71  func f(h func(), a A, b B) {
    72  	h()
    73  
    74  	instantiated[A](a)
    75  	instantiated[B](b)
    76  }
    77  `
    78  
    79  func TestStatic(t *testing.T) {
    80  	for _, e := range []struct {
    81  		input string
    82  		want  []string
    83  		// typeparams must be true if input uses type parameters
    84  		typeparams bool
    85  	}{
    86  		{input, []string{
    87  			"(*C).f -> (C).f",
    88  			"f -> (C).f",
    89  			"f -> f$1",
    90  			"f -> g",
    91  		}, false},
    92  		{genericsInput, []string{
    93  			"(*A).F -> (A).F",
    94  			"(*B).F -> (B).F",
    95  			"f -> instantiated[P.A]",
    96  			"f -> instantiated[P.B]",
    97  			"instantiated[P.A] -> (A).F",
    98  			"instantiated[P.B] -> (B).F",
    99  		}, true},
   100  	} {
   101  		conf := loader.Config{ParserMode: parser.ParseComments}
   102  		f, err := conf.ParseFile("P.go", e.input)
   103  		if err != nil {
   104  			t.Error(err)
   105  			continue
   106  		}
   107  
   108  		conf.CreateFromFiles("P", f)
   109  		iprog, err := conf.Load()
   110  		if err != nil {
   111  			t.Error(err)
   112  			continue
   113  		}
   114  
   115  		P := iprog.Created[0].Pkg
   116  
   117  		prog := ssautil.CreateProgram(iprog, ssa.InstantiateGenerics)
   118  		prog.Build()
   119  
   120  		cg := static.CallGraph(prog)
   121  
   122  		var edges []string
   123  		callgraph.GraphVisitEdges(cg, func(e *callgraph.Edge) error {
   124  			edges = append(edges, fmt.Sprintf("%s -> %s",
   125  				e.Caller.Func.RelString(P),
   126  				e.Callee.Func.RelString(P)))
   127  			return nil
   128  		})
   129  		sort.Strings(edges)
   130  
   131  		if !reflect.DeepEqual(edges, e.want) {
   132  			t.Errorf("Got edges %v, want %v", edges, e.want)
   133  		}
   134  	}
   135  }
   136  

View as plain text