brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.9 KiB · 40f00c9 Raw
267 lines · cpp
1//===-- CommandObjectDWIMPrint.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "CommandObjectDWIMPrint.h"10 11#include "lldb/DataFormatters/DumpValueObjectOptions.h"12#include "lldb/Expression/ExpressionVariable.h"13#include "lldb/Expression/UserExpression.h"14#include "lldb/Interpreter/CommandInterpreter.h"15#include "lldb/Interpreter/CommandObject.h"16#include "lldb/Interpreter/CommandReturnObject.h"17#include "lldb/Interpreter/OptionGroupFormat.h"18#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"19#include "lldb/Target/StackFrame.h"20#include "lldb/Utility/ConstString.h"21#include "lldb/ValueObject/ValueObject.h"22#include "lldb/lldb-defines.h"23#include "lldb/lldb-enumerations.h"24#include "lldb/lldb-forward.h"25#include "llvm/ADT/StringRef.h"26 27#include <regex>28 29using namespace llvm;30using namespace lldb;31using namespace lldb_private;32 33CommandObjectDWIMPrint::CommandObjectDWIMPrint(CommandInterpreter &interpreter)34    : CommandObjectRaw(interpreter, "dwim-print",35                       "Print a variable or expression.",36                       "dwim-print [<variable-name> | <expression>]",37                       eCommandProcessMustBePaused | eCommandTryTargetAPILock) {38 39  AddSimpleArgumentList(eArgTypeVarName);40 41  m_option_group.Append(&m_format_options,42                        OptionGroupFormat::OPTION_GROUP_FORMAT |43                            OptionGroupFormat::OPTION_GROUP_GDB_FMT,44                        LLDB_OPT_SET_1);45  StringRef exclude_expr_options[] = {"debug", "top-level"};46  m_option_group.Append(&m_expr_options, exclude_expr_options);47  m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);48  m_option_group.Finalize();49}50 51Options *CommandObjectDWIMPrint::GetOptions() { return &m_option_group; }52 53void CommandObjectDWIMPrint::DoExecute(StringRef command,54                                       CommandReturnObject &result) {55  m_option_group.NotifyOptionParsingStarting(&m_exe_ctx);56  OptionsWithRaw args{command};57  StringRef expr = args.GetRawPart();58 59  if (expr.empty()) {60    result.AppendErrorWithFormatv("'{0}' takes a variable or expression",61                                  m_cmd_name);62    return;63  }64 65  if (args.HasArgs()) {66    if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,67                               m_exe_ctx))68      return;69  }70 71  // If the user has not specified, default to disabling persistent results.72  if (m_expr_options.suppress_persistent_result == eLazyBoolCalculate)73    m_expr_options.suppress_persistent_result = eLazyBoolYes;74  bool suppress_result = m_expr_options.ShouldSuppressResult(m_varobj_options);75 76  auto verbosity = GetDebugger().GetDWIMPrintVerbosity();77 78  Target *target_ptr = m_exe_ctx.GetTargetPtr();79  // Fallback to the dummy target, which can allow for expression evaluation.80  Target &target = target_ptr ? *target_ptr : GetDummyTarget();81 82  EvaluateExpressionOptions eval_options =83      m_expr_options.GetEvaluateExpressionOptions(target, m_varobj_options);84  // This command manually removes the result variable, make sure expression85  // evaluation doesn't do it first.86  eval_options.SetSuppressPersistentResult(false);87 88  DumpValueObjectOptions dump_options = m_varobj_options.GetAsDumpOptions(89      m_expr_options.m_verbosity, m_format_options.GetFormat());90  dump_options.SetHideRootName(suppress_result)91      .SetExpandPointerTypeFlags(lldb::eTypeIsObjC);92 93  bool is_po = m_varobj_options.use_object_desc;94 95  StackFrame *frame = m_exe_ctx.GetFramePtr();96 97  // Either the language was explicitly specified, or we check the frame.98  SourceLanguage language{m_expr_options.language};99  if (!language && frame)100    language = frame->GuessLanguage();101 102  // Add a hint if object description was requested, but no description103  // function was implemented.104  auto maybe_add_hint = [&](llvm::StringRef output) {105    static bool note_shown = false;106    if (note_shown)107      return;108 109    // Identify the default output of object description for Swift and110    // Objective-C111    // "<Name: 0x...>. The regex is:112    // - Start with "<".113    // - Followed by 1 or more non-whitespace characters.114    // - Followed by ": 0x".115    // - Followed by 5 or more hex digits.116    // - Followed by ">".117    // - End with zero or more whitespace characters.118    static const std::regex swift_class_regex(119        "^<\\S+: 0x[[:xdigit:]]{5,}>\\s*$");120 121    if (GetDebugger().GetShowDontUsePoHint() && target_ptr &&122        (language.AsLanguageType() == lldb::eLanguageTypeSwift ||123         language.IsObjC()) &&124        std::regex_match(output.data(), swift_class_regex)) {125 126      result.AppendNote(127          "object description requested, but type doesn't implement "128          "a custom object description. Consider using \"p\" instead of "129          "\"po\" (this note will only be shown once per debug session).\n");130      note_shown = true;131    }132  };133 134  // Dump `valobj` according to whether `po` was requested or not.135  auto dump_val_object = [&](ValueObject &valobj) {136    if (is_po) {137      StreamString temp_result_stream;138      if (llvm::Error error = valobj.Dump(temp_result_stream, dump_options)) {139        result.AppendError(toString(std::move(error)));140        return;141      }142      llvm::StringRef output = temp_result_stream.GetString();143      maybe_add_hint(output);144      result.GetOutputStream() << output;145    } else {146      llvm::Error error =147        valobj.Dump(result.GetOutputStream(), dump_options);148      if (error) {149        result.AppendError(toString(std::move(error)));150        return;151      }152    }153    m_interpreter.PrintWarningsIfNecessary(result.GetOutputStream(),154                                           m_cmd_name);155    result.SetStatus(eReturnStatusSuccessFinishResult);156  };157 158  // First, try `expr` as a _limited_ frame variable expression path: only the159  // dot operator (`.`) is permitted for this case.160  //161  // This is limited to support only unambiguous expression paths. Of note,162  // expression paths are not attempted if the expression contain either the163  // arrow operator (`->`) or the subscript operator (`[]`). This is because164  // both operators can be overloaded in C++, and could result in ambiguity in165  // how the expression is handled. Additionally, `*` and `&` are not supported.166  const bool try_variable_path =167      expr.find_first_of("*&->[]") == StringRef::npos;168  if (frame && try_variable_path) {169    VariableSP var_sp;170    Status status;171    auto valobj_sp = frame->GetValueForVariableExpressionPath(172        expr, eval_options.GetUseDynamic(),173        StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, var_sp,174        status);175    if (valobj_sp && status.Success() && valobj_sp->GetError().Success()) {176      if (!suppress_result) {177        if (auto persisted_valobj = valobj_sp->Persist())178          valobj_sp = persisted_valobj;179      }180 181      if (verbosity == eDWIMPrintVerbosityFull) {182        StringRef flags;183        if (args.HasArgs())184          flags = args.GetArgString();185        result.AppendNoteWithFormatv("ran `frame variable {0}{1}`", flags,186                                     expr);187      }188 189      dump_val_object(*valobj_sp);190      return;191    }192  }193 194  // Second, try `expr` as a persistent variable.195  if (expr.starts_with("$"))196    if (auto *state = target.GetPersistentExpressionStateForLanguage(197            language.AsLanguageType()))198      if (auto var_sp = state->GetVariable(expr))199        if (auto valobj_sp = var_sp->GetValueObject()) {200          dump_val_object(*valobj_sp);201          return;202        }203 204  // Third, and lastly, try `expr` as a source expression to evaluate.205  {206    auto *exe_scope = m_exe_ctx.GetBestExecutionContextScope();207    ValueObjectSP valobj_sp;208    std::string fixed_expression;209 210    ExpressionResults expr_result = target.EvaluateExpression(211        expr, exe_scope, valobj_sp, eval_options, &fixed_expression);212 213    if (valobj_sp)214      result.GetValueObjectList().Append(valobj_sp);215 216    // Record the position of the expression in the command.217    std::optional<uint16_t> indent;218    if (fixed_expression.empty()) {219      size_t pos = m_original_command.rfind(expr);220      if (pos != llvm::StringRef::npos)221        indent = pos;222    }223    // Previously the indent was set up for diagnosing command line224    // parsing errors. Now point it to the expression.225    result.SetDiagnosticIndent(indent);226 227    // Only mention Fix-Its if the expression evaluator applied them.228    // Compiler errors refer to the final expression after applying Fix-It(s).229    if (!fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {230      Stream &error_stream = result.GetErrorStream();231      error_stream << "  Evaluated this expression after applying Fix-It(s):\n";232      error_stream << "    " << fixed_expression << "\n";233    }234 235    // If the expression failed, return an error.236    if (expr_result != eExpressionCompleted) {237      if (valobj_sp)238        result.SetError(valobj_sp->GetError().Clone());239      else240        result.AppendErrorWithFormatv(241            "unknown error evaluating expression `{0}`", expr);242      return;243    }244 245    if (verbosity != eDWIMPrintVerbosityNone) {246      StringRef flags;247      if (args.HasArgs())248        flags = args.GetArgStringWithDelimiter();249      result.AppendNoteWithFormatv("ran `expression {0}{1}`", flags, expr);250    }251 252    if (valobj_sp->GetError().GetError() != UserExpression::kNoResult)253      dump_val_object(*valobj_sp);254    else255      result.SetStatus(eReturnStatusSuccessFinishNoResult);256 257    if (suppress_result)258      if (auto result_var_sp =259              target.GetPersistentVariable(valobj_sp->GetName())) {260        auto language = valobj_sp->GetPreferredDisplayLanguage();261        if (auto *persistent_state =262                target.GetPersistentExpressionStateForLanguage(language))263          persistent_state->RemovePersistentVariable(result_var_sp);264      }265  }266}267