// Copyright 2022 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package ssa_test import ( "go/ast" "go/parser" "go/token" "go/types" "testing" "golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa/ssautil" ) // Tests that MethodValue returns the expected method. func TestMethodValue(t *testing.T) { input := ` package p type I interface{ M() } type S int func (S) M() {} type R[T any] struct{ S } var i I var s S var r R[string] func selections[T any]() { _ = i.M _ = s.M _ = r.M var v R[T] _ = v.M } ` // Parse the file. fset := token.NewFileSet() f, err := parser.ParseFile(fset, "input.go", input, 0) if err != nil { t.Error(err) return } // Build an SSA program from the parsed file. p, info, err := ssautil.BuildPackage(&types.Config{}, fset, types.NewPackage("p", ""), []*ast.File{f}, ssa.SanityCheckFunctions) if err != nil { t.Error(err) return } // Collect all of the *types.Selection in the function "selections". var selections []*types.Selection for _, decl := range f.Decls { if fn, ok := decl.(*ast.FuncDecl); ok && fn.Name.Name == "selections" { for _, stmt := range fn.Body.List { if assign, ok := stmt.(*ast.AssignStmt); ok { sel := assign.Rhs[0].(*ast.SelectorExpr) selections = append(selections, info.Selections[sel]) } } } } wants := map[string]string{ "method (p.S) M()": "(p.S).M", "method (p.R[string]) M()": "(p.R[string]).M", "method (p.I) M()": "nil", // interface "method (p.R[T]) M()": "nil", // parameterized } if len(wants) != len(selections) { t.Fatalf("Wanted %d selections. got %d", len(wants), len(selections)) } for _, selection := range selections { var got string if m := p.Prog.MethodValue(selection); m != nil { got = m.String() } else { got = "nil" } if want := wants[selection.String()]; want != got { t.Errorf("p.Prog.MethodValue(%s) expected %q. got %q", selection, want, got) } } }