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 }