]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/lldb/source/Interpreter/CommandAlias.cpp
Fix a memory leak in if_delgroups() introduced in r334118.
[FreeBSD/FreeBSD.git] / contrib / llvm-project / lldb / source / Interpreter / CommandAlias.cpp
1 //===-- CommandAlias.cpp -----------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "lldb/Interpreter/CommandAlias.h"
10
11 #include "llvm/Support/ErrorHandling.h"
12
13 #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"
18
19 using namespace lldb;
20 using namespace lldb_private;
21
22 static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp,
23                                     llvm::StringRef options_args,
24                                     OptionArgVectorSP &option_arg_vector_sp) {
25   bool success = true;
26   OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
27
28   if (options_args.size() < 1)
29     return true;
30
31   Args args(options_args);
32   std::string options_string(options_args);
33   // TODO: Find a way to propagate errors in this CommandReturnObject up the
34   // stack.
35   CommandReturnObject result;
36   // Check to see if the command being aliased can take any command options.
37   Options *options = cmd_obj_sp->GetOptions();
38   if (options) {
39     // See if any options were specified as part of the alias;  if so, handle
40     // them appropriately.
41     ExecutionContext exe_ctx =
42         cmd_obj_sp->GetCommandInterpreter().GetExecutionContext();
43     options->NotifyOptionParsingStarting(&exe_ctx);
44
45     llvm::Expected<Args> args_or =
46         options->ParseAlias(args, option_arg_vector, options_string);
47     if (!args_or) {
48       result.AppendError(toString(args_or.takeError()));
49       result.AppendError("Unable to create requested alias.\n");
50       result.SetStatus(eReturnStatusFailed);
51       return false;
52     }
53     args = std::move(*args_or);
54     options->VerifyPartialOptions(result);
55     if (!result.Succeeded() &&
56         result.GetStatus() != lldb::eReturnStatusStarted) {
57       result.AppendError("Unable to create requested alias.\n");
58       return false;
59     }
60   }
61
62   if (!options_string.empty()) {
63     if (cmd_obj_sp->WantsRawCommandString())
64       option_arg_vector->emplace_back("<argument>", -1, options_string);
65     else {
66       for (auto &entry : args.entries()) {
67         if (!entry.ref.empty())
68           option_arg_vector->emplace_back("<argument>", -1, entry.ref);
69       }
70     }
71   }
72
73   return success;
74 }
75
76 CommandAlias::CommandAlias(CommandInterpreter &interpreter,
77                            lldb::CommandObjectSP cmd_sp,
78                            llvm::StringRef options_args, llvm::StringRef name,
79                            llvm::StringRef help, llvm::StringRef syntax,
80                            uint32_t flags)
81     : CommandObject(interpreter, name, help, syntax, flags),
82       m_underlying_command_sp(), m_option_string(options_args),
83       m_option_args_sp(new OptionArgVector),
84       m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false),
85       m_did_set_help_long(false) {
86   if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) {
87     m_underlying_command_sp = cmd_sp;
88     for (int i = 0;
89          auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i);
90          i++) {
91       m_arguments.push_back(*cmd_entry);
92     }
93     if (!help.empty()) {
94       StreamString sstr;
95       StreamString translation_and_help;
96       GetAliasExpansion(sstr);
97
98       translation_and_help.Printf(
99           "(%s)  %s", sstr.GetData(),
100           GetUnderlyingCommand()->GetHelp().str().c_str());
101       SetHelp(translation_and_help.GetString());
102     }
103   }
104 }
105
106 bool CommandAlias::WantsRawCommandString() {
107   if (IsValid())
108     return m_underlying_command_sp->WantsRawCommandString();
109   return false;
110 }
111
112 bool CommandAlias::WantsCompletion() {
113   if (IsValid())
114     return m_underlying_command_sp->WantsCompletion();
115   return false;
116 }
117
118 int CommandAlias::HandleCompletion(CompletionRequest &request) {
119   if (IsValid())
120     return m_underlying_command_sp->HandleCompletion(request);
121   return -1;
122 }
123
124 int CommandAlias::HandleArgumentCompletion(
125     CompletionRequest &request, OptionElementVector &opt_element_vector) {
126   if (IsValid())
127     return m_underlying_command_sp->HandleArgumentCompletion(
128         request, opt_element_vector);
129   return -1;
130 }
131
132 Options *CommandAlias::GetOptions() {
133   if (IsValid())
134     return m_underlying_command_sp->GetOptions();
135   return nullptr;
136 }
137
138 bool CommandAlias::Execute(const char *args_string,
139                            CommandReturnObject &result) {
140   llvm_unreachable("CommandAlias::Execute is not to be called");
141 }
142
143 void CommandAlias::GetAliasExpansion(StreamString &help_string) const {
144   llvm::StringRef command_name = m_underlying_command_sp->GetCommandName();
145   help_string.Printf("'%*s", (int)command_name.size(), command_name.data());
146
147   if (!m_option_args_sp) {
148     help_string.Printf("'");
149     return;
150   }
151
152   OptionArgVector *options = m_option_args_sp.get();
153   std::string opt;
154   std::string value;
155
156   for (const auto &opt_entry : *options) {
157     std::tie(opt, std::ignore, value) = opt_entry;
158     if (opt == "<argument>") {
159       help_string.Printf(" %s", value.c_str());
160     } else {
161       help_string.Printf(" %s", opt.c_str());
162       if ((value != "<no-argument>") && (value != "<need-argument")) {
163         help_string.Printf(" %s", value.c_str());
164       }
165     }
166   }
167
168   help_string.Printf("'");
169 }
170
171 bool CommandAlias::IsDashDashCommand() {
172   if (m_is_dashdash_alias != eLazyBoolCalculate)
173     return (m_is_dashdash_alias == eLazyBoolYes);
174   m_is_dashdash_alias = eLazyBoolNo;
175   if (!IsValid())
176     return false;
177
178   std::string opt;
179   std::string value;
180
181   for (const auto &opt_entry : *GetOptionArguments()) {
182     std::tie(opt, std::ignore, value) = opt_entry;
183     if (opt == "<argument>" && !value.empty() &&
184         llvm::StringRef(value).endswith("--")) {
185       m_is_dashdash_alias = eLazyBoolYes;
186       break;
187     }
188   }
189
190   // if this is a nested alias, it may be adding arguments on top of an already
191   // dash-dash alias
192   if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias())
193     m_is_dashdash_alias =
194         (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes
195                                                      : eLazyBoolNo);
196   return (m_is_dashdash_alias == eLazyBoolYes);
197 }
198
199 bool CommandAlias::IsNestedAlias() {
200   if (GetUnderlyingCommand())
201     return GetUnderlyingCommand()->IsAlias();
202   return false;
203 }
204
205 std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() {
206   auto underlying = GetUnderlyingCommand();
207   if (!underlying)
208     return {nullptr, nullptr};
209
210   if (underlying->IsAlias()) {
211     auto desugared = ((CommandAlias *)underlying.get())->Desugar();
212     auto options = GetOptionArguments();
213     options->insert(options->begin(), desugared.second->begin(),
214                     desugared.second->end());
215     return {desugared.first, options};
216   }
217
218   return {underlying, GetOptionArguments()};
219 }
220
221 // allow CommandAlias objects to provide their own help, but fallback to the
222 // info for the underlying command if no customization has been provided
223 void CommandAlias::SetHelp(llvm::StringRef str) {
224   this->CommandObject::SetHelp(str);
225   m_did_set_help = true;
226 }
227
228 void CommandAlias::SetHelpLong(llvm::StringRef str) {
229   this->CommandObject::SetHelpLong(str);
230   m_did_set_help_long = true;
231 }
232
233 llvm::StringRef CommandAlias::GetHelp() {
234   if (!m_cmd_help_short.empty() || m_did_set_help)
235     return m_cmd_help_short;
236   if (IsValid())
237     return m_underlying_command_sp->GetHelp();
238   return llvm::StringRef();
239 }
240
241 llvm::StringRef CommandAlias::GetHelpLong() {
242   if (!m_cmd_help_long.empty() || m_did_set_help_long)
243     return m_cmd_help_long;
244   if (IsValid())
245     return m_underlying_command_sp->GetHelpLong();
246   return llvm::StringRef();
247 }