246 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			246 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- CommandAlias.cpp --------------------------------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "lldb/Interpreter/CommandAlias.h"
 | 
						|
 | 
						|
#include "llvm/Support/ErrorHandling.h"
 | 
						|
 | 
						|
#include "lldb/Interpreter/CommandInterpreter.h"
 | 
						|
#include "lldb/Interpreter/CommandObject.h"
 | 
						|
#include "lldb/Interpreter/CommandReturnObject.h"
 | 
						|
#include "lldb/Interpreter/Options.h"
 | 
						|
#include "lldb/Utility/StreamString.h"
 | 
						|
 | 
						|
using namespace lldb;
 | 
						|
using namespace lldb_private;
 | 
						|
 | 
						|
static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp,
 | 
						|
                                    llvm::StringRef options_args,
 | 
						|
                                    OptionArgVectorSP &option_arg_vector_sp) {
 | 
						|
  bool success = true;
 | 
						|
  OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
 | 
						|
 | 
						|
  if (options_args.size() < 1)
 | 
						|
    return true;
 | 
						|
 | 
						|
  Args args(options_args);
 | 
						|
  std::string options_string(options_args);
 | 
						|
  // TODO: Find a way to propagate errors in this CommandReturnObject up the
 | 
						|
  // stack.
 | 
						|
  CommandReturnObject result(false);
 | 
						|
  // Check to see if the command being aliased can take any command options.
 | 
						|
  Options *options = cmd_obj_sp->GetOptions();
 | 
						|
  if (options) {
 | 
						|
    // See if any options were specified as part of the alias;  if so, handle
 | 
						|
    // them appropriately.
 | 
						|
    ExecutionContext exe_ctx =
 | 
						|
        cmd_obj_sp->GetCommandInterpreter().GetExecutionContext();
 | 
						|
    options->NotifyOptionParsingStarting(&exe_ctx);
 | 
						|
 | 
						|
    llvm::Expected<Args> args_or =
 | 
						|
        options->ParseAlias(args, option_arg_vector, options_string);
 | 
						|
    if (!args_or) {
 | 
						|
      result.AppendError(toString(args_or.takeError()));
 | 
						|
      result.AppendError("Unable to create requested alias.\n");
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    args = std::move(*args_or);
 | 
						|
    options->VerifyPartialOptions(result);
 | 
						|
    if (!result.Succeeded() &&
 | 
						|
        result.GetStatus() != lldb::eReturnStatusStarted) {
 | 
						|
      result.AppendError("Unable to create requested alias.\n");
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!options_string.empty()) {
 | 
						|
    if (cmd_obj_sp->WantsRawCommandString())
 | 
						|
      option_arg_vector->emplace_back("<argument>", -1, options_string);
 | 
						|
    else {
 | 
						|
      for (auto &entry : args.entries()) {
 | 
						|
        if (!entry.ref().empty())
 | 
						|
          option_arg_vector->emplace_back(std::string("<argument>"), -1,
 | 
						|
                                          std::string(entry.ref()));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return success;
 | 
						|
}
 | 
						|
 | 
						|
CommandAlias::CommandAlias(CommandInterpreter &interpreter,
 | 
						|
                           lldb::CommandObjectSP cmd_sp,
 | 
						|
                           llvm::StringRef options_args, llvm::StringRef name,
 | 
						|
                           llvm::StringRef help, llvm::StringRef syntax,
 | 
						|
                           uint32_t flags)
 | 
						|
    : CommandObject(interpreter, name, help, syntax, flags),
 | 
						|
      m_option_string(std::string(options_args)),
 | 
						|
      m_option_args_sp(new OptionArgVector),
 | 
						|
      m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false),
 | 
						|
      m_did_set_help_long(false) {
 | 
						|
  if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) {
 | 
						|
    m_underlying_command_sp = cmd_sp;
 | 
						|
    for (int i = 0;
 | 
						|
         auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i);
 | 
						|
         i++) {
 | 
						|
      m_arguments.push_back(*cmd_entry);
 | 
						|
    }
 | 
						|
    if (!help.empty()) {
 | 
						|
      StreamString sstr;
 | 
						|
      StreamString translation_and_help;
 | 
						|
      GetAliasExpansion(sstr);
 | 
						|
 | 
						|
      translation_and_help.Printf(
 | 
						|
          "(%s)  %s", sstr.GetData(),
 | 
						|
          GetUnderlyingCommand()->GetHelp().str().c_str());
 | 
						|
      SetHelp(translation_and_help.GetString());
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool CommandAlias::WantsRawCommandString() {
 | 
						|
  if (IsValid())
 | 
						|
    return m_underlying_command_sp->WantsRawCommandString();
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool CommandAlias::WantsCompletion() {
 | 
						|
  if (IsValid())
 | 
						|
    return m_underlying_command_sp->WantsCompletion();
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void CommandAlias::HandleCompletion(CompletionRequest &request) {
 | 
						|
  if (IsValid())
 | 
						|
    m_underlying_command_sp->HandleCompletion(request);
 | 
						|
}
 | 
						|
 | 
						|
void CommandAlias::HandleArgumentCompletion(
 | 
						|
    CompletionRequest &request, OptionElementVector &opt_element_vector) {
 | 
						|
  if (IsValid())
 | 
						|
    m_underlying_command_sp->HandleArgumentCompletion(request,
 | 
						|
                                                      opt_element_vector);
 | 
						|
}
 | 
						|
 | 
						|
Options *CommandAlias::GetOptions() {
 | 
						|
  if (IsValid())
 | 
						|
    return m_underlying_command_sp->GetOptions();
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
bool CommandAlias::Execute(const char *args_string,
 | 
						|
                           CommandReturnObject &result) {
 | 
						|
  llvm_unreachable("CommandAlias::Execute is not to be called");
 | 
						|
}
 | 
						|
 | 
						|
void CommandAlias::GetAliasExpansion(StreamString &help_string) const {
 | 
						|
  llvm::StringRef command_name = m_underlying_command_sp->GetCommandName();
 | 
						|
  help_string.Printf("'%*s", (int)command_name.size(), command_name.data());
 | 
						|
 | 
						|
  if (!m_option_args_sp) {
 | 
						|
    help_string.Printf("'");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  OptionArgVector *options = m_option_args_sp.get();
 | 
						|
  std::string opt;
 | 
						|
  std::string value;
 | 
						|
 | 
						|
  for (const auto &opt_entry : *options) {
 | 
						|
    std::tie(opt, std::ignore, value) = opt_entry;
 | 
						|
    if (opt == "<argument>") {
 | 
						|
      help_string.Printf(" %s", value.c_str());
 | 
						|
    } else {
 | 
						|
      help_string.Printf(" %s", opt.c_str());
 | 
						|
      if ((value != "<no-argument>") && (value != "<need-argument")) {
 | 
						|
        help_string.Printf(" %s", value.c_str());
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  help_string.Printf("'");
 | 
						|
}
 | 
						|
 | 
						|
bool CommandAlias::IsDashDashCommand() {
 | 
						|
  if (m_is_dashdash_alias != eLazyBoolCalculate)
 | 
						|
    return (m_is_dashdash_alias == eLazyBoolYes);
 | 
						|
  m_is_dashdash_alias = eLazyBoolNo;
 | 
						|
  if (!IsValid())
 | 
						|
    return false;
 | 
						|
 | 
						|
  std::string opt;
 | 
						|
  std::string value;
 | 
						|
 | 
						|
  for (const auto &opt_entry : *GetOptionArguments()) {
 | 
						|
    std::tie(opt, std::ignore, value) = opt_entry;
 | 
						|
    if (opt == "<argument>" && !value.empty() &&
 | 
						|
        llvm::StringRef(value).endswith("--")) {
 | 
						|
      m_is_dashdash_alias = eLazyBoolYes;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // if this is a nested alias, it may be adding arguments on top of an already
 | 
						|
  // dash-dash alias
 | 
						|
  if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias())
 | 
						|
    m_is_dashdash_alias =
 | 
						|
        (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes
 | 
						|
                                                     : eLazyBoolNo);
 | 
						|
  return (m_is_dashdash_alias == eLazyBoolYes);
 | 
						|
}
 | 
						|
 | 
						|
bool CommandAlias::IsNestedAlias() {
 | 
						|
  if (GetUnderlyingCommand())
 | 
						|
    return GetUnderlyingCommand()->IsAlias();
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() {
 | 
						|
  auto underlying = GetUnderlyingCommand();
 | 
						|
  if (!underlying)
 | 
						|
    return {nullptr, nullptr};
 | 
						|
 | 
						|
  if (underlying->IsAlias()) {
 | 
						|
    auto desugared = ((CommandAlias *)underlying.get())->Desugar();
 | 
						|
    auto options = GetOptionArguments();
 | 
						|
    options->insert(options->begin(), desugared.second->begin(),
 | 
						|
                    desugared.second->end());
 | 
						|
    return {desugared.first, options};
 | 
						|
  }
 | 
						|
 | 
						|
  return {underlying, GetOptionArguments()};
 | 
						|
}
 | 
						|
 | 
						|
// allow CommandAlias objects to provide their own help, but fallback to the
 | 
						|
// info for the underlying command if no customization has been provided
 | 
						|
void CommandAlias::SetHelp(llvm::StringRef str) {
 | 
						|
  this->CommandObject::SetHelp(str);
 | 
						|
  m_did_set_help = true;
 | 
						|
}
 | 
						|
 | 
						|
void CommandAlias::SetHelpLong(llvm::StringRef str) {
 | 
						|
  this->CommandObject::SetHelpLong(str);
 | 
						|
  m_did_set_help_long = true;
 | 
						|
}
 | 
						|
 | 
						|
llvm::StringRef CommandAlias::GetHelp() {
 | 
						|
  if (!m_cmd_help_short.empty() || m_did_set_help)
 | 
						|
    return m_cmd_help_short;
 | 
						|
  if (IsValid())
 | 
						|
    return m_underlying_command_sp->GetHelp();
 | 
						|
  return llvm::StringRef();
 | 
						|
}
 | 
						|
 | 
						|
llvm::StringRef CommandAlias::GetHelpLong() {
 | 
						|
  if (!m_cmd_help_long.empty() || m_did_set_help_long)
 | 
						|
    return m_cmd_help_long;
 | 
						|
  if (IsValid())
 | 
						|
    return m_underlying_command_sp->GetHelpLong();
 | 
						|
  return llvm::StringRef();
 | 
						|
}
 |