25
25
#include " llvm/ADT/StringRef.h"
26
26
#include " llvm/Support/FormatVariadic.h"
27
27
28
+ #include < regex>
29
+
28
30
using namespace llvm ;
29
31
using namespace lldb ;
30
32
using namespace lldb_private ;
@@ -95,8 +97,46 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
95
97
m_expr_options.m_verbosity , m_format_options.GetFormat ());
96
98
dump_options.SetHideRootName (suppress_result);
97
99
100
+ bool is_po = m_varobj_options.use_objc ;
101
+
98
102
StackFrame *frame = m_exe_ctx.GetFramePtr ();
99
103
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
+
100
140
// First, try `expr` as the name of a frame variable.
101
141
if (frame) {
102
142
auto valobj_sp = frame->FindVariable (ConstString (expr));
@@ -114,7 +154,15 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
114
154
flags, expr);
115
155
}
116
156
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
+ }
118
166
result.SetStatus (eReturnStatusSuccessFinishResult);
119
167
return true ;
120
168
}
@@ -135,8 +183,17 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
135
183
expr);
136
184
}
137
185
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
+ }
140
197
141
198
if (suppress_result)
142
199
if (auto result_var_sp =
0 commit comments