package source
import (
)
func ( int, int) (string, error) {
, := CallExprArgs( + 1)
if != nil {
return "",
}
if >= len() {
return "", errors.New("failed to find expression")
}
return FormatNode([])
}
func ( int) ([]ast.Expr, error) {
, , , := runtime.Caller( + 1)
if ! {
return nil, errors.New("failed to get call stack")
}
debug("call stack position: %s:%d", , )
:= token.NewFileSet()
, := parser.ParseFile(, , nil, parser.AllErrors)
if != nil {
return nil, fmt.Errorf("failed to parse source file %s: %w", , )
}
, := getCallExprArgs(, , )
if != nil {
return nil, fmt.Errorf("call from %s:%d: %w", , , )
}
return , nil
}
func ( *token.FileSet, ast.Node, int) (ast.Node, error) {
if := scanToLine(, , ); != nil {
return , nil
}
if := scanToDeferLine(, , ); != nil {
, := guessDefer()
if != nil || != nil {
return ,
}
}
return nil, nil
}
func ( *token.FileSet, ast.Node, int) ast.Node {
var ast.Node
ast.Inspect(, func( ast.Node) bool {
switch {
case == nil || != nil:
return false
case .Position(.Pos()).Line == :
=
return false
}
return true
})
return
}
func ( *token.FileSet, ast.Node, int) ([]ast.Expr, error) {
, := getNodeAtLine(, , )
switch {
case != nil:
return nil,
case == nil:
return nil, fmt.Errorf("failed to find an expression")
}
debug("found node: %s", debugFormatNode{})
:= &callExprVisitor{}
ast.Walk(, )
if .expr == nil {
return nil, errors.New("failed to find call expression")
}
debug("callExpr: %s", debugFormatNode{.expr})
return .expr.Args, nil
}
type callExprVisitor struct {
expr *ast.CallExpr
}
func ( *callExprVisitor) ( ast.Node) ast.Visitor {
if .expr != nil || == nil {
return nil
}
debug("visit: %s", debugFormatNode{})
switch typed := .(type) {
case *ast.CallExpr:
.expr =
return nil
case *ast.DeferStmt:
ast.Walk(, .Call.Fun)
return nil
}
return
}
func ( ast.Node) (string, error) {
:= new(bytes.Buffer)
:= format.Node(, token.NewFileSet(), )
return .String(),
}
var debugEnabled = os.Getenv("GOTESTTOOLS_DEBUG") != ""
func ( string, ...interface{}) {
if debugEnabled {
fmt.Fprintf(os.Stderr, "DEBUG: "++"\n", ...)
}
}
type debugFormatNode struct {
ast.Node
}
func ( debugFormatNode) () string {
if .Node == nil {
return "none"
}
, := FormatNode(.Node)
if != nil {
return fmt.Sprintf("failed to format %s: %s", .Node, )
}
return fmt.Sprintf("(%T) %s", .Node, )
}