diff --git a/src/builtin_argparse.cpp b/src/builtin_argparse.cpp index b4facf9a4..93cf4d433 100644 --- a/src/builtin_argparse.cpp +++ b/src/builtin_argparse.cpp @@ -433,10 +433,11 @@ static int parse_cmd_opts(argparse_cmd_opts_t &opts, int *optind, //!OCLINT(hig if (opts.name.empty()) { // If no name has been given, we default to the function name. // If any error happens, the backtrace will show which argparse it was. - const wchar_t *fn = parser.get_function_name(1); - - if (!fn) fn = L"argparse"; - opts.name = fn; + if (maybe_t fn = parser.get_function_name(1)) { + opts.name = fn.acquire(); + } else { + opts.name = L"argparse"; + } } *optind = w.woptind; diff --git a/src/builtin_status.cpp b/src/builtin_status.cpp index 8235527e1..db87ef454 100644 --- a/src/builtin_status.cpp +++ b/src/builtin_status.cpp @@ -381,10 +381,8 @@ maybe_t builtin_status(parser_t &parser, io_streams_t &streams, const wchar } case STATUS_FUNCTION: { CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd) - const wchar_t *fn = parser.get_function_name(opts.level); - - if (!fn) fn = _(L"Not a function"); - streams.out.append_format(L"%ls\n", fn); + maybe_t fn = parser.get_function_name(opts.level); + streams.out.append_format(L"%ls\n", fn ? fn->c_str() : _(L"Not a function")); break; } case STATUS_LINE_NUMBER: { diff --git a/src/parser.cpp b/src/parser.cpp index 3b25bb173..0f49622b0 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -412,26 +412,19 @@ wcstring parser_t::stack_trace() const { return trace; } -/// Returns the name of the currently evaluated function if we are currently evaluating a function, -/// NULL otherwise. This is tested by moving down the block-scope-stack, checking every block if it -/// is of type FUNCTION_CALL. If the caller doesn't specify a starting position in the stack we -/// begin with the current block. -const wchar_t *parser_t::is_function() const { +bool parser_t::is_function() const { for (const auto &b : block_list) { if (b.is_function_call()) { - return b.function_name.c_str(); + return true; } else if (b.type() == block_type_t::source) { - // If a function sources a file, obviously that function's offset doesn't - // contribute. + // If a function sources a file, don't descend further. break; } } - return nullptr; + return false; } -/// Return the function name for the specified stack frame. Default is zero (current frame). -/// The special value zero means the function frame immediately above the closest breakpoint frame. -const wchar_t *parser_t::get_function_name(int level) { +maybe_t parser_t::get_function_name(int level) { if (level == 0) { // Return the function name for the level preceding the most recent breakpoint. If there // isn't one return the function name for the current level. @@ -441,13 +434,10 @@ const wchar_t *parser_t::get_function_name(int level) { if (b.type() == block_type_t::breakpoint) { found_breakpoint = true; } else if (found_breakpoint && b.is_function_call()) { - return b.function_name.c_str(); + return b.function_name; } } - return nullptr; // couldn't find a breakpoint frame - } else if (level == 1) { - // Return the function name for the current level. - return this->is_function(); + return none(); // couldn't find a breakpoint frame } // Level 1 is the topmost function call. Level 2 is its caller. Etc. @@ -456,11 +446,15 @@ const wchar_t *parser_t::get_function_name(int level) { if (b.is_function_call()) { funcs_seen++; if (funcs_seen == level) { - return b.function_name.c_str(); + return b.function_name; } + } else if (b.type() == block_type_t::source && level == 1) { + // Historical: If we want the topmost function, but we are really in a file sourced by a + // function, don't consider ourselves to be in a function. + break; } } - return nullptr; // couldn't find that function level + return none(); } int parser_t::get_lineno() const { diff --git a/src/parser.h b/src/parser.h index 19fa21110..49ce937f9 100644 --- a/src/parser.h +++ b/src/parser.h @@ -282,10 +282,8 @@ class parser_t : public std::enable_shared_from_this { /// Adds a job to the beginning of the job list. void job_add(shared_ptr job); - /// Returns the name of the currently evaluated function if we are currently evaluating a - /// function, null otherwise. This is tested by moving down the block-scope-stack, checking - /// every block if it is of type FUNCTION_CALL. - const wchar_t *is_function() const; + /// \return whether we are currently evaluating a function. + bool is_function() const; /// Create a parser. parser_t(); @@ -394,7 +392,7 @@ class parser_t : public std::enable_shared_from_this { static const wchar_t *get_block_desc(block_type_t block); /// Return the function name for the specified stack frame. Default is one (current frame). - const wchar_t *get_function_name(int level = 1); + maybe_t get_function_name(int level = 1); /// Promotes a job to the front of the list. void job_promote(job_t *job);