// GetFuncValueSourceAsString returns the source of the func value fv. func GetFuncValueSourceAsString(fv reflect.Value) string { // Checking the kind catches cases where f was nil, resulting in fv being a zero Value (i.e. invalid kind), // as well as when fv is non-func. if fv.Kind() != reflect.Func { return "kind not func" } pc := fv.Pointer() if pc == 0 { return "nil" } function := runtime.FuncForPC(pc) if function == nil { return "nil" } file, line := function.FileLine(pc) var startIndex, endIndex int { b, err := ioutil.ReadFile(file) if err != nil { return "<file not found>" } startIndex, endIndex = getLineStartEndIndicies(b, line-1) } fs := token.NewFileSet() fileAst, err := parser.ParseFile(fs, file, nil, 0*parser.ParseComments) if err != nil { return "<ParseFile failed>" } // TODO: Consider using ast.Walk() instead of custom FindFirst() query := func(i interface{}) bool { // TODO: Factor-out the unusual overlap check if f, ok := i.(*ast.FuncLit); ok && ((startIndex <= int(f.Pos())-1 && int(f.Pos())-1 <= endIndex) || (int(f.Pos())-1 <= startIndex && startIndex <= int(f.End())-1)) { return true } return false } funcAst := reflectfind.First(fileAst, query) // If func literal wasn't found, try again looking for func declaration if funcAst == nil { query := func(i interface{}) bool { // TODO: Factor-out the unusual overlap check if f, ok := i.(*ast.FuncDecl); ok && ((startIndex <= int(f.Pos())-1 && int(f.Pos())-1 <= endIndex) || (int(f.Pos())-1 <= startIndex && startIndex <= int(f.End())-1)) { return true } return false } funcAst = reflectfind.First(fileAst, query) } if funcAst == nil { return fmt.Sprintf("<func src not found at %v:%v>", file, line) } return printerutil.SprintAst(fs, funcAst) }
func getParent2ArgExprAllAsAst() []ast.Expr { // TODO: Replace use of debug.Stack() with direct use of runtime package... stack := string(stack()) // TODO: Bounds error checking, get rid of GetLine gists, etc. parentName := getLine(stack, 5) if !strings.Contains(parentName, ": ") { // TODO: This happens when source file isn't present in same location as when built. See if can do anything better // via direct use of runtime package (instead of debug.Stack(), which will exclude any func names)... return nil } parentName = parentName[1:strings.Index(parentName, ": ")] if dotPos := strings.LastIndex(parentName, "."); dotPos != -1 { // Trim package prefix. parentName = parentName[dotPos+1:] } str := getLine(stack, 7) str = str[strings.Index(str, ": ")+len(": "):] p, err := parserutil.ParseStmt(str) if err != nil { return nil } innerQuery := func(i interface{}) bool { if ident, ok := i.(*ast.Ident); ok && ident.Name == parentName { return true } return false } query := func(i interface{}) bool { if c, ok := i.(*ast.CallExpr); ok && nil != reflectfind.First(c.Fun, innerQuery) { return true } return false } callExpr, _ := reflectfind.First(p, query).(*ast.CallExpr) if callExpr == nil { return nil } return callExpr.Args }