golang.org/x/tools/gopls@v0.15.3/internal/golang/identifier.go (about)

     1  // Copyright 2018 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 golang
     6  
     7  import (
     8  	"errors"
     9  	"go/ast"
    10  	"go/types"
    11  )
    12  
    13  // ErrNoIdentFound is error returned when no identifier is found at a particular position
    14  var ErrNoIdentFound = errors.New("no identifier found")
    15  
    16  // inferredSignature determines the resolved non-generic signature for an
    17  // identifier in an instantiation expression.
    18  //
    19  // If no such signature exists, it returns nil.
    20  func inferredSignature(info *types.Info, id *ast.Ident) *types.Signature {
    21  	inst := info.Instances[id]
    22  	sig, _ := inst.Type.(*types.Signature)
    23  	return sig
    24  }
    25  
    26  func searchForEnclosing(info *types.Info, path []ast.Node) *types.TypeName {
    27  	for _, n := range path {
    28  		switch n := n.(type) {
    29  		case *ast.SelectorExpr:
    30  			if sel, ok := info.Selections[n]; ok {
    31  				recv := Deref(sel.Recv())
    32  
    33  				// Keep track of the last exported type seen.
    34  				var exported *types.TypeName
    35  				if named, ok := recv.(*types.Named); ok && named.Obj().Exported() {
    36  					exported = named.Obj()
    37  				}
    38  				// We don't want the last element, as that's the field or
    39  				// method itself.
    40  				for _, index := range sel.Index()[:len(sel.Index())-1] {
    41  					if r, ok := recv.Underlying().(*types.Struct); ok {
    42  						recv = Deref(r.Field(index).Type())
    43  						if named, ok := recv.(*types.Named); ok && named.Obj().Exported() {
    44  							exported = named.Obj()
    45  						}
    46  					}
    47  				}
    48  				return exported
    49  			}
    50  		}
    51  	}
    52  	return nil
    53  }
    54  
    55  // typeToObject returns the relevant type name for the given type, after
    56  // unwrapping pointers, arrays, slices, channels, and function signatures with
    57  // a single non-error result, and ignoring built-in named types.
    58  func typeToObject(typ types.Type) *types.TypeName {
    59  	switch typ := typ.(type) {
    60  	case *types.Named:
    61  		// TODO(rfindley): this should use typeparams.NamedTypeOrigin.
    62  		return typ.Obj()
    63  	case *types.Pointer:
    64  		return typeToObject(typ.Elem())
    65  	case *types.Array:
    66  		return typeToObject(typ.Elem())
    67  	case *types.Slice:
    68  		return typeToObject(typ.Elem())
    69  	case *types.Chan:
    70  		return typeToObject(typ.Elem())
    71  	case *types.Signature:
    72  		// Try to find a return value of a named type. If there's only one
    73  		// such value, jump to its type definition.
    74  		var res *types.TypeName
    75  
    76  		results := typ.Results()
    77  		for i := 0; i < results.Len(); i++ {
    78  			obj := typeToObject(results.At(i).Type())
    79  			if obj == nil || hasErrorType(obj) {
    80  				// Skip builtins. TODO(rfindley): should comparable be handled here as well?
    81  				continue
    82  			}
    83  			if res != nil {
    84  				// The function/method must have only one return value of a named type.
    85  				return nil
    86  			}
    87  
    88  			res = obj
    89  		}
    90  		return res
    91  	default:
    92  		return nil
    93  	}
    94  }
    95  
    96  func hasErrorType(obj types.Object) bool {
    97  	return types.IsInterface(obj.Type()) && obj.Pkg() == nil && obj.Name() == "error"
    98  }
    99  
   100  // typeSwitchImplicits returns all the implicit type switch objects that
   101  // correspond to the leaf *ast.Ident. It also returns the original type
   102  // associated with the identifier (outside of a case clause).
   103  func typeSwitchImplicits(info *types.Info, path []ast.Node) ([]types.Object, types.Type) {
   104  	ident, _ := path[0].(*ast.Ident)
   105  	if ident == nil {
   106  		return nil, nil
   107  	}
   108  
   109  	var (
   110  		ts     *ast.TypeSwitchStmt
   111  		assign *ast.AssignStmt
   112  		cc     *ast.CaseClause
   113  		obj    = info.ObjectOf(ident)
   114  	)
   115  
   116  	// Walk our ancestors to determine if our leaf ident refers to a
   117  	// type switch variable, e.g. the "a" from "switch a := b.(type)".
   118  Outer:
   119  	for i := 1; i < len(path); i++ {
   120  		switch n := path[i].(type) {
   121  		case *ast.AssignStmt:
   122  			// Check if ident is the "a" in "a := foo.(type)". The "a" in
   123  			// this case has no types.Object, so check for ident equality.
   124  			if len(n.Lhs) == 1 && n.Lhs[0] == ident {
   125  				assign = n
   126  			}
   127  		case *ast.CaseClause:
   128  			// Check if ident is a use of "a" within a case clause. Each
   129  			// case clause implicitly maps "a" to a different types.Object,
   130  			// so check if ident's object is the case clause's implicit
   131  			// object.
   132  			if obj != nil && info.Implicits[n] == obj {
   133  				cc = n
   134  			}
   135  		case *ast.TypeSwitchStmt:
   136  			// Look for the type switch that owns our previously found
   137  			// *ast.AssignStmt or *ast.CaseClause.
   138  			if n.Assign == assign {
   139  				ts = n
   140  				break Outer
   141  			}
   142  
   143  			for _, stmt := range n.Body.List {
   144  				if stmt == cc {
   145  					ts = n
   146  					break Outer
   147  				}
   148  			}
   149  		}
   150  	}
   151  	if ts == nil {
   152  		return nil, nil
   153  	}
   154  	// Our leaf ident refers to a type switch variable. Fan out to the
   155  	// type switch's implicit case clause objects.
   156  	var objs []types.Object
   157  	for _, cc := range ts.Body.List {
   158  		if ccObj := info.Implicits[cc]; ccObj != nil {
   159  			objs = append(objs, ccObj)
   160  		}
   161  	}
   162  	// The right-hand side of a type switch should only have one
   163  	// element, and we need to track its type in order to generate
   164  	// hover information for implicit type switch variables.
   165  	var typ types.Type
   166  	if assign, ok := ts.Assign.(*ast.AssignStmt); ok && len(assign.Rhs) == 1 {
   167  		if rhs := assign.Rhs[0].(*ast.TypeAssertExpr); ok {
   168  			typ = info.TypeOf(rhs.X)
   169  		}
   170  	}
   171  	return objs, typ
   172  }