2525#include " llvm/ADT/StringRef.h"
2626#include " llvm/Support/FormatVariadic.h"
2727
28+ #include < regex>
29+
2830using namespace llvm ;
2931using namespace lldb ;
3032using namespace lldb_private ;
@@ -95,8 +97,46 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
9597 m_expr_options.m_verbosity , m_format_options.GetFormat ());
9698 dump_options.SetHideRootName (suppress_result);
9799
100+ bool is_po = m_varobj_options.use_objc ;
101+
98102 StackFrame *frame = m_exe_ctx.GetFramePtr ();
99103
104+ // Either Swift was explicitly specified, or the frame is Swift.
105+ lldb::LanguageType language = m_expr_options.language ;
106+ if (language == lldb::eLanguageTypeUnknown && frame)
107+ language = frame->GuessLanguage ();
108+
109+ // Add a hint if object description was requested, but no description
110+ // function was implemented.
111+ auto maybe_add_hint = [&](llvm::StringRef output) {
112+ // Identify the default output of object description for Swift and
113+ // Objective-C
114+ // "<Name: 0x...>. The regex is:
115+ // - Start with "<".
116+ // - Followed by 1 or more non-whitespace characters.
117+ // - Followed by ": 0x".
118+ // - Followed by 5 or more hex digits.
119+ // - Followed by ">".
120+ // - End with zero or more whitespace characters.
121+ const std::regex swift_class_regex (" ^<\\ S+: 0x[[:xdigit:]]{5,}>\\ s*$" );
122+
123+ if (GetDebugger ().GetShowDontUsePoHint () && target_ptr &&
124+ (language == lldb::eLanguageTypeSwift ||
125+ language == lldb::eLanguageTypeObjC) &&
126+ std::regex_match (output.data (), swift_class_regex)) {
127+
128+ static bool note_shown = false ;
129+ if (note_shown)
130+ return ;
131+
132+ result.GetOutputStream ()
133+ << " note: object description requested, but type doesn't implement "
134+ " a custom object description. Consider using \" p\" instead of "
135+ " \" po\" (this note will only be shown once per debug session).\n " ;
136+ note_shown = true ;
137+ }
138+ };
139+
100140 // First, try `expr` as the name of a frame variable.
101141 if (frame) {
102142 auto valobj_sp = frame->FindVariable (ConstString (expr));
@@ -114,7 +154,15 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
114154 flags, expr);
115155 }
116156
117- valobj_sp->Dump (result.GetOutputStream (), dump_options);
157+ if (is_po) {
158+ StreamString temp_result_stream;
159+ valobj_sp->Dump (temp_result_stream, dump_options);
160+ llvm::StringRef output = temp_result_stream.GetString ();
161+ maybe_add_hint (output);
162+ result.GetOutputStream () << output;
163+ } else {
164+ valobj_sp->Dump (result.GetOutputStream (), dump_options);
165+ }
118166 result.SetStatus (eReturnStatusSuccessFinishResult);
119167 return true ;
120168 }
@@ -135,8 +183,17 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
135183 expr);
136184 }
137185
138- if (valobj_sp->GetError ().GetError () != UserExpression::kNoResult )
139- valobj_sp->Dump (result.GetOutputStream (), dump_options);
186+ if (valobj_sp->GetError ().GetError () != UserExpression::kNoResult ) {
187+ if (is_po) {
188+ StreamString temp_result_stream;
189+ valobj_sp->Dump (temp_result_stream, dump_options);
190+ llvm::StringRef output = temp_result_stream.GetString ();
191+ maybe_add_hint (output);
192+ result.GetOutputStream () << output;
193+ } else {
194+ valobj_sp->Dump (result.GetOutputStream (), dump_options);
195+ }
196+ }
140197
141198 if (suppress_result)
142199 if (auto result_var_sp =
0 commit comments