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  }