github.com/jujuyuki/gospal@v1.0.1-0.20210215170718-af79fae13b20/ssa/find.go (about)

     1  package ssa
     2  
     3  import (
     4  	"regexp"
     5  	"strings"
     6  
     7  	"golang.org/x/tools/go/ssa"
     8  )
     9  
    10  // FindFunc parses path (e.g. "github.com/nickng/gospal/ssa".MainPkgs) and
    11  // returns Function body in SSA IR.
    12  func (info *Info) FindFunc(path string) (*ssa.Function, error) {
    13  	pkgPath, fnName := parseFuncPath(path)
    14  	graph, err := info.BuildCallGraph("rta", false)
    15  	if err != nil {
    16  		return nil, err
    17  	}
    18  	funcs, err := graph.UsedFunctions()
    19  	if err != nil {
    20  		return nil, err
    21  	}
    22  	for _, f := range funcs {
    23  		if f.Pkg.Pkg.Path() == pkgPath && f.Name() == fnName {
    24  			return f, nil
    25  		}
    26  	}
    27  	return nil, nil
    28  }
    29  
    30  // parseFuncPath splits path to package and function segments.
    31  // Does not handle complex functions with receivers.
    32  func parseFuncPath(path string) (pkgPath, fnName string) {
    33  	if len(path) < 1 {
    34  		return "", ""
    35  	}
    36  	switch path[0] {
    37  	case '(':
    38  		regex := regexp.MustCompile(`\((?P<pkg>[^)]+)\).(?P<fn>.+)`)
    39  		submatches := regex.FindStringSubmatch(path)
    40  		if len(submatches) >= 3 {
    41  			return submatches[1], submatches[2]
    42  		}
    43  	case '"':
    44  		regex := regexp.MustCompile(`"(?P<pkg>[^)]+)".(?P<fn>.+)`)
    45  		submatches := regex.FindStringSubmatch(path)
    46  		if len(submatches) >= 3 {
    47  			return submatches[1], submatches[2]
    48  		}
    49  	default:
    50  		parts := strings.Split(path, ".")
    51  		if len(parts) >= 2 {
    52  			return parts[0], parts[1]
    53  		}
    54  	}
    55  	return "", path
    56  }