| // Copyright 2018 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 typeutil_test |
| |
| import ( |
| "go/ast" |
| "go/importer" |
| "go/parser" |
| "go/token" |
| "go/types" |
| "strings" |
| "testing" |
| |
| "golang.org/x/tools/go/types/typeutil" |
| ) |
| |
| func TestStaticCallee(t *testing.T) { |
| const src = `package p |
| |
| import "fmt" |
| |
| type T int |
| |
| func g(int) |
| |
| var f = g |
| |
| var x int |
| |
| type s struct{ f func(int) } |
| func (s) g(int) |
| |
| type I interface{ f(int) } |
| |
| var a struct{b struct{c s}} |
| |
| func calls() { |
| g(x) // a declared func |
| s{}.g(x) // a concrete method |
| a.b.c.g(x) // same |
| fmt.Println(x) // declared func, qualified identifier |
| } |
| |
| func noncalls() { |
| _ = T(x) // a type |
| f(x) // a var |
| panic(x) // a built-in |
| s{}.f(x) // a field |
| I(nil).f(x) // interface method |
| } |
| ` |
| // parse |
| fset := token.NewFileSet() |
| f, err := parser.ParseFile(fset, "p.go", src, 0) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| // type-check |
| info := &types.Info{ |
| Uses: make(map[*ast.Ident]types.Object), |
| Selections: make(map[*ast.SelectorExpr]*types.Selection), |
| } |
| cfg := &types.Config{Importer: importer.ForCompiler(fset, "source", nil)} |
| if _, err := cfg.Check("p", fset, []*ast.File{f}, info); err != nil { |
| t.Fatal(err) |
| } |
| |
| for _, decl := range f.Decls { |
| if decl, ok := decl.(*ast.FuncDecl); ok && strings.HasSuffix(decl.Name.Name, "calls") { |
| wantCallee := decl.Name.Name == "calls" // false within func noncalls() |
| ast.Inspect(decl.Body, func(n ast.Node) bool { |
| if call, ok := n.(*ast.CallExpr); ok { |
| fn := typeutil.StaticCallee(info, call) |
| if fn == nil && wantCallee { |
| t.Errorf("%s: StaticCallee returned nil", |
| fset.Position(call.Lparen)) |
| } else if fn != nil && !wantCallee { |
| t.Errorf("%s: StaticCallee returned %s, want nil", |
| fset.Position(call.Lparen), fn) |
| } |
| } |
| return true |
| }) |
| } |
| } |
| } |