-
Notifications
You must be signed in to change notification settings - Fork 0
/
method.go
107 lines (93 loc) · 1.92 KB
/
method.go
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package traceable
import (
"go/types"
"strconv"
)
type Method struct {
name string
args []types.Type
returns []types.Type
isVariadic bool
}
func (m Method) acceptsContext() bool {
if len(m.args) == 0 {
return false
}
for _, a := range m.args {
if isContextType(a) {
return true
}
}
return false
}
func (m Method) contextArg() string {
for i, a := range m.args {
if isContextType(a) {
return "a" + strconv.Itoa(i)
}
}
return ""
}
func (m Method) imports() map[string]struct{} {
imports := make(map[string]struct{})
for _, t := range m.args {
for ip := range importsOf(t) {
imports[ip] = struct{}{}
}
}
for _, t := range m.returns {
for ip := range importsOf(t) {
imports[ip] = struct{}{}
}
}
return imports
}
func importsOf(t types.Type) map[string]struct{} {
switch u := t.(type) {
case *types.Pointer:
return importsOf(u.Elem())
case *types.Map:
return mergeMaps(importsOf(u.Key()), importsOf(u.Elem()))
case *types.Array:
return importsOf(u.Elem())
case *types.Slice:
return importsOf(u.Elem())
case *types.Chan:
return importsOf(u.Elem())
case *types.Signature:
imports := make(map[string]struct{})
for i := 0; i < u.Params().Len(); i++ {
imports = mergeMaps(imports, importsOf(u.Params().At(i).Type()))
}
for i := 0; i < u.Results().Len(); i++ {
imports = mergeMaps(imports, importsOf(u.Results().At(i).Type()))
}
return imports
case *types.Named:
if pkg := u.Obj().Pkg(); pkg != nil {
return map[string]struct{}{
pkg.Path(): struct{}{},
}
}
return nil
default:
return nil
}
}
func isContextType(t types.Type) bool {
named, ok := t.(*types.Named)
if !ok {
return false
}
return named.Obj().Name() == "Context"
}
func mergeMaps(a map[string]struct{}, maps ...map[string]struct{}) map[string]struct{} {
for _, b := range maps {
for bk, bv := range b {
if _, ok := a[bk]; !ok {
a[bk] = bv
}
}
}
return a
}