golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/refactor/rename/util.go (about)

     1  // Copyright 2014 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 rename
     6  
     7  import (
     8  	"go/ast"
     9  	"go/token"
    10  	"go/types"
    11  	"os"
    12  	"path/filepath"
    13  	"reflect"
    14  	"runtime"
    15  	"strings"
    16  	"unicode"
    17  
    18  	"golang.org/x/tools/go/ast/astutil"
    19  )
    20  
    21  func objectKind(obj types.Object) string {
    22  	switch obj := obj.(type) {
    23  	case *types.PkgName:
    24  		return "imported package name"
    25  	case *types.TypeName: // defined type | alias | type parameter
    26  		return "type"
    27  	case *types.Var:
    28  		if obj.IsField() {
    29  			return "field"
    30  		}
    31  	case *types.Func:
    32  		if obj.Type().(*types.Signature).Recv() != nil {
    33  			return "method"
    34  		}
    35  	}
    36  	// label, func, var, const
    37  	return strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types."))
    38  }
    39  
    40  // NB: for renamings, blank is not considered valid.
    41  func isValidIdentifier(id string) bool {
    42  	if id == "" || id == "_" {
    43  		return false
    44  	}
    45  	for i, r := range id {
    46  		if !isLetter(r) && (i == 0 || !isDigit(r)) {
    47  			return false
    48  		}
    49  	}
    50  	return token.Lookup(id) == token.IDENT
    51  }
    52  
    53  // isLocal reports whether obj is local to some function.
    54  // Precondition: not a struct field or interface method.
    55  func isLocal(obj types.Object) bool {
    56  	// [... 5=stmt 4=func 3=file 2=pkg 1=universe]
    57  	var depth int
    58  	for scope := obj.Parent(); scope != nil; scope = scope.Parent() {
    59  		depth++
    60  	}
    61  	return depth >= 4
    62  }
    63  
    64  func isPackageLevel(obj types.Object) bool {
    65  	return obj.Pkg().Scope().Lookup(obj.Name()) == obj
    66  }
    67  
    68  // -- Plundered from go/scanner: ---------------------------------------
    69  
    70  func isLetter(ch rune) bool {
    71  	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
    72  }
    73  
    74  func isDigit(ch rune) bool {
    75  	return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
    76  }
    77  
    78  // -- Plundered from golang.org/x/tools/cmd/guru -----------------
    79  
    80  // sameFile returns true if x and y have the same basename and denote
    81  // the same file.
    82  func sameFile(x, y string) bool {
    83  	if runtime.GOOS == "windows" {
    84  		x = filepath.ToSlash(x)
    85  		y = filepath.ToSlash(y)
    86  	}
    87  	if x == y {
    88  		return true
    89  	}
    90  	if filepath.Base(x) == filepath.Base(y) { // (optimisation)
    91  		if xi, err := os.Stat(x); err == nil {
    92  			if yi, err := os.Stat(y); err == nil {
    93  				return os.SameFile(xi, yi)
    94  			}
    95  		}
    96  	}
    97  	return false
    98  }
    99  
   100  func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
   101  
   102  func is[T any](x any) bool {
   103  	_, ok := x.(T)
   104  	return ok
   105  }