...
1
2
3
4
5
6
7 package genericfeatures
8
9 import (
10 "go/ast"
11 "go/types"
12 "strings"
13
14 "golang.org/x/tools/go/ast/inspector"
15 "golang.org/x/tools/internal/typeparams"
16 )
17
18
19
20 type Features int
21
22 const (
23
24
25 GenericTypeDecls Features = 1 << iota
26
27
28
29 GenericFuncDecls
30
31
32
33
34 EmbeddedTypeSets
35
36
37
38 TypeInstantiation
39
40
41
42 FuncInstantiation
43 )
44
45 func (f Features) String() string {
46 var feats []string
47 if f&GenericTypeDecls != 0 {
48 feats = append(feats, "typeDecl")
49 }
50 if f&GenericFuncDecls != 0 {
51 feats = append(feats, "funcDecl")
52 }
53 if f&EmbeddedTypeSets != 0 {
54 feats = append(feats, "typeSet")
55 }
56 if f&TypeInstantiation != 0 {
57 feats = append(feats, "typeInstance")
58 }
59 if f&FuncInstantiation != 0 {
60 feats = append(feats, "funcInstance")
61 }
62 return "features{" + strings.Join(feats, ",") + "}"
63 }
64
65
66
67 func ForPackage(inspect *inspector.Inspector, info *types.Info) Features {
68 nodeFilter := []ast.Node{
69 (*ast.FuncType)(nil),
70 (*ast.InterfaceType)(nil),
71 (*ast.ImportSpec)(nil),
72 (*ast.TypeSpec)(nil),
73 }
74
75 var direct Features
76
77 inspect.Preorder(nodeFilter, func(node ast.Node) {
78 switch n := node.(type) {
79 case *ast.FuncType:
80 if tparams := typeparams.ForFuncType(n); tparams != nil {
81 direct |= GenericFuncDecls
82 }
83 case *ast.InterfaceType:
84 tv := info.Types[n]
85 if iface, _ := tv.Type.(*types.Interface); iface != nil && !typeparams.IsMethodSet(iface) {
86 direct |= EmbeddedTypeSets
87 }
88 case *ast.TypeSpec:
89 if tparams := typeparams.ForTypeSpec(n); tparams != nil {
90 direct |= GenericTypeDecls
91 }
92 }
93 })
94
95 instances := typeparams.GetInstances(info)
96 for _, inst := range instances {
97 switch inst.Type.(type) {
98 case *types.Named:
99 direct |= TypeInstantiation
100 case *types.Signature:
101 direct |= FuncInstantiation
102 }
103 }
104 return direct
105 }
106
View as plain text