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  }