code: 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
  }
docs: // getFuncAST gets the callee site function AST representation for the code
  // inside the function f at line l.