cuelang.org/go@v0.10.1/internal/golangorgx/tools/refactor/inline/util.go (about)

     1  // Copyright 2023 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  package inline
     6  
     7  // This file defines various common helpers.
     8  
     9  import (
    10  	"go/ast"
    11  	"go/token"
    12  	"go/types"
    13  	"reflect"
    14  	"strings"
    15  
    16  	"cuelang.org/go/internal/golangorgx/tools/typeparams"
    17  )
    18  
    19  func is[T any](x any) bool {
    20  	_, ok := x.(T)
    21  	return ok
    22  }
    23  
    24  // TODO(adonovan): use go1.21's slices.Clone.
    25  func clone[T any](slice []T) []T { return append([]T{}, slice...) }
    26  
    27  // TODO(adonovan): use go1.21's slices.Index.
    28  func index[T comparable](slice []T, x T) int {
    29  	for i, elem := range slice {
    30  		if elem == x {
    31  			return i
    32  		}
    33  	}
    34  	return -1
    35  }
    36  
    37  func btoi(b bool) int {
    38  	if b {
    39  		return 1
    40  	} else {
    41  		return 0
    42  	}
    43  }
    44  
    45  func offsetOf(fset *token.FileSet, pos token.Pos) int {
    46  	return fset.PositionFor(pos, false).Offset
    47  }
    48  
    49  // objectKind returns an object's kind (e.g. var, func, const, typename).
    50  func objectKind(obj types.Object) string {
    51  	return strings.TrimPrefix(strings.ToLower(reflect.TypeOf(obj).String()), "*types.")
    52  }
    53  
    54  // within reports whether pos is within the half-open interval [n.Pos, n.End).
    55  func within(pos token.Pos, n ast.Node) bool {
    56  	return n.Pos() <= pos && pos < n.End()
    57  }
    58  
    59  // trivialConversion reports whether it is safe to omit the implicit
    60  // value-to-variable conversion that occurs in argument passing or
    61  // result return. The only case currently allowed is converting from
    62  // untyped constant to its default type (e.g. 0 to int).
    63  //
    64  // The reason for this check is that converting from A to B to C may
    65  // yield a different result than converting A directly to C: consider
    66  // 0 to int32 to any.
    67  func trivialConversion(val types.Type, obj *types.Var) bool {
    68  	return types.Identical(types.Default(val), obj.Type())
    69  }
    70  
    71  func checkInfoFields(info *types.Info) {
    72  	assert(info.Defs != nil, "types.Info.Defs is nil")
    73  	assert(info.Implicits != nil, "types.Info.Implicits is nil")
    74  	assert(info.Scopes != nil, "types.Info.Scopes is nil")
    75  	assert(info.Selections != nil, "types.Info.Selections is nil")
    76  	assert(info.Types != nil, "types.Info.Types is nil")
    77  	assert(info.Uses != nil, "types.Info.Uses is nil")
    78  }
    79  
    80  func funcHasTypeParams(decl *ast.FuncDecl) bool {
    81  	// generic function?
    82  	if decl.Type.TypeParams != nil {
    83  		return true
    84  	}
    85  	// method on generic type?
    86  	if decl.Recv != nil {
    87  		t := decl.Recv.List[0].Type
    88  		if u, ok := t.(*ast.StarExpr); ok {
    89  			t = u.X
    90  		}
    91  		return is[*ast.IndexExpr](t) || is[*ast.IndexListExpr](t)
    92  	}
    93  	return false
    94  }
    95  
    96  // intersects reports whether the maps' key sets intersect.
    97  func intersects[K comparable, T1, T2 any](x map[K]T1, y map[K]T2) bool {
    98  	if len(x) > len(y) {
    99  		return intersects(y, x)
   100  	}
   101  	for k := range x {
   102  		if _, ok := y[k]; ok {
   103  			return true
   104  		}
   105  	}
   106  	return false
   107  }
   108  
   109  // convert returns syntax for the conversion T(x).
   110  func convert(T, x ast.Expr) *ast.CallExpr {
   111  	// The formatter generally adds parens as needed,
   112  	// but before go1.22 it had a bug (#63362) for
   113  	// channel types that requires this workaround.
   114  	if ch, ok := T.(*ast.ChanType); ok && ch.Dir == ast.RECV {
   115  		T = &ast.ParenExpr{X: T}
   116  	}
   117  	return &ast.CallExpr{
   118  		Fun:  T,
   119  		Args: []ast.Expr{x},
   120  	}
   121  }
   122  
   123  // isPointer reports whether t is a pointer type.
   124  func isPointer(t types.Type) bool { return t != deref(t) }
   125  
   126  // indirectSelection is like seln.Indirect() without bug #8353.
   127  func indirectSelection(seln *types.Selection) bool {
   128  	// Work around bug #8353 in Selection.Indirect when Kind=MethodVal.
   129  	if seln.Kind() == types.MethodVal {
   130  		tArg, indirect := effectiveReceiver(seln)
   131  		if indirect {
   132  			return true
   133  		}
   134  
   135  		tParam := seln.Obj().Type().Underlying().(*types.Signature).Recv().Type()
   136  		return isPointer(tArg) && !isPointer(tParam) // implicit *
   137  	}
   138  
   139  	return seln.Indirect()
   140  }
   141  
   142  // effectiveReceiver returns the effective type of the method
   143  // receiver after all implicit field selections (but not implicit * or
   144  // & operations) have been applied.
   145  //
   146  // The boolean indicates whether any implicit field selection was indirect.
   147  func effectiveReceiver(seln *types.Selection) (types.Type, bool) {
   148  	assert(seln.Kind() == types.MethodVal, "not MethodVal")
   149  	t := seln.Recv()
   150  	indices := seln.Index()
   151  	indirect := false
   152  	for _, index := range indices[:len(indices)-1] {
   153  		if tElem := deref(t); tElem != t {
   154  			indirect = true
   155  			t = tElem
   156  		}
   157  		t = typeparams.CoreType(t).(*types.Struct).Field(index).Type()
   158  	}
   159  	return t, indirect
   160  }