golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/go/callgraph/static/static_test.go (about) 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 }