aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.cpp
new file mode 100644
index 000000000000..695f3d7931cd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -0,0 +1,227 @@
+//===-- CommandObjectDWIMPrint.cpp ------------------------------*- C++ -*-===//
+//
+// 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 "CommandObjectDWIMPrint.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/DumpValueObjectOptions.h"
+#include "lldb/Expression/ExpressionVariable.h"
+#include "lldb/Expression/UserExpression.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#include <regex>
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectDWIMPrint::CommandObjectDWIMPrint(CommandInterpreter &interpreter)
+ : CommandObjectRaw(interpreter, "dwim-print",
+ "Print a variable or expression.",
+ "dwim-print [<variable-name> | <expression>]",
+ eCommandProcessMustBePaused | eCommandTryTargetAPILock) {
+
+ CommandArgumentData var_name_arg(eArgTypeVarName, eArgRepeatPlain);
+ m_arguments.push_back({var_name_arg});
+
+ m_option_group.Append(&m_format_options,
+ OptionGroupFormat::OPTION_GROUP_FORMAT |
+ OptionGroupFormat::OPTION_GROUP_GDB_FMT,
+ LLDB_OPT_SET_1);
+ StringRef exclude_expr_options[] = {"debug", "top-level"};
+ m_option_group.Append(&m_expr_options, exclude_expr_options);
+ m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+}
+
+Options *CommandObjectDWIMPrint::GetOptions() { return &m_option_group; }
+
+void CommandObjectDWIMPrint::HandleArgumentCompletion(
+ CompletionRequest &request, OptionElementVector &opt_element_vector) {
+ lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), lldb::eVariablePathCompletion, request, nullptr);
+}
+
+void CommandObjectDWIMPrint::DoExecute(StringRef command,
+ CommandReturnObject &result) {
+ m_option_group.NotifyOptionParsingStarting(&m_exe_ctx);
+ OptionsWithRaw args{command};
+ StringRef expr = args.GetRawPart();
+
+ if (expr.empty()) {
+ result.AppendErrorWithFormatv("'{0}' takes a variable or expression",
+ m_cmd_name);
+ return;
+ }
+
+ if (args.HasArgs()) {
+ if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
+ m_exe_ctx))
+ return;
+ }
+
+ // If the user has not specified, default to disabling persistent results.
+ if (m_expr_options.suppress_persistent_result == eLazyBoolCalculate)
+ m_expr_options.suppress_persistent_result = eLazyBoolYes;
+ bool suppress_result = m_expr_options.ShouldSuppressResult(m_varobj_options);
+
+ auto verbosity = GetDebugger().GetDWIMPrintVerbosity();
+
+ Target *target_ptr = m_exe_ctx.GetTargetPtr();
+ // Fallback to the dummy target, which can allow for expression evaluation.
+ Target &target = target_ptr ? *target_ptr : GetDummyTarget();
+
+ EvaluateExpressionOptions eval_options =
+ m_expr_options.GetEvaluateExpressionOptions(target, m_varobj_options);
+ // This command manually removes the result variable, make sure expression
+ // evaluation doesn't do it first.
+ eval_options.SetSuppressPersistentResult(false);
+
+ DumpValueObjectOptions dump_options = m_varobj_options.GetAsDumpOptions(
+ m_expr_options.m_verbosity, m_format_options.GetFormat());
+ dump_options.SetHideRootName(suppress_result);
+
+ bool is_po = m_varobj_options.use_objc;
+
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+
+ // Either Swift was explicitly specified, or the frame is Swift.
+ lldb::LanguageType language = m_expr_options.language;
+ if (language == lldb::eLanguageTypeUnknown && frame)
+ language = frame->GuessLanguage();
+
+ // Add a hint if object description was requested, but no description
+ // function was implemented.
+ auto maybe_add_hint = [&](llvm::StringRef output) {
+ // Identify the default output of object description for Swift and
+ // Objective-C
+ // "<Name: 0x...>. The regex is:
+ // - Start with "<".
+ // - Followed by 1 or more non-whitespace characters.
+ // - Followed by ": 0x".
+ // - Followed by 5 or more hex digits.
+ // - Followed by ">".
+ // - End with zero or more whitespace characters.
+ const std::regex swift_class_regex("^<\\S+: 0x[[:xdigit:]]{5,}>\\s*$");
+
+ if (GetDebugger().GetShowDontUsePoHint() && target_ptr &&
+ (language == lldb::eLanguageTypeSwift ||
+ language == lldb::eLanguageTypeObjC) &&
+ std::regex_match(output.data(), swift_class_regex)) {
+
+ static bool note_shown = false;
+ if (note_shown)
+ return;
+
+ result.GetOutputStream()
+ << "note: object description requested, but type doesn't implement "
+ "a custom object description. Consider using \"p\" instead of "
+ "\"po\" (this note will only be shown once per debug session).\n";
+ note_shown = true;
+ }
+ };
+
+ // First, try `expr` as the name of a frame variable.
+ if (frame) {
+ auto valobj_sp = frame->FindVariable(ConstString(expr));
+ if (valobj_sp && valobj_sp->GetError().Success()) {
+ if (!suppress_result) {
+ if (auto persisted_valobj = valobj_sp->Persist())
+ valobj_sp = persisted_valobj;
+ }
+
+ if (verbosity == eDWIMPrintVerbosityFull) {
+ StringRef flags;
+ if (args.HasArgs())
+ flags = args.GetArgString();
+ result.AppendMessageWithFormatv("note: ran `frame variable {0}{1}`",
+ flags, expr);
+ }
+
+ if (is_po) {
+ StreamString temp_result_stream;
+ valobj_sp->Dump(temp_result_stream, dump_options);
+ llvm::StringRef output = temp_result_stream.GetString();
+ maybe_add_hint(output);
+ result.GetOutputStream() << output;
+ } else {
+ valobj_sp->Dump(result.GetOutputStream(), dump_options);
+ }
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return;
+ }
+ }
+
+ // Second, also lastly, try `expr` as a source expression to evaluate.
+ {
+ auto *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
+ ValueObjectSP valobj_sp;
+ std::string fixed_expression;
+
+ ExpressionResults expr_result = target.EvaluateExpression(
+ expr, exe_scope, valobj_sp, eval_options, &fixed_expression);
+
+ // Only mention Fix-Its if the expression evaluator applied them.
+ // Compiler errors refer to the final expression after applying Fix-It(s).
+ if (!fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
+ Stream &error_stream = result.GetErrorStream();
+ error_stream << " Evaluated this expression after applying Fix-It(s):\n";
+ error_stream << " " << fixed_expression << "\n";
+ }
+
+ if (expr_result == eExpressionCompleted) {
+ if (verbosity != eDWIMPrintVerbosityNone) {
+ StringRef flags;
+ if (args.HasArgs())
+ flags = args.GetArgStringWithDelimiter();
+ result.AppendMessageWithFormatv("note: ran `expression {0}{1}`", flags,
+ expr);
+ }
+
+ if (valobj_sp->GetError().GetError() != UserExpression::kNoResult) {
+ if (is_po) {
+ StreamString temp_result_stream;
+ valobj_sp->Dump(temp_result_stream, dump_options);
+ llvm::StringRef output = temp_result_stream.GetString();
+ maybe_add_hint(output);
+ result.GetOutputStream() << output;
+ } else {
+ valobj_sp->Dump(result.GetOutputStream(), dump_options);
+ }
+ }
+
+ if (suppress_result)
+ if (auto result_var_sp =
+ target.GetPersistentVariable(valobj_sp->GetName())) {
+ auto language = valobj_sp->GetPreferredDisplayLanguage();
+ if (auto *persistent_state =
+ target.GetPersistentExpressionStateForLanguage(language))
+ persistent_state->RemovePersistentVariable(result_var_sp);
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ if (valobj_sp)
+ result.SetError(valobj_sp->GetError());
+ else
+ result.AppendErrorWithFormatv(
+ "unknown error evaluating expression `{0}`", expr);
+ }
+ }
+}