180814287SRaphael Isemann //===-- CommandAlias.cpp --------------------------------------------------===//
2937631cfSEnrico Granata //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6937631cfSEnrico Granata //
7937631cfSEnrico Granata //===----------------------------------------------------------------------===//
8937631cfSEnrico Granata 
9937631cfSEnrico Granata #include "lldb/Interpreter/CommandAlias.h"
10937631cfSEnrico Granata 
113e271af4SEnrico Granata #include "llvm/Support/ErrorHandling.h"
123e271af4SEnrico Granata 
13e1cfbc79STodd Fiala #include "lldb/Interpreter/CommandInterpreter.h"
144643c012SEnrico Granata #include "lldb/Interpreter/CommandObject.h"
154643c012SEnrico Granata #include "lldb/Interpreter/CommandReturnObject.h"
164643c012SEnrico Granata #include "lldb/Interpreter/Options.h"
17bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
184643c012SEnrico Granata 
194643c012SEnrico Granata using namespace lldb;
204643c012SEnrico Granata using namespace lldb_private;
214643c012SEnrico Granata 
22b9c1b51eSKate Stone static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp,
23a449698cSZachary Turner                                     llvm::StringRef options_args,
24b9c1b51eSKate Stone                                     OptionArgVectorSP &option_arg_vector_sp) {
254643c012SEnrico Granata   bool success = true;
264643c012SEnrico Granata   OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
274643c012SEnrico Granata 
28a449698cSZachary Turner   if (options_args.size() < 1)
294643c012SEnrico Granata     return true;
304643c012SEnrico Granata 
314643c012SEnrico Granata   Args args(options_args);
32a449698cSZachary Turner   std::string options_string(options_args);
331abaeeceSPavel Labath   // TODO: Find a way to propagate errors in this CommandReturnObject up the
341abaeeceSPavel Labath   // stack.
35de019b88SJonas Devlieghere   CommandReturnObject result(false);
364643c012SEnrico Granata   // Check to see if the command being aliased can take any command options.
374643c012SEnrico Granata   Options *options = cmd_obj_sp->GetOptions();
38b9c1b51eSKate Stone   if (options) {
39b9c1b51eSKate Stone     // See if any options were specified as part of the alias;  if so, handle
40b9c1b51eSKate Stone     // them appropriately.
41e1cfbc79STodd Fiala     ExecutionContext exe_ctx =
42e1cfbc79STodd Fiala         cmd_obj_sp->GetCommandInterpreter().GetExecutionContext();
43e1cfbc79STodd Fiala     options->NotifyOptionParsingStarting(&exe_ctx);
445f56fca4SPavel Labath 
455f56fca4SPavel Labath     llvm::Expected<Args> args_or =
465f56fca4SPavel Labath         options->ParseAlias(args, option_arg_vector, options_string);
475f56fca4SPavel Labath     if (!args_or) {
485f56fca4SPavel Labath       result.AppendError(toString(args_or.takeError()));
495f56fca4SPavel Labath       result.AppendError("Unable to create requested alias.\n");
505f56fca4SPavel Labath       result.SetStatus(eReturnStatusFailed);
515f56fca4SPavel Labath       return false;
525f56fca4SPavel Labath     }
535f56fca4SPavel Labath     args = std::move(*args_or);
544643c012SEnrico Granata     options->VerifyPartialOptions(result);
55b9c1b51eSKate Stone     if (!result.Succeeded() &&
56b9c1b51eSKate Stone         result.GetStatus() != lldb::eReturnStatusStarted) {
574643c012SEnrico Granata       result.AppendError("Unable to create requested alias.\n");
584643c012SEnrico Granata       return false;
594643c012SEnrico Granata     }
604643c012SEnrico Granata   }
614643c012SEnrico Granata 
62b9c1b51eSKate Stone   if (!options_string.empty()) {
634643c012SEnrico Granata     if (cmd_obj_sp->WantsRawCommandString())
645c28c66fSZachary Turner       option_arg_vector->emplace_back("<argument>", -1, options_string);
65b9c1b51eSKate Stone     else {
6697d2c401SZachary Turner       for (auto &entry : args.entries()) {
670d9a201eSRaphael Isemann         if (!entry.ref().empty())
685bbaf543SMartin Storsjö           option_arg_vector->emplace_back(std::string("<argument>"), -1,
695bbaf543SMartin Storsjö                                           std::string(entry.ref()));
7097d2c401SZachary Turner       }
714643c012SEnrico Granata     }
724643c012SEnrico Granata   }
734643c012SEnrico Granata 
744643c012SEnrico Granata   return success;
754643c012SEnrico Granata }
764643c012SEnrico Granata 
773e271af4SEnrico Granata CommandAlias::CommandAlias(CommandInterpreter &interpreter,
783e271af4SEnrico Granata                            lldb::CommandObjectSP cmd_sp,
79a449698cSZachary Turner                            llvm::StringRef options_args, llvm::StringRef name,
80a449698cSZachary Turner                            llvm::StringRef help, llvm::StringRef syntax,
81a449698cSZachary Turner                            uint32_t flags)
82b9c1b51eSKate Stone     : CommandObject(interpreter, name, help, syntax, flags),
83*8cdcd41eSTatyana Krasnukha       m_option_string(std::string(options_args)),
84bef55ac8SEnrico Granata       m_option_args_sp(new OptionArgVector),
85b9c1b51eSKate Stone       m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false),
86b9c1b51eSKate Stone       m_did_set_help_long(false) {
87b9c1b51eSKate Stone   if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) {
883e271af4SEnrico Granata     m_underlying_command_sp = cmd_sp;
89bef55ac8SEnrico Granata     for (int i = 0;
90bef55ac8SEnrico Granata          auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i);
91b9c1b51eSKate Stone          i++) {
92bef55ac8SEnrico Granata       m_arguments.push_back(*cmd_entry);
93bef55ac8SEnrico Granata     }
94a449698cSZachary Turner     if (!help.empty()) {
953e271af4SEnrico Granata       StreamString sstr;
963e271af4SEnrico Granata       StreamString translation_and_help;
973e271af4SEnrico Granata       GetAliasExpansion(sstr);
983e271af4SEnrico Granata 
990fe35b15SZachary Turner       translation_and_help.Printf(
1000fe35b15SZachary Turner           "(%s)  %s", sstr.GetData(),
1011e8016b2SZachary Turner           GetUnderlyingCommand()->GetHelp().str().c_str());
102c156427dSZachary Turner       SetHelp(translation_and_help.GetString());
1033e271af4SEnrico Granata     }
1043e271af4SEnrico Granata   }
1054643c012SEnrico Granata }
1064643c012SEnrico Granata 
107b9c1b51eSKate Stone bool CommandAlias::WantsRawCommandString() {
1083e271af4SEnrico Granata   if (IsValid())
1093e271af4SEnrico Granata     return m_underlying_command_sp->WantsRawCommandString();
1103e271af4SEnrico Granata   return false;
1113e271af4SEnrico Granata }
1123e271af4SEnrico Granata 
113b9c1b51eSKate Stone bool CommandAlias::WantsCompletion() {
114bef55ac8SEnrico Granata   if (IsValid())
115bef55ac8SEnrico Granata     return m_underlying_command_sp->WantsCompletion();
116bef55ac8SEnrico Granata   return false;
117bef55ac8SEnrico Granata }
118bef55ac8SEnrico Granata 
119ae34ed2cSRaphael Isemann void CommandAlias::HandleCompletion(CompletionRequest &request) {
120bef55ac8SEnrico Granata   if (IsValid())
121ae34ed2cSRaphael Isemann     m_underlying_command_sp->HandleCompletion(request);
122bef55ac8SEnrico Granata }
123bef55ac8SEnrico Granata 
124ae34ed2cSRaphael Isemann void CommandAlias::HandleArgumentCompletion(
1252443bbd4SRaphael Isemann     CompletionRequest &request, OptionElementVector &opt_element_vector) {
126bef55ac8SEnrico Granata   if (IsValid())
127ae34ed2cSRaphael Isemann     m_underlying_command_sp->HandleArgumentCompletion(request,
128ae34ed2cSRaphael Isemann                                                       opt_element_vector);
129bef55ac8SEnrico Granata }
130bef55ac8SEnrico Granata 
131b9c1b51eSKate Stone Options *CommandAlias::GetOptions() {
132bef55ac8SEnrico Granata   if (IsValid())
133bef55ac8SEnrico Granata     return m_underlying_command_sp->GetOptions();
134bef55ac8SEnrico Granata   return nullptr;
135bef55ac8SEnrico Granata }
136bef55ac8SEnrico Granata 
137b9c1b51eSKate Stone bool CommandAlias::Execute(const char *args_string,
138b9c1b51eSKate Stone                            CommandReturnObject &result) {
1393e271af4SEnrico Granata   llvm_unreachable("CommandAlias::Execute is not to be called");
1404643c012SEnrico Granata }
1414643c012SEnrico Granata 
142a483f579SZachary Turner void CommandAlias::GetAliasExpansion(StreamString &help_string) const {
143a449698cSZachary Turner   llvm::StringRef command_name = m_underlying_command_sp->GetCommandName();
144a449698cSZachary Turner   help_string.Printf("'%*s", (int)command_name.size(), command_name.data());
1454643c012SEnrico Granata 
1465c28c66fSZachary Turner   if (!m_option_args_sp) {
1475c28c66fSZachary Turner     help_string.Printf("'");
1485c28c66fSZachary Turner     return;
1495c28c66fSZachary Turner   }
1505c28c66fSZachary Turner 
1514643c012SEnrico Granata   OptionArgVector *options = m_option_args_sp.get();
1525c28c66fSZachary Turner   std::string opt;
1535c28c66fSZachary Turner   std::string value;
1545c28c66fSZachary Turner 
1555c28c66fSZachary Turner   for (const auto &opt_entry : *options) {
1565c28c66fSZachary Turner     std::tie(opt, std::ignore, value) = opt_entry;
1575c28c66fSZachary Turner     if (opt == "<argument>") {
1584643c012SEnrico Granata       help_string.Printf(" %s", value.c_str());
159b9c1b51eSKate Stone     } else {
1604643c012SEnrico Granata       help_string.Printf(" %s", opt.c_str());
1618d20cfdfSJonas Devlieghere       if ((value != "<no-argument>") && (value != "<need-argument")) {
1624643c012SEnrico Granata         help_string.Printf(" %s", value.c_str());
1634643c012SEnrico Granata       }
1644643c012SEnrico Granata     }
1654643c012SEnrico Granata   }
1664643c012SEnrico Granata 
1674643c012SEnrico Granata   help_string.Printf("'");
1684643c012SEnrico Granata }
169bef55ac8SEnrico Granata 
170b9c1b51eSKate Stone bool CommandAlias::IsDashDashCommand() {
1715c28c66fSZachary Turner   if (m_is_dashdash_alias != eLazyBoolCalculate)
1725c28c66fSZachary Turner     return (m_is_dashdash_alias == eLazyBoolYes);
173bef55ac8SEnrico Granata   m_is_dashdash_alias = eLazyBoolNo;
1745c28c66fSZachary Turner   if (!IsValid())
1755c28c66fSZachary Turner     return false;
1765c28c66fSZachary Turner 
1775c28c66fSZachary Turner   std::string opt;
1785c28c66fSZachary Turner   std::string value;
1795c28c66fSZachary Turner 
1805c28c66fSZachary Turner   for (const auto &opt_entry : *GetOptionArguments()) {
1815c28c66fSZachary Turner     std::tie(opt, std::ignore, value) = opt_entry;
1825c28c66fSZachary Turner     if (opt == "<argument>" && !value.empty() &&
1835c28c66fSZachary Turner         llvm::StringRef(value).endswith("--")) {
184bef55ac8SEnrico Granata       m_is_dashdash_alias = eLazyBoolYes;
185bef55ac8SEnrico Granata       break;
186bef55ac8SEnrico Granata     }
187bef55ac8SEnrico Granata   }
1885c28c66fSZachary Turner 
18905097246SAdrian Prantl   // if this is a nested alias, it may be adding arguments on top of an already
19005097246SAdrian Prantl   // dash-dash alias
1913c110dd6SEnrico Granata   if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias())
192b9c1b51eSKate Stone     m_is_dashdash_alias =
193b9c1b51eSKate Stone         (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes
194b9c1b51eSKate Stone                                                      : eLazyBoolNo);
195bef55ac8SEnrico Granata   return (m_is_dashdash_alias == eLazyBoolYes);
196bef55ac8SEnrico Granata }
197bef55ac8SEnrico Granata 
198b9c1b51eSKate Stone bool CommandAlias::IsNestedAlias() {
1993c110dd6SEnrico Granata   if (GetUnderlyingCommand())
2003c110dd6SEnrico Granata     return GetUnderlyingCommand()->IsAlias();
2013c110dd6SEnrico Granata   return false;
2023c110dd6SEnrico Granata }
2033c110dd6SEnrico Granata 
204b9c1b51eSKate Stone std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() {
205660764a0SEnrico Granata   auto underlying = GetUnderlyingCommand();
206660764a0SEnrico Granata   if (!underlying)
207660764a0SEnrico Granata     return {nullptr, nullptr};
208660764a0SEnrico Granata 
209b9c1b51eSKate Stone   if (underlying->IsAlias()) {
210660764a0SEnrico Granata     auto desugared = ((CommandAlias *)underlying.get())->Desugar();
211660764a0SEnrico Granata     auto options = GetOptionArguments();
212b9c1b51eSKate Stone     options->insert(options->begin(), desugared.second->begin(),
213b9c1b51eSKate Stone                     desugared.second->end());
214660764a0SEnrico Granata     return {desugared.first, options};
215660764a0SEnrico Granata   }
216660764a0SEnrico Granata 
217660764a0SEnrico Granata   return {underlying, GetOptionArguments()};
218660764a0SEnrico Granata }
219660764a0SEnrico Granata 
220b9c1b51eSKate Stone // allow CommandAlias objects to provide their own help, but fallback to the
22105097246SAdrian Prantl // info for the underlying command if no customization has been provided
222442f6530SZachary Turner void CommandAlias::SetHelp(llvm::StringRef str) {
223bfb75e9bSEnrico Granata   this->CommandObject::SetHelp(str);
224bfb75e9bSEnrico Granata   m_did_set_help = true;
225bfb75e9bSEnrico Granata }
226bfb75e9bSEnrico Granata 
227442f6530SZachary Turner void CommandAlias::SetHelpLong(llvm::StringRef str) {
228bfb75e9bSEnrico Granata   this->CommandObject::SetHelpLong(str);
229bfb75e9bSEnrico Granata   m_did_set_help_long = true;
230bfb75e9bSEnrico Granata }
231bfb75e9bSEnrico Granata 
232442f6530SZachary Turner llvm::StringRef CommandAlias::GetHelp() {
233bfb75e9bSEnrico Granata   if (!m_cmd_help_short.empty() || m_did_set_help)
234442f6530SZachary Turner     return m_cmd_help_short;
235bef55ac8SEnrico Granata   if (IsValid())
236bef55ac8SEnrico Granata     return m_underlying_command_sp->GetHelp();
237442f6530SZachary Turner   return llvm::StringRef();
238bef55ac8SEnrico Granata }
239bef55ac8SEnrico Granata 
240442f6530SZachary Turner llvm::StringRef CommandAlias::GetHelpLong() {
241bfb75e9bSEnrico Granata   if (!m_cmd_help_long.empty() || m_did_set_help_long)
242442f6530SZachary Turner     return m_cmd_help_long;
243bef55ac8SEnrico Granata   if (IsValid())
244bef55ac8SEnrico Granata     return m_underlying_command_sp->GetHelpLong();
245442f6530SZachary Turner   return llvm::StringRef();
246bef55ac8SEnrico Granata }
247