aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Commands/CommandObjectDWIMPrint.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Commands/CommandObjectDWIMPrint.cpp')
-rw-r--r--lldb/source/Commands/CommandObjectDWIMPrint.cpp88
1 files changed, 77 insertions, 11 deletions
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index b2b7f201a5ad..695f3d7931cd 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -25,6 +25,8 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FormatVariadic.h"
+#include <regex>
+
using namespace llvm;
using namespace lldb;
using namespace lldb_private;
@@ -56,7 +58,7 @@ void CommandObjectDWIMPrint::HandleArgumentCompletion(
GetCommandInterpreter(), lldb::eVariablePathCompletion, request, nullptr);
}
-bool CommandObjectDWIMPrint::DoExecute(StringRef command,
+void CommandObjectDWIMPrint::DoExecute(StringRef command,
CommandReturnObject &result) {
m_option_group.NotifyOptionParsingStarting(&m_exe_ctx);
OptionsWithRaw args{command};
@@ -65,13 +67,13 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
if (expr.empty()) {
result.AppendErrorWithFormatv("'{0}' takes a variable or expression",
m_cmd_name);
- return false;
+ return;
}
if (args.HasArgs()) {
if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
m_exe_ctx))
- return false;
+ return;
}
// If the user has not specified, default to disabling persistent results.
@@ -95,8 +97,46 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
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));
@@ -114,9 +154,17 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
flags, expr);
}
- valobj_sp->Dump(result.GetOutputStream(), dump_options);
+ 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 true;
+ return;
}
}
@@ -124,8 +172,19 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
{
auto *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
ValueObjectSP valobj_sp;
- ExpressionResults expr_result =
- target.EvaluateExpression(expr, exe_scope, valobj_sp, eval_options);
+ 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;
@@ -135,8 +194,17 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
expr);
}
- if (valobj_sp->GetError().GetError() != UserExpression::kNoResult)
- valobj_sp->Dump(result.GetOutputStream(), dump_options);
+ 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 =
@@ -148,14 +216,12 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
}
result.SetStatus(eReturnStatusSuccessFinishResult);
- return true;
} else {
if (valobj_sp)
result.SetError(valobj_sp->GetError());
else
result.AppendErrorWithFormatv(
"unknown error evaluating expression `{0}`", expr);
- return false;
}
}
}