Beispiel #1
0
// 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)
}
Beispiel #2
0
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
}