File: features.go

package info (click to toggle)
golang-golang-x-tools 1%3A0.25.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental, sid, trixie
  • size: 22,724 kB
  • sloc: javascript: 2,027; asm: 1,645; sh: 166; yacc: 155; makefile: 49; ansic: 8
file content (104 lines) | stat: -rw-r--r-- 2,691 bytes parent folder | download | duplicates (2)
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
// 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"

	"golang.org/x/tools/go/ast/inspector"
	"golang.org/x/tools/internal/aliases"
)

// 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 := n.TypeParams; tparams != nil {
				direct |= GenericFuncDecls
			}
		case *ast.InterfaceType:
			tv := info.Types[n]
			if iface, _ := tv.Type.(*types.Interface); iface != nil && !iface.IsMethodSet() {
				direct |= EmbeddedTypeSets
			}
		case *ast.TypeSpec:
			if tparams := n.TypeParams; tparams != nil {
				direct |= GenericTypeDecls
			}
		}
	})

	for _, inst := range info.Instances {
		switch aliases.Unalias(inst.Type).(type) {
		case *types.Named:
			direct |= TypeInstantiation
		case *types.Signature:
			direct |= FuncInstantiation
		}
	}
	return direct
}