File: callee_test.go

package info (click to toggle)
golang-golang-x-tools 1%3A0.0~git20190125.d66bd3c%2Bds-4
  • links: PTS, VCS
  • area: main
  • in suites: buster, buster-backports
  • size: 8,912 kB
  • sloc: asm: 1,394; yacc: 155; makefile: 109; sh: 108; ansic: 17; xml: 11
file content (89 lines) | stat: -rw-r--r-- 1,925 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// 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.For("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
			})
		}
	}
}