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 
ProcessAliasOptionsArgs(lldb::CommandObjectSP & cmd_obj_sp,llvm::StringRef options_args,OptionArgVectorSP & option_arg_vector_sp)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       return false;
515f56fca4SPavel Labath     }
525f56fca4SPavel Labath     args = std::move(*args_or);
534643c012SEnrico Granata     options->VerifyPartialOptions(result);
54b9c1b51eSKate Stone     if (!result.Succeeded() &&
55b9c1b51eSKate Stone         result.GetStatus() != lldb::eReturnStatusStarted) {
564643c012SEnrico Granata       result.AppendError("Unable to create requested alias.\n");
574643c012SEnrico Granata       return false;
584643c012SEnrico Granata     }
594643c012SEnrico Granata   }
604643c012SEnrico Granata 
61b9c1b51eSKate Stone   if (!options_string.empty()) {
624643c012SEnrico Granata     if (cmd_obj_sp->WantsRawCommandString())
635c28c66fSZachary Turner       option_arg_vector->emplace_back("<argument>", -1, options_string);
64b9c1b51eSKate Stone     else {
6597d2c401SZachary Turner       for (auto &entry : args.entries()) {
660d9a201eSRaphael Isemann         if (!entry.ref().empty())
675bbaf543SMartin Storsjö           option_arg_vector->emplace_back(std::string("<argument>"), -1,
685bbaf543SMartin Storsjö                                           std::string(entry.ref()));
6997d2c401SZachary Turner       }
704643c012SEnrico Granata     }
714643c012SEnrico Granata   }
724643c012SEnrico Granata 
734643c012SEnrico Granata   return success;
744643c012SEnrico Granata }
754643c012SEnrico Granata 
CommandAlias(CommandInterpreter & interpreter,lldb::CommandObjectSP cmd_sp,llvm::StringRef options_args,llvm::StringRef name,llvm::StringRef help,llvm::StringRef syntax,uint32_t flags)763e271af4SEnrico Granata CommandAlias::CommandAlias(CommandInterpreter &interpreter,
773e271af4SEnrico Granata                            lldb::CommandObjectSP cmd_sp,
78a449698cSZachary Turner                            llvm::StringRef options_args, llvm::StringRef name,
79a449698cSZachary Turner                            llvm::StringRef help, llvm::StringRef syntax,
80a449698cSZachary Turner                            uint32_t flags)
81b9c1b51eSKate Stone     : CommandObject(interpreter, name, help, syntax, flags),
82*8cdcd41eSTatyana Krasnukha       m_option_string(std::string(options_args)),
83bef55ac8SEnrico Granata       m_option_args_sp(new OptionArgVector),
84b9c1b51eSKate Stone       m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false),
85b9c1b51eSKate Stone       m_did_set_help_long(false) {
86b9c1b51eSKate Stone   if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) {
873e271af4SEnrico Granata     m_underlying_command_sp = cmd_sp;
88bef55ac8SEnrico Granata     for (int i = 0;
89bef55ac8SEnrico Granata          auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i);
90b9c1b51eSKate Stone          i++) {
91bef55ac8SEnrico Granata       m_arguments.push_back(*cmd_entry);
92bef55ac8SEnrico Granata     }
93a449698cSZachary Turner     if (!help.empty()) {
943e271af4SEnrico Granata       StreamString sstr;
953e271af4SEnrico Granata       StreamString translation_and_help;
963e271af4SEnrico Granata       GetAliasExpansion(sstr);
973e271af4SEnrico Granata 
980fe35b15SZachary Turner       translation_and_help.Printf(
990fe35b15SZachary Turner           "(%s)  %s", sstr.GetData(),
1001e8016b2SZachary Turner           GetUnderlyingCommand()->GetHelp().str().c_str());
101c156427dSZachary Turner       SetHelp(translation_and_help.GetString());
1023e271af4SEnrico Granata     }
1033e271af4SEnrico Granata   }
1044643c012SEnrico Granata }
1054643c012SEnrico Granata 
WantsRawCommandString()106b9c1b51eSKate Stone bool CommandAlias::WantsRawCommandString() {
1073e271af4SEnrico Granata   if (IsValid())
1083e271af4SEnrico Granata     return m_underlying_command_sp->WantsRawCommandString();
1093e271af4SEnrico Granata   return false;
1103e271af4SEnrico Granata }
1113e271af4SEnrico Granata 
WantsCompletion()112b9c1b51eSKate Stone bool CommandAlias::WantsCompletion() {
113bef55ac8SEnrico Granata   if (IsValid())
114bef55ac8SEnrico Granata     return m_underlying_command_sp->WantsCompletion();
115bef55ac8SEnrico Granata   return false;
116bef55ac8SEnrico Granata }
117bef55ac8SEnrico Granata 
HandleCompletion(CompletionRequest & request)118ae34ed2cSRaphael Isemann void CommandAlias::HandleCompletion(CompletionRequest &request) {
119bef55ac8SEnrico Granata   if (IsValid())
120ae34ed2cSRaphael Isemann     m_underlying_command_sp->HandleCompletion(request);
121bef55ac8SEnrico Granata }
122bef55ac8SEnrico Granata 
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)123ae34ed2cSRaphael Isemann void CommandAlias::HandleArgumentCompletion(
1242443bbd4SRaphael Isemann     CompletionRequest &request, OptionElementVector &opt_element_vector) {
125bef55ac8SEnrico Granata   if (IsValid())
126ae34ed2cSRaphael Isemann     m_underlying_command_sp->HandleArgumentCompletion(request,
127ae34ed2cSRaphael Isemann                                                       opt_element_vector);
128bef55ac8SEnrico Granata }
129bef55ac8SEnrico Granata 
GetOptions()130b9c1b51eSKate Stone Options *CommandAlias::GetOptions() {
131bef55ac8SEnrico Granata   if (IsValid())
132bef55ac8SEnrico Granata     return m_underlying_command_sp->GetOptions();
133bef55ac8SEnrico Granata   return nullptr;
134bef55ac8SEnrico Granata }
135bef55ac8SEnrico Granata 
Execute(const char * args_string,CommandReturnObject & result)136b9c1b51eSKate Stone bool CommandAlias::Execute(const char *args_string,
137b9c1b51eSKate Stone                            CommandReturnObject &result) {
1383e271af4SEnrico Granata   llvm_unreachable("CommandAlias::Execute is not to be called");
1394643c012SEnrico Granata }
1404643c012SEnrico Granata 
GetAliasExpansion(StreamString & help_string) const141a483f579SZachary Turner void CommandAlias::GetAliasExpansion(StreamString &help_string) const {
142a449698cSZachary Turner   llvm::StringRef command_name = m_underlying_command_sp->GetCommandName();
143a449698cSZachary Turner   help_string.Printf("'%*s", (int)command_name.size(), command_name.data());
1444643c012SEnrico Granata 
1455c28c66fSZachary Turner   if (!m_option_args_sp) {
1465c28c66fSZachary Turner     help_string.Printf("'");
1475c28c66fSZachary Turner     return;
1485c28c66fSZachary Turner   }
1495c28c66fSZachary Turner 
1504643c012SEnrico Granata   OptionArgVector *options = m_option_args_sp.get();
1515c28c66fSZachary Turner   std::string opt;
1525c28c66fSZachary Turner   std::string value;
1535c28c66fSZachary Turner 
1545c28c66fSZachary Turner   for (const auto &opt_entry : *options) {
1555c28c66fSZachary Turner     std::tie(opt, std::ignore, value) = opt_entry;
1565c28c66fSZachary Turner     if (opt == "<argument>") {
1574643c012SEnrico Granata       help_string.Printf(" %s", value.c_str());
158b9c1b51eSKate Stone     } else {
1594643c012SEnrico Granata       help_string.Printf(" %s", opt.c_str());
1608d20cfdfSJonas Devlieghere       if ((value != "<no-argument>") && (value != "<need-argument")) {
1614643c012SEnrico Granata         help_string.Printf(" %s", value.c_str());
1624643c012SEnrico Granata       }
1634643c012SEnrico Granata     }
1644643c012SEnrico Granata   }
1654643c012SEnrico Granata 
1664643c012SEnrico Granata   help_string.Printf("'");
1674643c012SEnrico Granata }
168bef55ac8SEnrico Granata 
IsDashDashCommand()169b9c1b51eSKate Stone bool CommandAlias::IsDashDashCommand() {
1705c28c66fSZachary Turner   if (m_is_dashdash_alias != eLazyBoolCalculate)
1715c28c66fSZachary Turner     return (m_is_dashdash_alias == eLazyBoolYes);
172bef55ac8SEnrico Granata   m_is_dashdash_alias = eLazyBoolNo;
1735c28c66fSZachary Turner   if (!IsValid())
1745c28c66fSZachary Turner     return false;
1755c28c66fSZachary Turner 
1765c28c66fSZachary Turner   std::string opt;
1775c28c66fSZachary Turner   std::string value;
1785c28c66fSZachary Turner 
1795c28c66fSZachary Turner   for (const auto &opt_entry : *GetOptionArguments()) {
1805c28c66fSZachary Turner     std::tie(opt, std::ignore, value) = opt_entry;
1815c28c66fSZachary Turner     if (opt == "<argument>" && !value.empty() &&
1825c28c66fSZachary Turner         llvm::StringRef(value).endswith("--")) {
183bef55ac8SEnrico Granata       m_is_dashdash_alias = eLazyBoolYes;
184bef55ac8SEnrico Granata       break;
185bef55ac8SEnrico Granata     }
186bef55ac8SEnrico Granata   }
1875c28c66fSZachary Turner 
18805097246SAdrian Prantl   // if this is a nested alias, it may be adding arguments on top of an already
18905097246SAdrian Prantl   // dash-dash alias
1903c110dd6SEnrico Granata   if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias())
191b9c1b51eSKate Stone     m_is_dashdash_alias =
192b9c1b51eSKate Stone         (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes
193b9c1b51eSKate Stone                                                      : eLazyBoolNo);
194bef55ac8SEnrico Granata   return (m_is_dashdash_alias == eLazyBoolYes);
195bef55ac8SEnrico Granata }
196bef55ac8SEnrico Granata 
IsNestedAlias()197b9c1b51eSKate Stone bool CommandAlias::IsNestedAlias() {
1983c110dd6SEnrico Granata   if (GetUnderlyingCommand())
1993c110dd6SEnrico Granata     return GetUnderlyingCommand()->IsAlias();
2003c110dd6SEnrico Granata   return false;
2013c110dd6SEnrico Granata }
2023c110dd6SEnrico Granata 
Desugar()203b9c1b51eSKate Stone std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() {
204660764a0SEnrico Granata   auto underlying = GetUnderlyingCommand();
205660764a0SEnrico Granata   if (!underlying)
206660764a0SEnrico Granata     return {nullptr, nullptr};
207660764a0SEnrico Granata 
208b9c1b51eSKate Stone   if (underlying->IsAlias()) {
209660764a0SEnrico Granata     auto desugared = ((CommandAlias *)underlying.get())->Desugar();
210660764a0SEnrico Granata     auto options = GetOptionArguments();
211b9c1b51eSKate Stone     options->insert(options->begin(), desugared.second->begin(),
212b9c1b51eSKate Stone                     desugared.second->end());
213660764a0SEnrico Granata     return {desugared.first, options};
214660764a0SEnrico Granata   }
215660764a0SEnrico Granata 
216660764a0SEnrico Granata   return {underlying, GetOptionArguments()};
217660764a0SEnrico Granata }
218660764a0SEnrico Granata 
219b9c1b51eSKate Stone // allow CommandAlias objects to provide their own help, but fallback to the
22005097246SAdrian Prantl // info for the underlying command if no customization has been provided
SetHelp(llvm::StringRef str)221442f6530SZachary Turner void CommandAlias::SetHelp(llvm::StringRef str) {
222bfb75e9bSEnrico Granata   this->CommandObject::SetHelp(str);
223bfb75e9bSEnrico Granata   m_did_set_help = true;
224bfb75e9bSEnrico Granata }
225bfb75e9bSEnrico Granata 
SetHelpLong(llvm::StringRef str)226442f6530SZachary Turner void CommandAlias::SetHelpLong(llvm::StringRef str) {
227bfb75e9bSEnrico Granata   this->CommandObject::SetHelpLong(str);
228bfb75e9bSEnrico Granata   m_did_set_help_long = true;
229bfb75e9bSEnrico Granata }
230bfb75e9bSEnrico Granata 
GetHelp()231442f6530SZachary Turner llvm::StringRef CommandAlias::GetHelp() {
232bfb75e9bSEnrico Granata   if (!m_cmd_help_short.empty() || m_did_set_help)
233442f6530SZachary Turner     return m_cmd_help_short;
234bef55ac8SEnrico Granata   if (IsValid())
235bef55ac8SEnrico Granata     return m_underlying_command_sp->GetHelp();
236442f6530SZachary Turner   return llvm::StringRef();
237bef55ac8SEnrico Granata }
238bef55ac8SEnrico Granata 
GetHelpLong()239442f6530SZachary Turner llvm::StringRef CommandAlias::GetHelpLong() {
240bfb75e9bSEnrico Granata   if (!m_cmd_help_long.empty() || m_did_set_help_long)
241442f6530SZachary Turner     return m_cmd_help_long;
242bef55ac8SEnrico Granata   if (IsValid())
243bef55ac8SEnrico Granata     return m_underlying_command_sp->GetHelpLong();
244442f6530SZachary Turner   return llvm::StringRef();
245bef55ac8SEnrico Granata }
246