Path: blob/main/contrib/llvm-project/lldb/source/Interpreter/CommandAlias.cpp
39587 views
//===-- CommandAlias.cpp --------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Interpreter/CommandAlias.h"910#include "llvm/ADT/STLExtras.h"11#include "llvm/Support/ErrorHandling.h"1213#include "lldb/Interpreter/CommandInterpreter.h"14#include "lldb/Interpreter/CommandObject.h"15#include "lldb/Interpreter/CommandReturnObject.h"16#include "lldb/Interpreter/Options.h"17#include "lldb/Utility/StreamString.h"1819using namespace lldb;20using namespace lldb_private;2122static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp,23llvm::StringRef options_args,24OptionArgVectorSP &option_arg_vector_sp) {25bool success = true;26OptionArgVector *option_arg_vector = option_arg_vector_sp.get();2728if (options_args.size() < 1)29return true;3031Args args(options_args);32std::string options_string(options_args);33// TODO: Find a way to propagate errors in this CommandReturnObject up the34// stack.35CommandReturnObject result(false);36// Check to see if the command being aliased can take any command options.37Options *options = cmd_obj_sp->GetOptions();38if (options) {39// See if any options were specified as part of the alias; if so, handle40// them appropriately.41ExecutionContext exe_ctx =42cmd_obj_sp->GetCommandInterpreter().GetExecutionContext();43options->NotifyOptionParsingStarting(&exe_ctx);4445llvm::Expected<Args> args_or =46options->ParseAlias(args, option_arg_vector, options_string);47if (!args_or) {48result.AppendError(toString(args_or.takeError()));49result.AppendError("Unable to create requested alias.\n");50return false;51}52args = std::move(*args_or);53options->VerifyPartialOptions(result);54if (!result.Succeeded() &&55result.GetStatus() != lldb::eReturnStatusStarted) {56result.AppendError("Unable to create requested alias.\n");57return false;58}59}6061if (!options_string.empty()) {62if (cmd_obj_sp->WantsRawCommandString())63option_arg_vector->emplace_back(CommandInterpreter::g_argument,64-1, options_string);65else {66for (auto &entry : args.entries()) {67if (!entry.ref().empty())68option_arg_vector->emplace_back(std::string(CommandInterpreter::g_argument), -1,69std::string(entry.ref()));70}71}72}7374return success;75}7677CommandAlias::CommandAlias(CommandInterpreter &interpreter,78lldb::CommandObjectSP cmd_sp,79llvm::StringRef options_args, llvm::StringRef name,80llvm::StringRef help, llvm::StringRef syntax,81uint32_t flags)82: CommandObject(interpreter, name, help, syntax, flags),83m_option_string(std::string(options_args)),84m_option_args_sp(new OptionArgVector),85m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false),86m_did_set_help_long(false) {87if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) {88m_underlying_command_sp = cmd_sp;89for (int i = 0;90auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i);91i++) {92m_arguments.push_back(*cmd_entry);93}94if (!help.empty()) {95StreamString sstr;96StreamString translation_and_help;97GetAliasExpansion(sstr);9899translation_and_help.Printf(100"(%s) %s", sstr.GetData(),101GetUnderlyingCommand()->GetHelp().str().c_str());102SetHelp(translation_and_help.GetString());103}104}105}106107bool CommandAlias::WantsRawCommandString() {108if (IsValid())109return m_underlying_command_sp->WantsRawCommandString();110return false;111}112113bool CommandAlias::WantsCompletion() {114if (IsValid())115return m_underlying_command_sp->WantsCompletion();116return false;117}118119void CommandAlias::HandleCompletion(CompletionRequest &request) {120if (IsValid())121m_underlying_command_sp->HandleCompletion(request);122}123124void CommandAlias::HandleArgumentCompletion(125CompletionRequest &request, OptionElementVector &opt_element_vector) {126if (IsValid())127m_underlying_command_sp->HandleArgumentCompletion(request,128opt_element_vector);129}130131Options *CommandAlias::GetOptions() {132if (IsValid())133return m_underlying_command_sp->GetOptions();134return nullptr;135}136137void CommandAlias::Execute(const char *args_string,138CommandReturnObject &result) {139llvm_unreachable("CommandAlias::Execute is not to be called");140}141142void CommandAlias::GetAliasExpansion(StreamString &help_string) const {143llvm::StringRef command_name = m_underlying_command_sp->GetCommandName();144help_string.Printf("'%*s", (int)command_name.size(), command_name.data());145146if (!m_option_args_sp) {147help_string.Printf("'");148return;149}150151OptionArgVector *options = m_option_args_sp.get();152std::string opt;153std::string value;154155for (const auto &opt_entry : *options) {156std::tie(opt, std::ignore, value) = opt_entry;157if (opt == CommandInterpreter::g_argument) {158help_string.Printf(" %s", value.c_str());159} else {160help_string.Printf(" %s", opt.c_str());161if ((value != CommandInterpreter::g_no_argument)162&& (value != CommandInterpreter::g_need_argument)) {163help_string.Printf(" %s", value.c_str());164}165}166}167168help_string.Printf("'");169}170171bool CommandAlias::IsDashDashCommand() {172if (m_is_dashdash_alias != eLazyBoolCalculate)173return (m_is_dashdash_alias == eLazyBoolYes);174m_is_dashdash_alias = eLazyBoolNo;175if (!IsValid())176return false;177178std::string opt;179std::string value;180181for (const auto &opt_entry : *GetOptionArguments()) {182std::tie(opt, std::ignore, value) = opt_entry;183if (opt == CommandInterpreter::g_argument && !value.empty() &&184llvm::StringRef(value).ends_with("--")) {185m_is_dashdash_alias = eLazyBoolYes;186break;187}188}189190// if this is a nested alias, it may be adding arguments on top of an already191// dash-dash alias192if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias())193m_is_dashdash_alias =194(GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes195: eLazyBoolNo);196return (m_is_dashdash_alias == eLazyBoolYes);197}198199bool CommandAlias::IsNestedAlias() {200if (GetUnderlyingCommand())201return GetUnderlyingCommand()->IsAlias();202return false;203}204205std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() {206auto underlying = GetUnderlyingCommand();207if (!underlying)208return {nullptr, nullptr};209210if (underlying->IsAlias()) {211// FIXME: This doesn't work if the original alias fills a slot in the212// underlying alias, since this just appends the two lists.213auto desugared = ((CommandAlias *)underlying.get())->Desugar();214OptionArgVectorSP options = std::make_shared<OptionArgVector>();215llvm::append_range(*options, *desugared.second);216llvm::append_range(*options, *GetOptionArguments());217return {desugared.first, options};218}219220return {underlying, GetOptionArguments()};221}222223// allow CommandAlias objects to provide their own help, but fallback to the224// info for the underlying command if no customization has been provided225void CommandAlias::SetHelp(llvm::StringRef str) {226this->CommandObject::SetHelp(str);227m_did_set_help = true;228}229230void CommandAlias::SetHelpLong(llvm::StringRef str) {231this->CommandObject::SetHelpLong(str);232m_did_set_help_long = true;233}234235llvm::StringRef CommandAlias::GetHelp() {236if (!m_cmd_help_short.empty() || m_did_set_help)237return m_cmd_help_short;238if (IsValid())239return m_underlying_command_sp->GetHelp();240return llvm::StringRef();241}242243llvm::StringRef CommandAlias::GetHelpLong() {244if (!m_cmd_help_long.empty() || m_did_set_help_long)245return m_cmd_help_long;246if (IsValid())247return m_underlying_command_sp->GetHelpLong();248return llvm::StringRef();249}250251252