forked from golang/tools
/
features.go
105 lines (91 loc) · 2.7 KB
/
features.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
// Copyright 2021 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.
// The genericfeatures package provides utilities for detecting usage of
// generic programming in Go packages.
package genericfeatures
import (
"go/ast"
"go/types"
"strings"
"github.com/bafko/tools/go/ast/inspector"
"github.com/bafko/tools/internal/typeparams"
)
// Features is a set of flags reporting which features of generic Go code a
// package uses, or 0.
type Features int
const (
// GenericTypeDecls indicates whether the package declares types with type
// parameters.
GenericTypeDecls Features = 1 << iota
// GenericFuncDecls indicates whether the package declares functions with
// type parameters.
GenericFuncDecls
// EmbeddedTypeSets indicates whether the package declares interfaces that
// contain structural type restrictions, i.e. are not fully described by
// their method sets.
EmbeddedTypeSets
// TypeInstantiation indicates whether the package instantiates any generic
// types.
TypeInstantiation
// FuncInstantiation indicates whether the package instantiates any generic
// functions.
FuncInstantiation
)
func (f Features) String() string {
var feats []string
if f&GenericTypeDecls != 0 {
feats = append(feats, "typeDecl")
}
if f&GenericFuncDecls != 0 {
feats = append(feats, "funcDecl")
}
if f&EmbeddedTypeSets != 0 {
feats = append(feats, "typeSet")
}
if f&TypeInstantiation != 0 {
feats = append(feats, "typeInstance")
}
if f&FuncInstantiation != 0 {
feats = append(feats, "funcInstance")
}
return "features{" + strings.Join(feats, ",") + "}"
}
// ForPackage computes which generic features are used directly by the
// package being analyzed.
func ForPackage(inspect *inspector.Inspector, info *types.Info) Features {
nodeFilter := []ast.Node{
(*ast.FuncType)(nil),
(*ast.InterfaceType)(nil),
(*ast.ImportSpec)(nil),
(*ast.TypeSpec)(nil),
}
var direct Features
inspect.Preorder(nodeFilter, func(node ast.Node) {
switch n := node.(type) {
case *ast.FuncType:
if tparams := typeparams.ForFuncType(n); tparams != nil {
direct |= GenericFuncDecls
}
case *ast.InterfaceType:
tv := info.Types[n]
if iface, _ := tv.Type.(*types.Interface); iface != nil && !typeparams.IsMethodSet(iface) {
direct |= EmbeddedTypeSets
}
case *ast.TypeSpec:
if tparams := typeparams.ForTypeSpec(n); tparams != nil {
direct |= GenericTypeDecls
}
}
})
instances := typeparams.GetInstances(info)
for _, inst := range instances {
switch inst.Type.(type) {
case *types.Named:
direct |= TypeInstantiation
case *types.Signature:
direct |= FuncInstantiation
}
}
return direct
}