github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/typeparams/genericfeatures/features.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // The genericfeatures package provides utilities for detecting usage of 6 // generic programming in Go packages. 7 package genericfeatures 8 9 import ( 10 "go/ast" 11 "go/types" 12 "strings" 13 14 "github.com/powerman/golang-tools/go/ast/inspector" 15 "github.com/powerman/golang-tools/internal/typeparams" 16 ) 17 18 // Features is a set of flags reporting which features of generic Go code a 19 // package uses, or 0. 20 type Features int 21 22 const ( 23 // GenericTypeDecls indicates whether the package declares types with type 24 // parameters. 25 GenericTypeDecls Features = 1 << iota 26 27 // GenericFuncDecls indicates whether the package declares functions with 28 // type parameters. 29 GenericFuncDecls 30 31 // EmbeddedTypeSets indicates whether the package declares interfaces that 32 // contain structural type restrictions, i.e. are not fully described by 33 // their method sets. 34 EmbeddedTypeSets 35 36 // TypeInstantiation indicates whether the package instantiates any generic 37 // types. 38 TypeInstantiation 39 40 // FuncInstantiation indicates whether the package instantiates any generic 41 // functions. 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 // ForPackage computes which generic features are used directly by the 66 // package being analyzed. 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 }