Skip to content

Commit ff35dfd

Browse files
Merge pull request #7140 from augusto2112/cherry-pick-hint-po
[lldb] Print hint if object description is requested but not implemented
2 parents 299c632 + c963487 commit ff35dfd

File tree

7 files changed

+140
-3
lines changed

7 files changed

+140
-3
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
316316

317317
llvm::StringRef GetAutosuggestionAnsiSuffix() const;
318318

319+
bool GetShowDontUsePoHint() const;
320+
319321
bool GetUseSourceCache() const;
320322

321323
bool SetUseSourceCache(bool use_source_cache);

lldb/source/Commands/CommandObjectDWIMPrint.cpp

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include "llvm/ADT/StringRef.h"
2828
#include "llvm/Support/FormatVariadic.h"
2929

30+
#include <regex>
31+
3032
using namespace llvm;
3133
using namespace lldb;
3234
using namespace lldb_private;
@@ -109,6 +111,37 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
109111
language = frame->GuessLanguage();
110112
// END SWIFT
111113

114+
// Add a hint if object description was requested, but no description
115+
// function was implemented.
116+
auto maybe_add_hint = [&](llvm::StringRef output) {
117+
// Identify the default output of object description for Swift and
118+
// Objective-C
119+
// "<Name: 0x...>. The regex is:
120+
// - Start with "<".
121+
// - Followed by 1 or more non-whitespace characters.
122+
// - Followed by ": 0x".
123+
// - Followed by 5 or more hex digits.
124+
// - Followed by ">".
125+
// - End with zero or more whitespace characters.
126+
const std::regex swift_class_regex("^<\\S+: 0x[[:xdigit:]]{5,}>\\s*$");
127+
128+
if (GetDebugger().GetShowDontUsePoHint() && target_ptr &&
129+
(language == lldb::eLanguageTypeSwift ||
130+
language == lldb::eLanguageTypeObjC) &&
131+
std::regex_match(output.data(), swift_class_regex)) {
132+
133+
static bool note_shown = false;
134+
if (note_shown)
135+
return;
136+
137+
result.GetOutputStream()
138+
<< "note: object description requested, but type doesn't implement "
139+
"a custom object description. Consider using \"p\" instead of "
140+
"\"po\" (this note will only be shown once per debug session).\n";
141+
note_shown = true;
142+
}
143+
};
144+
112145
// First, try `expr` as the name of a frame variable.
113146
if (frame) {
114147
auto valobj_sp = frame->FindVariable(ConstString(expr));
@@ -126,7 +159,15 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
126159
flags, expr);
127160
}
128161

129-
valobj_sp->Dump(result.GetOutputStream(), dump_options);
162+
if (is_po) {
163+
StreamString temp_result_stream;
164+
valobj_sp->Dump(temp_result_stream, dump_options);
165+
llvm::StringRef output = temp_result_stream.GetString();
166+
maybe_add_hint(output);
167+
result.GetOutputStream() << output;
168+
} else {
169+
valobj_sp->Dump(result.GetOutputStream(), dump_options);
170+
}
130171
result.SetStatus(eReturnStatusSuccessFinishResult);
131172
return true;
132173
}
@@ -184,8 +225,17 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
184225
expr);
185226
}
186227

187-
if (valobj_sp->GetError().GetError() != UserExpression::kNoResult)
188-
valobj_sp->Dump(result.GetOutputStream(), dump_options);
228+
if (valobj_sp->GetError().GetError() != UserExpression::kNoResult) {
229+
if (is_po) {
230+
StreamString temp_result_stream;
231+
valobj_sp->Dump(temp_result_stream, dump_options);
232+
llvm::StringRef output = temp_result_stream.GetString();
233+
maybe_add_hint(output);
234+
result.GetOutputStream() << output;
235+
} else {
236+
valobj_sp->Dump(result.GetOutputStream(), dump_options);
237+
}
238+
}
189239

190240
if (suppress_result)
191241
if (auto result_var_sp =

lldb/source/Core/CoreProperties.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ let Definition = "debugger" in {
225225
Global,
226226
DefaultStringValue<"${ansi.normal}">,
227227
Desc<"When displaying suggestion in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the suggestion.">;
228+
def ShowDontUsePoHint: Property<"show-dont-use-po-hint", "Boolean">,
229+
Global,
230+
DefaultTrue,
231+
Desc<"If true, and object description was requested for a type that does not implement it, LLDB will print a hint telling the user to consider using p instead.">;
228232
def DWIMPrintVerbosity: Property<"dwim-print-verbosity", "Enum">,
229233
Global,
230234
DefaultEnumValue<"eDWIMPrintVerbosityNone">,

lldb/source/Core/Debugger.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,12 @@ llvm::StringRef Debugger::GetAutosuggestionAnsiSuffix() const {
423423
return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
424424
}
425425

426+
bool Debugger::GetShowDontUsePoHint() const {
427+
const uint32_t idx = ePropertyShowDontUsePoHint;
428+
return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr,
429+
idx, g_debugger_properties[idx].default_uint_value != 0);
430+
}
431+
426432
bool Debugger::GetUseSourceCache() const {
427433
const uint32_t idx = ePropertyUseSourceCache;
428434
return m_collection_sp->GetPropertyAtIndexAsBoolean(
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
OBJC_SOURCES := main.m
2+
LD_EXTRAS = -lobjc -framework Foundation
3+
4+
include Makefile.rules
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
from lldbsuite.test.lldbtest import *
4+
from lldbsuite.test import lldbutil
5+
6+
7+
class TestObjcPoHint(TestBase):
8+
NO_DEBUG_INFO_TESTCASE = True
9+
10+
def test_show_po_hint(self):
11+
### Test that the po hint is shown once with the DWIM print command
12+
self.build()
13+
_, _, _, _ = lldbutil.run_to_source_breakpoint(
14+
self, "Set breakpoint here", lldb.SBFileSpec("main.m")
15+
)
16+
# Make sure the hint is printed the first time
17+
self.expect(
18+
"dwim-print -O -- foo",
19+
substrs=[
20+
"note: object description requested, but type doesn't implement "
21+
'a custom object description. Consider using "p" instead of "po"',
22+
"<Foo: 0x",
23+
],
24+
)
25+
26+
# Make sure it's not printed again.
27+
self.expect(
28+
"dwim-print -O -- foo",
29+
substrs=[
30+
"note: object description"
31+
],
32+
matching=False,
33+
)
34+
35+
def test_show_po_hint_disabled(self):
36+
### Test that when the setting is disabled the hint is not printed
37+
self.build()
38+
_, _, _, _ = lldbutil.run_to_source_breakpoint(
39+
self, "Set breakpoint here", lldb.SBFileSpec("main.m")
40+
)
41+
self.runCmd("setting set show-dont-use-po-hint false")
42+
# Make sure the hint is printed the first time
43+
self.expect(
44+
"dwim-print -O -- foo",
45+
substrs=[
46+
"note: object description"
47+
],
48+
matching=False,
49+
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@interface Foo : NSObject {}
4+
5+
-(id) init;
6+
7+
@end
8+
9+
@implementation Foo
10+
11+
-(id) init
12+
{
13+
return self = [super init];
14+
}
15+
@end
16+
17+
int main()
18+
{
19+
Foo *foo = [Foo new];
20+
NSLog(@"a"); // Set breakpoint here.
21+
return 0;
22+
}

0 commit comments

Comments
 (0)