Source file src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go

     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 testinggoroutine
     6  
     7  import (
     8  	"go/ast"
     9  	"go/types"
    10  	"slices"
    11  )
    12  
    13  // AST and types utilities that not specific to testinggoroutines.
    14  
    15  // localFunctionDecls returns a mapping from *types.Func to *ast.FuncDecl in files.
    16  func localFunctionDecls(info *types.Info, files []*ast.File) func(*types.Func) *ast.FuncDecl {
    17  	var fnDecls map[*types.Func]*ast.FuncDecl // computed lazily
    18  	return func(f *types.Func) *ast.FuncDecl {
    19  		if f != nil && fnDecls == nil {
    20  			fnDecls = make(map[*types.Func]*ast.FuncDecl)
    21  			for _, file := range files {
    22  				for _, decl := range file.Decls {
    23  					if fnDecl, ok := decl.(*ast.FuncDecl); ok {
    24  						if fn, ok := info.Defs[fnDecl.Name].(*types.Func); ok {
    25  							fnDecls[fn] = fnDecl
    26  						}
    27  					}
    28  				}
    29  			}
    30  		}
    31  		// TODO: set f = f.Origin() here.
    32  		return fnDecls[f]
    33  	}
    34  }
    35  
    36  // isMethodNamed returns true if f is a method defined
    37  // in package with the path pkgPath with a name in names.
    38  //
    39  // (Unlike [analysisinternal.IsMethodNamed], it ignores the receiver type name.)
    40  func isMethodNamed(f *types.Func, pkgPath string, names ...string) bool {
    41  	if f == nil {
    42  		return false
    43  	}
    44  	if f.Pkg() == nil || f.Pkg().Path() != pkgPath {
    45  		return false
    46  	}
    47  	if f.Type().(*types.Signature).Recv() == nil {
    48  		return false
    49  	}
    50  	return slices.Contains(names, f.Name())
    51  }
    52  
    53  // funcLitInScope returns a FuncLit that id is at least initially assigned to.
    54  //
    55  // TODO: This is closely tied to id.Obj which is deprecated.
    56  func funcLitInScope(id *ast.Ident) *ast.FuncLit {
    57  	// Compare to (*ast.Object).Pos().
    58  	if id.Obj == nil {
    59  		return nil
    60  	}
    61  	var rhs ast.Expr
    62  	switch d := id.Obj.Decl.(type) {
    63  	case *ast.AssignStmt:
    64  		for i, x := range d.Lhs {
    65  			if ident, isIdent := x.(*ast.Ident); isIdent && ident.Name == id.Name && i < len(d.Rhs) {
    66  				rhs = d.Rhs[i]
    67  			}
    68  		}
    69  	case *ast.ValueSpec:
    70  		for i, n := range d.Names {
    71  			if n.Name == id.Name && i < len(d.Values) {
    72  				rhs = d.Values[i]
    73  			}
    74  		}
    75  	}
    76  	lit, _ := rhs.(*ast.FuncLit)
    77  	return lit
    78  }
    79  

View as plain text