github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/ssa/methods_test.go (about) 1 // Copyright 2022 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 ssa_test 6 7 import ( 8 "go/ast" 9 "go/parser" 10 "go/token" 11 "go/types" 12 "testing" 13 14 "golang.org/x/tools/go/ssa" 15 "golang.org/x/tools/go/ssa/ssautil" 16 "golang.org/x/tools/internal/typeparams" 17 ) 18 19 // Tests that MethodValue returns the expected method. 20 func TestMethodValue(t *testing.T) { 21 if !typeparams.Enabled { 22 t.Skip("TestMethodValue requires type parameters") 23 } 24 input := ` 25 package p 26 27 type I interface{ M() } 28 29 type S int 30 func (S) M() {} 31 type R[T any] struct{ S } 32 33 var i I 34 var s S 35 var r R[string] 36 37 func selections[T any]() { 38 _ = i.M 39 _ = s.M 40 _ = r.M 41 42 var v R[T] 43 _ = v.M 44 } 45 ` 46 47 // Parse the file. 48 fset := token.NewFileSet() 49 f, err := parser.ParseFile(fset, "input.go", input, 0) 50 if err != nil { 51 t.Error(err) 52 return 53 } 54 55 // Build an SSA program from the parsed file. 56 p, info, err := ssautil.BuildPackage(&types.Config{}, fset, 57 types.NewPackage("p", ""), []*ast.File{f}, ssa.SanityCheckFunctions) 58 if err != nil { 59 t.Error(err) 60 return 61 } 62 63 // Collect all of the *types.Selection in the function "selections". 64 var selections []*types.Selection 65 for _, decl := range f.Decls { 66 if fn, ok := decl.(*ast.FuncDecl); ok && fn.Name.Name == "selections" { 67 for _, stmt := range fn.Body.List { 68 if assign, ok := stmt.(*ast.AssignStmt); ok { 69 sel := assign.Rhs[0].(*ast.SelectorExpr) 70 selections = append(selections, info.Selections[sel]) 71 } 72 } 73 } 74 } 75 76 wants := map[string]string{ 77 "method (p.S) M()": "(p.S).M", 78 "method (p.R[string]) M()": "(p.R[string]).M", 79 "method (p.I) M()": "nil", // interface 80 "method (p.R[T]) M()": "nil", // parameterized 81 } 82 if len(wants) != len(selections) { 83 t.Fatalf("Wanted %d selections. got %d", len(wants), len(selections)) 84 } 85 for _, selection := range selections { 86 var got string 87 if m := p.Prog.MethodValue(selection); m != nil { 88 got = m.String() 89 } else { 90 got = "nil" 91 } 92 if want := wants[selection.String()]; want != got { 93 t.Errorf("p.Prog.MethodValue(%s) expected %q. got %q", selection, want, got) 94 } 95 } 96 }