stack/source.go
func (p *parsedFile) getFuncAST(f string, l int) (d *ast.FuncDecl) {
	if len(p.lineToByteOffset) <= l {
		// The line number in the stack trace line does not exist in the file. That
		// can only mean that the sources on disk do not match the sources used to
		// build the binary.
		// TODO(maruel): This should be surfaced, so that source parsing is
		// completely ignored.
		return
	}

	// Walk the AST to find the lineToByteOffset that fits the line number.
	var lastFunc *ast.FuncDecl
	var found ast.Node
	// Inspect() goes depth first. This means for example that a function like:
	// func a() {
	//   b := func() {}
	//   c()
	// }
	//
	// Were we are looking at the c() call can return confused values. It is
	// important to look at the actual ast.Node hierarchy.
	ast.Inspect(p.parsed, func(n ast.Node) bool {
		if d != nil {
			return false
		}
		if n == nil {
			return true
		}
		if found != nil {
			// We are walking up.
		}
		if int(n.Pos()) >= p.lineToByteOffset[l] {
			// We are expecting a ast.CallExpr node. It can be harder to figure out
			// when there are multiple calls on a single line, as the stack trace
			// doesn't have file byte offset information, only line based.
			// gofmt will always format to one function call per line but there can
			// be edge cases, like:
			//   a = A{Foo(), Bar()}
			d = lastFunc
			//p.processNode(call, n)
			return false
		} else if f, ok := n.(*ast.FuncDecl); ok {
			lastFunc = f
		}
		return true
	})
	return
}
func (p *parsedFile) getFuncAST(f string, l int) (d *ast.FuncDecl) {
	if len(p.lineToByteOffset) <= l {
		// The line number in the stack trace line does not exist in the file. That
		// can only mean that the sources on disk do not match the sources used to
		// build the binary.
		// TODO(maruel): This should be surfaced, so that source parsing is
		// completely ignored.
		return
	}

	// Walk the AST to find the lineToByteOffset that fits the line number.
	var lastFunc *ast.FuncDecl
	var found ast.Node
	// Inspect() goes depth first. This means for example that a function like:
	// func a() {
	//   b := func() {}
	//   c()
	// }
	//
	// Were we are looking at the c() call can return confused values. It is
	// important to look at the actual ast.Node hierarchy.
	ast.Inspect(p.parsed, func(n ast.Node) bool {
		if d != nil {
			return false
		}
		if n == nil {
			return true
		}
		if found != nil {
			// We are walking up.
		}
		if int(n.Pos()) >= p.lineToByteOffset[l] {
			// We are expecting a ast.CallExpr node. It can be harder to figure out
			// when there are multiple calls on a single line, as the stack trace
			// doesn't have file byte offset information, only line based.
			// gofmt will always format to one function call per line but there can
			// be edge cases, like:
			//   a = A{Foo(), Bar()}
			d = lastFunc
			//p.processNode(call, n)
			return false
		} else if f, ok := n.(*ast.FuncDecl); ok {
			lastFunc = f
		}
		return true
	})
	return
}
func ( p * parsedFile ) getFuncAST ( f string , l int ) ( d * ast . FuncDecl ) { if len ( p . lineToByteOffset ) <= l { // The line number in the stack trace line does not exist in the file. That // can only mean that the sources on disk do not match the sources used to // build the binary. // TODO(maruel): This should be surfaced, so that source parsing is // completely ignored. return } // Walk the AST to find the lineToByteOffset that fits the line number. var lastFunc * ast . FuncDecl var found ast . Node // Inspect() goes depth first. This means for example that a function like: // func a() { //   b := func() {} //   c() // } // // Were we are looking at the c() call can return confused values. It is // important to look at the actual ast.Node hierarchy. ast . Inspect ( p . parsed , func ( n ast . Node ) bool { if d != nil { return false } if n == nil { return true } if found != nil { // We are walking up. } if int ( n . Pos ( ) ) >= p . lineToByteOffset [ l ] { // We are expecting a ast.CallExpr node. It can be harder to figure out // when there are multiple calls on a single line, as the stack trace // doesn't have file byte offset information, only line based. // gofmt will always format to one function call per line but there can // be edge cases, like: //   a = A{Foo(), Bar()} d = lastFunc //p.processNode(call, n) return false } else if f , ok := n . ( * ast . FuncDecl ) ; ok { lastFunc = f } return true } ) return }
// getFuncAST gets the callee site function AST representation for the code
// inside the function f at line l.
getFuncAST gets the callee site function AST representation for the code inside the function f at line l .